#include <applicat.h>
#include <mask.h>
#include <progind.h>
#include <relation.h>
#include <archives.h>
#include <utility.h>
#include "ve5400.h"
#include "velib.h"
#include <doc.h>

//-----------------------------------------------------------------------------------------------
//-------MASCHERA-----------------------------
class TArchive_mask : public TMask
{
public:
  TArchive_mask();
  virtual ~TArchive_mask() { }
};

TArchive_mask::TArchive_mask() : TMask("ve5400") 
{
  TList_field& lf = (TList_field&)field(F_DRIVE);
  TToken_string codes, values;  
  TString4 str; 
  int k = 0;
  for (int d = 0; d < 26; d++)
  {
    str.format("%c:/", d+'A');
    const bool isrem = xvt_fsys_is_removable_drive(str) != 0;
    const bool isfix = !isrem && xvt_fsys_is_fixed_drive(str);
    if (isrem || isfix)
    {
			str.rtrim(1); // Togli slash finale
      codes.add(str);
      values.add(str);
      TToken_string& message = *lf.message(k++, TRUE);
      if (isrem)
        message.format("CLEAR,%d", F_PATH);
      else                                   
        message.format("ENABLE,%d", F_PATH);
    }
  }
  lf.replace_items(codes, values);
}

//-----------------------------------------------------------------------------------------------
//-------APPLICAZIONE-----------------------------
class TArchive_doc : public TSkeleton_application
{
  TArray _file;
  TIsamtempfile *_tdoc;                    //dichiaro un puntatore al file documenti (non posso dichiarare un file)
  TIsamtempfile *_trdoc;                   //                              righe documenti
  TIsamtempfile *_trcf;                    //                              clienti/ fornitori
  TIsamtempfile *_trcfv;                    //                             clienti/ fornitori vendite
  TFilename      _tmp_dir, _path;
  TArchive       _arc; 
  TString        _desc;
  char           _unit;
  
protected:                                                                  // TSkeleton_application
  virtual void main_loop();
  void open_files(int logicnum, ...);
  virtual bool create();
  void create_tmp_files(bool create);
  void delete_tmp_files(bool remove);
  void archivia(const TMask& m);
  void ripristina(const TMask& m);

  bool restore_file(TIsamtempfile& src, bool update);
  bool restore_clifo(bool update);
  bool restore_docs();

public:
  TArchive_doc() { }
  virtual ~TArchive_doc() { }
};

void TArchive_doc::open_files(int logicnum, ...)  
{  
  va_list marker;
  va_start(marker, logicnum);
  while (logicnum > 0)
  {
    CHECKD(_file.objptr(logicnum) == NULL, "File gia' aperto: ", logicnum);
    _file.add(new TLocalisamfile(logicnum), logicnum);
    logicnum = va_arg(marker, int);
  }
}

bool TArchive_doc::create()
{                 
  open_files(LF_TABCOM, LF_TAB, LF_CLIFO, LF_OCCAS, LF_INDSP, LF_CFVEN,
             LF_DOC, LF_RIGHEDOC, LF_ANAMAG, LF_MOVMAG, LF_RMOVMAG, LF_CONDV,
             LF_SVRIEP, LF_AGENTI, LF_PERCPROV, LF_CESS, 0);
  _tmp_dir.temp();
  _tmp_dir = _tmp_dir.path();
  _tmp_dir << "VE";
  if (!_tmp_dir.exist()) make_dir(_tmp_dir);
  _tmp_dir.insert("%");                                   // Add % sign
       
  _tdoc = _trdoc = _trcf = _trcfv = NULL;     
       
  return TSkeleton_application::create();
}


void TArchive_doc::create_tmp_files(bool create)         //crea i files temporanei (nella directory temp) 
{
  TFilename tf(_tmp_dir);
  tf.add("f1");
  _tdoc   = new TIsamtempfile(LF_DOC, tf, create);         
  tf.rtrim(1); tf << "2";
  _trdoc   = new TIsamtempfile(LF_RIGHEDOC, tf, create);
  tf.rtrim(1); tf << "3";
  _trcf   = new TIsamtempfile(LF_CLIFO, tf, create);
  tf.rtrim(1); tf << "4";
  _trcfv   = new TIsamtempfile(LF_CFVEN, tf, create);
}                     

void TArchive_doc::delete_tmp_files(bool remove)        //cancella i files temporanei al termine dell'archiviazione
{
  if (remove)                                           // Cosi' posso forzare la cancellazione in chiusura
  {
    _tdoc->set_autodel();
    _trdoc->set_autodel();
    _trcf->set_autodel();
    _trcfv->set_autodel();
  }
  delete _tdoc;
  delete _trdoc;
  delete _trcf;
  delete _trcfv;
  _tdoc = NULL;
  _trdoc = NULL;
  _trcf = NULL;
  _trcfv = NULL;
}



void TArchive_doc::archivia(const TMask& m)
{ 
	const bool with_clifor = m.get_bool(F_WITHCLI);
  TRelation rel(LF_DOC);                         //crea una relazione sul file identificato dal numero LF_DOC
  m.autosave(rel);                               //scrive, in base alla rel, i valori del campo con specifica LF_DOC
    
  TRectype recini(rel.curr());                   //crea recini di TRectype che costruisce il record corrente del file
  TRectype recfin(rel.curr());                   //crea recfin di TRectype che costruisce il record corrente del file
    
  recini.put(DOC_NDOC, m.get(F_NUMFR));     //setta il contenuto del campo DOC_NDOC con il numero che arriva da m.get (� il numero del primo record da leggere)
  recfin.put(DOC_NDOC, m.get(F_NUMTO));     //come sopra ma per l'ultimo record (questi due numeri gli servono nel cursore)
    
  _unit = m.get(F_DRIVE)[0];             //legge solo i drive dei floppy e quelli locali
  _path = m.get(F_PATH);                 //path di destinazione del file da creare (se non floppy) 
  _desc = m.get(F_DESCRFILE);            //descrizione nel file .ini
    
  TString filter;                                 //crea l'ogetto filter da TString


  TCursor cur(&rel, filter, 1, &recini, &recfin); //crea un cursore (cur) basato sulla relazione rel, il filtro filter, da recini a recfin
  const long total = cur.items();                 //mette in total il numero totale di record
    
  if (total > 0)                                  //se c'� almeno un record...
  {
    TString msg = "Confermare l'invio di ";  //istanza della TString (compare una box con la richiesta di conferma)
    msg.add_plural(total, "documento");              //cerca il plurale della stringa "documento" se total �>1
    if (yesno_box(msg))                              //se si conferma l'archiviazione (OK nella box)...
    { 
                                                    //chiamo la funzione che crea i file temporanei in modo da creare un
      create_tmp_files(TRUE);                       //file di intestazione ed un file di righe temporanei (N.B. non devo
                                                    //creare alcun oggetto perch� la funzione � un metodo della TArchive_doc
                                                    //e quindi l'oggetto � gi� creato
                                                             
      TProgind pi(total, "Elaborazione in corso...", TRUE, TRUE);      //istanza pi di TProgind che fa comparire la finestra di elaborazione in corso
      TDocumento* doc = new TDocumento;                                //doc � un puntatore ad una istanza di TDocumento
      rel.lfile().set_curr(doc);                                       //applica set_curr al localisamfile che viene ritornato da rel.lfile()
                                                                       //set_curr sostituisce il record corrente del file doc
      int err = NOERR;
                                                                         
      for (cur = 0; cur.pos() < total && !pi.iscancelled() && err==NOERR; ++cur)     //for cur che va da 0 alla posizione corrente (che deve essere < del numero totale
                                                                                     //dei record (total) and non essere interrotto e non esserci errore
      { 
        err = _tdoc->write(doc->head());                                               //scrive l'intestazione sul file temp delle testate
				if (with_clifor)
				{
					TString key(doc->get(DOC_TIPOCF));
					key << "|" << doc->get(DOC_CODCF);
					TRectype clifor(cache().get(LF_CLIFO, key));
					TRectype cfven(cache().get(LF_CFVEN, key));

					if (!clifor.empty())
						clifor.write(*_trcf);

					if (!cfven.empty())
						cfven.write(*_trcfv);
				}
        if (err != NOERR)                                                            //se invece c'� un errore..
        {
          error_box("Errore %d durante la copia dell'intestazione", err);
          break;
        }
        for (int r = 1; r <= doc->physical_rows() && err==NOERR; r++)                //scrive le righe sul file temp delle
        {                                                                            //righe;
          err = _trdoc->write((*doc)[r]);                                            //scrive le righe sul file
          if (err != NOERR)
          {
            error_box("Errore %d durante la copia delle righe", err);
						break;
          } 
        }
        pi.addstatus(1L);                                                           //mette la barra di work in progress
      }                                              
        
      delete_tmp_files(false);                                //chiude i files temp in modo da risparmiare memoria
      
      const char * dir = &_tmp_dir[1];                        //fa puntare dir alla directory temp
      bool rt = _arc.backup(dir,_unit,_desc, TRUE);           //esegue la compressione ed il salvataggio sul device scelto
      create_tmp_files(false);                                //apre i files temp, riallocandoli (NON li crea effettvam.)
      delete_tmp_files(true);                                //cancella fisicamente i files temp

      TFilename unit;
      unit << _unit << ':' << SLASH;
      if (!xvt_fsys_is_removable_drive(unit) && _path != "")  //se il drive non e' rimovibile,sposta i files dalla root del drive 
      {                                         //alla target dir scritta sulla maschera
        for (int i = 0; i <= 1; i++)
        {
          TFilename orig = unit;
          TFilename dest;
          dest << unit << _path;
          const char * name = i == 0 ? "backup.ini" : "ve.z00";
          orig << name;
          dest << SLASH << name;
          fcopy(orig, dest);
          xvt_fsys_removefile(orig);  //elimina il file di origine dopo averlo copiato
        }
      }
    }
  }
}

bool TArchive_doc::restore_file(TIsamtempfile& src, bool update)
{
	TLocalisamfile dst(src.num());

  TString msg; msg << TR("Trasferimento") << ' ' << dst.description();
  TProgind pi(src.items(), msg, true, true);
  for (int err = src.first(); err == NOERR; err = src.next())
	{
		err = src.curr().write(dst);
		if (err == _isreinsert)
		{
			if (update)
				err = src.curr().rewrite(dst);
      else
  			err = NOERR;
		}
	  if (err != NOERR) 
		  return error_box(FR("Errore %d"), err);  
	}

  return !pi.iscancelled();
}

bool TArchive_doc::restore_clifo(bool update)
{
  return restore_file(*_trcf, update) && restore_file(*_trcfv, update);
}

bool TArchive_doc::restore_docs()
{
  TIsamfile doc(LF_DOC);
  doc.open();
  int err = doc.lock();
  if (err != NOERR)  
    return error_box("Il file documenti non puo' essere bloccato in modo esclusivo."
                     "Nessun documento ricevuto. Errore %d.",err);

  if (restore_file(*_trdoc, true))
  {           
    _tdoc->set_curr(new TDocumento);
    restore_file(*_tdoc, false);
  }

  doc.close();
  return err == NOERR;
}

void TArchive_doc::ripristina(const TMask& m)
{
  _unit = m.get(F_DRIVE)[0];
  _path = m.get(F_PATH);

  TFilename unit;
  unit << _unit << ':' << SLASH;

  if (!xvt_fsys_is_removable_drive(unit) && _path != "") //ripristina dalla directory scelta come origine dei dati
  {
    TFilename path;
    path << _unit << ':' << SLASH << _path;
    for (int i = 0; i<= 1; i++)
    {
      TFilename orig = path;
      TFilename dest = unit;
      const char * name = i == 0 ? "backup.ini" : "ve.z00";
      orig << SLASH << name;
      dest << name;
      fcopy(orig, dest);
    }
  }

  const char* dir = & _tmp_dir[1];
  if (_arc.restore(dir,_unit,FALSE,TRUE))
  {
    create_tmp_files(FALSE); // In realta' ci sono gia'

    if (m.get_bool(F_WITHCLI))
      restore_clifo(m.get_bool(F_UPDATE));
    restore_docs();

    delete_tmp_files(true);                                                            // Removes temp files!

//elimina i files copiati sulla root di un eventuale unita' fissa
    if (!xvt_fsys_is_removable_drive(unit) && _path != "") 
    {
      for (int i = 0; i<= 1; i++)
      {
        TFilename file_to_erease = unit;
        const char * name = i == 0 ? "backup.ini" : "ve.z00";
        file_to_erease << name;
        xvt_fsys_removefile(file_to_erease);;
      }
    }

  } 
  else
    error_box("Errore nella ricezione dei file da dischetto. Nessun documento ricevuto.");
}



//////////////////////////////////////////////////////////
//////////  Main loop del programma            ///////////
//////////////////////////////////////////////////////////


void TArchive_doc::main_loop()
{
  TArchive_mask m;
  KEY key = K_ENTER;
                                 
    while (key != K_QUIT)
    {
       key=m.run();
       
       if (key == K_ENTER)
         archivia(m);
       if (key == K_DEL)
         ripristina(m);
    }       
 
}                                           

int ve5400(int argc, char* argv[])
{
  TArchive_doc a;
  a.run(argc, argv, "Invio/Ricezione");
  return 0;
}