#include <applicat.h>
#include <config.h>
#include <mask.h>
#include <progind.h>
#include <relation.h>
#include <urldefid.h>
#include <utility.h>

#include <saldi.h>
#include <pconti.h>
#include <partite.h>
#include <scadenze.h> 
#include <pagsca.h> 

#include "../cg/cglib.h"    
#include "../cg/conto.h"
#include "../cg/saldacon.h"

#include "sc1200.h"

class TCreatepart_app : public TApplication
{ 
  TEsercizi_contabili _esc;
  bool _num_cli, _num_for;
  TString _desccl, _descfo;
  TDate _today;
  
  TLocalisamfile* _conti;
  
protected:  // Applicat
  virtual void on_firm_change();
  virtual void on_config_change();
  
  virtual bool create();
  virtual bool destroy();
  virtual bool menu(MENU_TAG m);  

protected:
  void zap_file(int logicnum) const;
  bool zap_partite() const;
  int crea_partite(int anno_es, int anno_rif, bool check);
  
public: 
  char is_clifo(int g, int c, int& indbil);
  TCreatepart_app() : _today(TODAY) {}
  virtual ~TCreatepart_app() {}  
};


bool TCreatepart_app::create()
{
  TApplication::create();
  
  _conti = new TLocalisamfile(LF_PCON);
  
  dispatch_e_menu(BAR_ITEM(1));
  return TRUE;
}

bool TCreatepart_app::destroy()
{                                      
  delete _conti;

  return TApplication::destroy();        
}

void TCreatepart_app::on_firm_change()
{
  _esc.update();
}

void TCreatepart_app::on_config_change()
{
  TConfig cd(CONFIG_DITTA, "cg");
  _num_cli = cd.get_bool("NrCliDx");
  _num_for = cd.get_bool("NrForDx");
  TPartita::carica_allineamento();
}

void TCreatepart_app::zap_file(int logicnum) const
{
  TDir dir;
  dir.get(logicnum, _lock, _nordir, _sysdirop);
  dir.eod() = 0;
  dir.put(logicnum, _nordir, _sysdirop);
  
  TSystemisamfile f(logicnum);
  f.pack();
}

bool TCreatepart_app::zap_partite() const
{                  
  bool ok = TRUE;                 

  TSystemisamfile partite(LF_PARTITE);
  partite.open();
  bool zap = partite.items() != 0;
  partite.close();
  
  if (zap)
  {
    zap = yesno_box("Il saldaconto non e' vuoto.\n"
                    "La procedura lo azzera completamente.\n"
                    "Si desidera proseguire?");     
    if (zap)
      zap = yesno_box("Confermare l'azzeramento del saldaconto esistente");  
    
    if (zap)
    {
      zap_file(LF_PARTITE);
      zap_file(LF_SCADENZE);
      zap_file(LF_PAGSCA);
    }
    else
      ok = FALSE;
  }
  
  return ok;
}


char TCreatepart_app::is_clifo(int g, int c, int& indbil)
{
  _conti->zero();
  _conti->put(PCN_GRUPPO, g);
  _conti->put(PCN_CONTO, c);
  
  if (_conti->read() != NOERR)      
  {
    warning_box("Piano dei conti disallineato con archivio saldi: esecuzione interrotta");
    return '\0'; 
  }
  
  const char cf = _conti->get_char(PCN_TMCF);    
  indbil = _conti->get_int(PCN_INDBIL);

  return cf;
}

int TCreatepart_app::crea_partite(int anno_es, int anno_rif, bool check)
{
  TRelation saldi(LF_SALDI);
  saldi.curr().put(SLD_ANNOES, anno_es);

  TCursor cur(&saldi, "", 1, &saldi.curr(), &saldi.curr());      
  const long items = cur.items();
  
  if (items == 0)
    return -1;

  begin_wait();    
  
  // Apre i files per usarli con l'oggetto TPartita
  TLocalisamfile partite(LF_PARTITE);
  TLocalisamfile scadenze(LF_SCADENZE);
  TLocalisamfile pagamenti(LF_PAGSCA);

  int n_part = 0;
  TProgind prind(items, "Creazione saldaconto", FALSE, TRUE, 45);
   
  for (cur = 0; cur.pos() < items; ++cur)
  {               
    const int gruppo  = cur.curr().get_int(SLD_GRUPPO);
    const int conto   = cur.curr().get_int(SLD_CONTO);  
    const long sottoc = cur.curr().get_long(SLD_SOTTOCONTO);    
    int indbil;
    const char cf = is_clifo(gruppo, conto, indbil);
    if (cf > ' ')
    {
      TSaldo sld;
           
      // ciuccia il saldo e vedi se e' movimentato nell'esercizio corrente 
      if (!sld.ultima_immissione_verifica(anno_es, gruppo, conto, sottoc, indbil, 1))
      {
        // non movimentato: se e' conto patrimoniale....
        if (!(indbil == 1 || indbil == 2 || indbil == 5))
        { 
          prind.addstatus(1);
          continue;          
        }
        // .. vedi saldo esercizio precedente, altrimenti inkul
        sld.saldofin_esprec(anno_es, gruppo, conto, sottoc);
      }
          
      // genera importo con sezione appropriata       
      TImporto saldo(cur.curr().get_char(SLD_FLAGSALINI), sld.saldoini());
      TImporto pdare('D', sld.prgdare());   
      TImporto pavere('A', sld.prgavere());
          
      saldo += pdare;         
      saldo += pavere;                 
      saldo.normalize();
          
      if (!saldo.is_zero())
      {                                            
        const TBill clifo(gruppo, conto, sottoc, cf);
        TString16 numero("*");             
        if ((cf == 'C' && _num_cli) || (cf == 'F' && _num_for))
          numero.right_just(7);
        
        TPartita game(clifo, anno_rif, numero);
        if (check)
        {                                  
          for (int p = game.last(); p > 0; p = game.pred(p))
          {         
            const TRiga_partite& riga = game.riga(p);
            const int g = riga.get_int(PART_GRUPPOCL);
            const int c = riga.get_int(PART_CONTOCL);
            if (gruppo == g && conto == c)
              break;     // Esiste gia' una riga con questo conto
          }
          if (p > 0)     // Il cliente esiste gia', per cui ignoro il saldo
            continue;
        }  
        
        TRiga_partite& riga = game.new_row();
        riga.put(PART_DATAREG, _today);
        riga.put(PART_DATADOC, _today);
        riga.put(PART_DATAPAG, _today);
        riga.put(PART_SEZ,     saldo.sezione());
        riga.put(PART_IMPORTO, saldo.valore());
        riga.put(PART_DESCR, cf == 'C' ? _desccl : _descfo);
            
        // cazzata dare/avere/fare/baciare/cagare 
        const tipo_movimento tipo = (cf == 'C' ? (saldo.sezione() == 'D' ? tm_fattura : tm_nota_credito) : 
                         (saldo.sezione() == 'D' ?  tm_nota_credito : tm_fattura));

        riga.put(PART_TIPOMOV, (int)tipo);
            
        if (tipo == tm_fattura)
        {
          TRiga_scadenze& scad = riga.new_row();
          scad.put(SCAD_IMPORTO, saldo.valore());
          scad.put(SCAD_DATASCAD, _today);
          scad.put(SCAD_TIPOPAG, 1);        // rimessa diretta
        } 
        else
        {
          const int r = riga.get_int(PART_NRIGA);
          TRectype& unas = game.unassigned().row(r, TRUE);
          unas.put(PAGSCA_IMPORTO, saldo.valore());
          unas.put(PAGSCA_ACCSAL, 'A');
        }
        
        if (game.write())
          n_part++;
        else
        {
          error_box("Impossibile scrivere la partita %d %s", 
                    anno_rif, (const char *)numero);
          break;
        }  
      }
    }
    prind.addstatus(1);  
  }

  end_wait();
  return n_part;
}

bool TCreatepart_app::menu(MENU_TAG)
{ 
  TMask m("sc1200a");

  _desccl << "Apertura clienti al "   << _today;
  _descfo << "Apertura fornitori al " << _today;
  
  m.set(F_DESCCL, _desccl);                                                               
  m.set(F_DESCFO, _descfo);
  m.set(F_ANNO, _esc.last());
  
  while (m.run() == K_ENTER) 
  {
    const int anno_es = m.get_int(F_ANNO);
    _desccl = m.get(F_DESCCL);
    _descfo = m.get(F_DESCFO);
    
    // sputtana tutto il saldaculo
    if (!zap_partite()) 
      continue;         
    
    const TEsercizio& selected_es = _esc.esercizio(anno_es);
    const int anno_rif = selected_es.inizio().year();
    int n_part = crea_partite(anno_es, anno_rif, FALSE);
    if (n_part >= 0)
    {   
      const int pred_es = _esc.pred(anno_es);
      if (pred_es > 0)
      {
        const int p = crea_partite(pred_es, anno_rif, TRUE);
        if (p > 0) n_part += p;                       
      }  
    }
    else 
      message_box("Nessun saldo presente per l'esercizio %d", anno_es);    
    
    if (n_part > 0)               // May be -1
      m.set(F_NUMPART, n_part);
    else
      m.reset(F_NUMPART)  ;
  } // while run 
  
  return FALSE;
}


int sc1200(int argc, char** argv)
{
  TCreatepart_app a;
  a.run(argc, argv, "Apertura scadenze da saldi");
  return 0;
}
