#include <applicat.h>
#include <archives.h>
#include <mask.h>    
#include <progind.h>

#include "../cg/cgsaldac.h"
#include "sc1100.h"    

class TDeletepart_app : public TSkeleton_application
{                                     
  TArchive       _arc;      
  TArray         _to_zap;    // Array contenente le chiavi delle partite da eliminare
  TDate          _datalimite;
  TString        _desc;
  char           _unit;
  TFilename      _tmp_dir;
  TIsamtempfile  *_tpart,*_tscad,*_tpagsca;
  TLocalisamfile *_part,*_scad,*_pagsca;
  
protected:

  void backup_delete_partite();    // Backup e cancellazione delle partite da eliminare
  void restore_partite();          // Ripristino partite cancellate 
  void delete_partite_restored();  // Cancellazione partite ripristinate
  void create_tmp_files(bool create=TRUE);
  void delete_tmp_files(bool remove=TRUE);
  virtual bool create();
  virtual bool destroy();
  virtual void main_loop();  
  
public:

  TDate& datalimite() { return _datalimite; }

  TDeletepart_app() {};  
  ~TDeletepart_app() {};  
};

void TDeletepart_app::backup_delete_partite()
{
  TPartita *partita;
  TRecnotype total = 0;   
  int err;
  
  err = _part->lock();
  if (err != NOERR) 
  {
    error_box(FR("Il file partite non puo' essere bloccato in modo esclusivo."
              " Nessuna partita cancellata. Errore %d."),err);
    return;
  }
  create_tmp_files();
  _part->zero();                                        
  // Scorre il file delle partite
{
  TProgind p(10, TR("Ricerca e copia delle partite da eliminare..."), TRUE, FALSE, 10);
  for (_part->first();_part->good() && !p.iscancelled();_part->read(_isgreat))
  {
    const char tipocf = _part->get_char(PART_TIPOCF);
    const long codcf = _part->get_long(PART_SOTTOCONTO);
    const int anno = _part->get_int(PART_ANNO);
    const TString16 num_part(_part->get(PART_NUMPART));                    
    TBill conto(0,0,codcf,tipocf);
    partita = new TPartita(conto,anno,num_part);
    bool to_delete = TRUE;
    // Scorre le righe di questa partita partendo dall'ultima
    int r=partita->last();
    if (r == 0) to_delete = FALSE;
    for (;r>0 && to_delete && !p.iscancelled();r=partita->pred(r))
    {
      TRiga_partite& row = partita->riga(r);
      // Passa alla prossima se trova almeno una riga di partita che non sia CHIUSA o 
      // che abbia la data di registrazione maggiore della data limite
      // Ovvero: tutte le righe della partita in esame devono avere il flag
      // CHIUSA settato a TRUE e DATAREG <= della data limite
      if (!row.get_bool(PART_CHIUSA) ||
          row.get_date(PART_DATAREG) > _datalimite)
        to_delete = FALSE;  
      
      // Se TIPOMOV != 1 e' inutile controllare la partita. 
      // N.B. TIPOMOV = 1 quando la partita si riferisce alle scadenze di una fattura
      if (to_delete && row.get_int(PART_TIPOMOV) == 1) 
      {                                 
        // Scorre le rate di scadenza per questa riga di partita
        for (int n=row.rate();(n>0 && to_delete && !p.iscancelled()); n--)
        { 
          if (row.rata(n).get_date(SCAD_DATASCAD) > _datalimite)
            to_delete = FALSE;     
        }
      }
    }
    if (to_delete && !p.iscancelled()) // Se TRUE la partita puo' essere eliminata!
    {              // Memorizza la chiave della partita in un array
      TToken_string id(30);
      id = _part->get(PART_TIPOCF);
      id.add(_part->get(PART_SOTTOCONTO));
      id.add(_part->get(PART_ANNO));
      id.add(_part->get(PART_NUMPART));
      _to_zap.add(id);                                        
      // Memorizza le righe della partita, scadenze e pagsca sui file temporanei
      // Scorre le righe di partita da eliminare e le scrive sul file temporaneo
      for (int x=partita->last();x > 0 && err==NOERR;x=partita->pred(x))
      {
        TRiga_partite& row = partita->riga(x);
        err = _tpart->write(row);                                                     
        // Scorre le righe di scadenza per questa riga di partita e le scrive
        for (int y=row.rate();y > 0 && err==NOERR; y--)
        { 
          const TRiga_scadenze& r_scad = row.rata(y); 
          err=_tscad->write(r_scad);                            
          // Scorre le righe dei pagamenti relativi alla scadenza e le scrive
          for (int z=r_scad.last();z > 0 && err==NOERR;z=r_scad.pred(z))
          {
            TRectype pag(r_scad.row(z));
            err=_tpagsca->write(pag);
          }
        }
      }             
      total++;
    }       
    delete partita;
    _part->put(PART_NRIGA,9999);  // Forza la rilettura della prossima partita
  }  // end of for
  if (p.iscancelled()) total=0;
}
if (total != 0)                                        
  if (err==NOERR)           
{
  const char * dir = &_tmp_dir[1];
  delete_tmp_files(FALSE); //Close tmp files only
  bool rt = _arc.backup(dir,_unit,_desc,FALSE);// Backup delle partite da eliminare, prefix unnecessary
  create_tmp_files(FALSE); // Reopen tmp files.
  if (rt) 
  {
    // Effettiva cancellazione delle partite                                
    TString80 caption(TR("Cancellazione di "));
    caption.add_plural(total, TR("partita"));
    if (!yesno_box(caption))
      _to_zap.destroy();
    TProgind pi(total, caption, FALSE, TRUE, 10);
    const int items = _to_zap.items();
    for (int i = 0; i < items; i++)
    {          
      TToken_string& id = (TToken_string&)_to_zap[i];        
      id.restart();
      const char tipocf = id.get_char();
      const long codcf  = id.get_long();
      const int anno    = id.get_int();
      const TString16 num=id.get();                    
      TBill conto(0,0,codcf,tipocf);
      partita = new TPartita(conto,anno,num);
      partita->remove();
      delete partita;
      pi.addstatus(1);
    }   
  }                                          
}
else
error_box(FR("Errore %d scrivendo sui files temporanei."
          " La cancellazione delle partite chiuse non verra' effettuata."),err);
          // Cerca scadenze e pagamenti senza partite: solo su richiesta
          TString80 caption(TR("Cancellazione scadenze e pagamenti senza partite"));
          if (err == NOERR && yesno_box(caption))
{
  TString16 lastpart;
  int lastanno = 0;
  
  TProgind p(10, caption, TRUE, FALSE, 10);
  // Esamina le scadenze...
  for (_scad->first(); !_scad->eof() && err == NOERR; _scad->next())
  {             
    _part->zero();
    _part->put(PART_TIPOCF,   _scad->get(SCAD_TIPOCF));
    _part->put(PART_GRUPPO,  _scad->get(SCAD_GRUPPO));
    _part->put(PART_CONTO,   _scad->get(SCAD_CONTO));
    _part->put(PART_SOTTOCONTO,_scad->get(SCAD_SOTTOCONTO));
    lastanno = _scad->get_int(SCAD_ANNO);
    _part->put(PART_ANNO,    lastanno);
    lastpart = _scad->get(SCAD_NUMPART);
    _part->put(PART_NUMPART, lastpart);
    _part->put(PART_NRIGA, _scad->get(SCAD_NRIGA));
    if (_part->read(_isequal) != NOERR)
      err = _scad->remove();      
  }  
  if (err != NOERR)
    error_box(FR("Errore %d nella cancellazione delle scadenze %d/%s"), 
              err, lastanno, (const char *)lastpart);
  else                   
  { 
    // ... e i pagamenti 
    for (_pagsca->first(); !_pagsca->eof() && err == NOERR; _pagsca->next())
    {             
      _part->zero();
      _part->put(PART_TIPOCF,   _pagsca->get(PAGSCA_TIPOC));
      _part->put(PART_GRUPPO,  _pagsca->get(PAGSCA_GRUPPO));
      _part->put(PART_CONTO,   _pagsca->get(PAGSCA_CONTO));
      _part->put(PART_SOTTOCONTO,_pagsca->get(PAGSCA_SOTTOCONTO));
      lastanno = _pagsca->get_int(PAGSCA_ANNO);
      _part->put(PART_ANNO,    lastanno);
      lastpart = _pagsca->get(PAGSCA_NUMPART);
      _part->put(PART_NUMPART, lastpart);
      _part->put(PART_NRIGA, _pagsca->get(PAGSCA_NRIGA));
      if (_part->read(_isequal) != NOERR)
        err = _pagsca->remove();
    }
    if (err != NOERR)
      error_box(FR("Errore %d nella cancellazione dei pagamenti %d/%s"), 
                err, lastanno, (const char *) lastpart);
  }
}
delete_tmp_files();    // Physical remove of tmp files
_part->unlock();
}

void TDeletepart_app::restore_partite()
{
  int err = _part->lock();
  if (err != NOERR)  
  {
    error_box(FR("Il file partite non puo' essere bloccato in modo esclusivo."
              " Nessuna partita ripristinata. Errore %d."),err);
    return ;
  }
  const char* dir =& _tmp_dir[1]; // Cut out % sign
  if (_arc.restore(dir,_unit,FALSE,FALSE))
  {
    create_tmp_files(FALSE);  // In realta' ci sono gia'
    // Credo di poter andare a colpo sicuro nel trasferimento
    // di questi miserabili record, ovvero: se sono stati tolti prima
    // non dovrebbero esserci piu'... (Colombo's Egg...). Al limite riscrive i record
    // gia' presenti. 
    const TRecnotype items = _tpart->items() + _tscad->items() + _tpagsca->items();
    TProgind pi(items, TR("Ripristino partite eliminate"), FALSE, TRUE, 10);

    for (_tpart->first();_tpart->good() && err==NOERR;_tpart->next())
    {
      _tpart->put(PART_RICARICATA,TRUE);
      if ((err=_part->write(_tpart->curr())) == _isreinsert)
        err=_part->rewrite(_tpart->curr());
      pi.addstatus(1);
    }
    if (err != NOERR) 
      error_box(FR("Errore %d ripristinando il file PARTITE."),err);  
    else
    {
      for (_tscad->first();_tscad->good() && err==NOERR;_tscad->next())
      {
        if ((err=_scad->write(_tscad->curr())) == _isreinsert)
          err=_scad->rewrite(_tscad->curr());
        pi.addstatus(1);
      }
      if (err != NOERR)
        error_box(FR("Errore %d ripristinando il file SCADENZE."),err);  
      else
      {
        for (_tpagsca->first();_tpagsca->good() && err==NOERR;_tpagsca->next())
        {
          if ((err=_pagsca->write(_tpagsca->curr())) == _isreinsert)
            err=_pagsca->rewrite(_tpagsca->curr());
          pi.addstatus(1);
        }
        if (err != NOERR) error_box(FR("Errore %d ripristinando il file PAGSCA."),err); 
      }
    }
    delete_tmp_files();  // Removes tmp files!
  } 
else
  error_box(TR("Errore nel ripristino dei file da dischetto. Nessuna partita ripristinata."));
  _part->unlock();
}

void TDeletepart_app::delete_partite_restored()
{
  TRecnotype total = 0;
  TPartita* partita;
  int err = _part->lock();
  if (err != NOERR)
  {
    error_box(FR("Il file partite non puo' essere bloccato in modo esclusivo."
              " Nessuna partita cancellata. Errore %d."), err);
    return;
  }                                              
  _part->zero();                                        
  TProgind p(10, TR("Eliminazione partite ricaricate..."), TRUE, FALSE);
  for (_part->first();_part->good();_part->read(_isgreat))
  {
    if (_part->get_bool(PART_RICARICATA))
    {
      const char tipocf = _part->get_char(PART_TIPOCF);
      const long codcf = _part->get_long(PART_SOTTOCONTO);
      const int anno = _part->get_int(PART_ANNO);
      const TString16 num_part(_part->get(PART_NUMPART));                    
      TBill conto(0,0,codcf,tipocf);
      partita = new TPartita(conto,anno,num_part);
      partita->remove();
      delete partita;  
      total++;
    }
    _part->put(PART_NRIGA,9999);  // Forza la rilettura della prossima partita
  }                 
  if (total != 0) message_box(FR("Eliminate %ld partite ricaricate."),total);
  _part->unlock();
}

void TDeletepart_app::create_tmp_files(bool create)
{
  _tpart   = new TIsamtempfile(LF_PARTITE, "f1", create);
  _tscad   = new TIsamtempfile(LF_SCADENZE, "f2", create);
  _tpagsca = new TIsamtempfile(LF_PAGSCA, "f3", create);
}                     

void TDeletepart_app::delete_tmp_files(bool remove)
{
  if (remove)        // Cosi' posso forzare la cancellazione in chiusura
  {
    _tpart->set_autodel();
    _tscad->set_autodel();
    _tpagsca->set_autodel();
  }
  delete _tpart;
  delete _tscad;
  delete _tpagsca;     
}

bool TDeletepart_app::create()
{
	open_files(LF_TABCOM, LF_TAB, LF_PCON, LF_PARTITE, LF_SCADENZE, LF_PAGSCA, 0);

  _part = new TLocalisamfile(LF_PARTITE);
  _scad = new TLocalisamfile(LF_SCADENZE);
  _pagsca = new TLocalisamfile(LF_PAGSCA);
  return TSkeleton_application::create();
}

bool TDeletepart_app::destroy()
{                
  delete _part;
  delete _scad;
  delete _pagsca;
  return TSkeleton_application::destroy();
}

void TDeletepart_app::main_loop()
{               
  TMask m("sc1100a");
  
  while (m.run() != K_QUIT) 
  {                 
    _datalimite = m.get(F_DATE);       
    _unit       = m.get(F_UNIT)[0];
    _desc       = m.get(F_DESC);
    int scelta  = m.get_int(F_OPERAZIONE);
    switch (scelta)
    {
    case 1:
      backup_delete_partite(); 
      break;
    case 2:                   
      restore_partite();
      break;
    case 3:             
      delete_partite_restored();
      break;
    default:
      break;
    }
  }
}


int sc1100(int argc, char** argv)
{
  TDeletepart_app a;
  a.run(argc, argv, TR("Archiviazione partite pareggiate"));
  return 0;
}