#include <xvt.h>

#include <applicat.h>
#include <assoc.h>
#include <isam.h>
#include <mailbox.h>
#include <progind.h>
#include <prefix.h>  
#include <scanner.h>
#include <tabutil.h>
#include <urldefid.h>
#include <utility.h>
#include <extcdecl.h>
#if XVT_OS == XVT_OS_WIN
#include <direct.h>
#define RMDIR _rmdir
#else               
#define RMDIR rmdir
#endif

#include <rmov.h>

#define usage "Errore - uso : bacnv [1|2|3|4|5|6|7|8] ditta"

///////////////////////////////////////////////////////////////////////////////////////////////////////
// Applicazione di conversione archivi XBase, valida per tutti e 4 i tipi di DLL
///////////////////////////////////////////////////////////////////////////////////////////////////////

class TConversione_xbase : public TApplication
{

protected:
  virtual bool create () ;
  virtual bool destroy();
  void update();
  void convert_dir();
  int  convert_file(int logicnum);

public:
  TConversione_xbase()  {}
  ~TConversione_xbase() {}

};

bool TConversione_xbase::create() // initvar e arrmask

{
  TApplication::create();

  update();
  return FALSE;
}

bool TConversione_xbase::destroy() // releasev e arrmask

{
  return TApplication::destroy() ;
}

int TConversione_xbase::convert_file(int logicnum)
  
{
  int   err = NOERR;
  TSystemisamfile f(logicnum);
  
  err=f.pack(); // Pack data and index, so rebuild indexes according to present DLL, leaving old indexes

  return err;
}

void TConversione_xbase::convert_dir()

{         
  const TString pref(prefix().name());
  const bool is_com = prefix().is_com(); 
  TDir d;
  
  d.get(LF_DIR);                 
  const int items = (int)d.eod();
  TString80 s("Aggiornamento archivi ");

  if (pref == "com") s << "comuni";
  else s << " della ditta " << atol (pref);
  
  TProgind p((long)(items ? items : 1), s, TRUE, TRUE, 70);

  p.setstatus(1L);
  
  for (int i = 2; i <= items; i++)
  {                   
    p.setstatus((long)(i+1));
    d.get(i, _nolock, _nordir, _sysdirop);                 

    const bool to_convert = (is_com ? d.is_com() : d.is_firm());
    
    if (to_convert && d.len() > 0) 
      convert_file(i);
  }
}

void TConversione_xbase::update()

{ 
  long firm = get_firm();             
  TString pref;
  if (firm == 0) pref = prefix().name();
  
  do_events();
  begin_wait();
  
  prefix().set("com");
  convert_dir();

  TLocalisamfile ditte(LF_NDITTE);
  
  set_autoload_new_files(FALSE);
  for (ditte.first(); !ditte.eof(); ditte.next())
  {
    const long codditta = ditte.get_long("CODDITTA");
    const TRecnotype rec = ditte.recno();
    
    if (prefix().exist(codditta))
    {
      set_firm(codditta);
      convert_dir();
    }
  }
  if (firm > 0) set_firm(firm);
  else prefix().set(pref);
  set_autoload_new_files(TRUE);
  end_wait();
}



/////////////////////////////////////////////////////////////////////////////////////////
// Applicazione di conversione archivi
/////////////////////////////////////////////////////////////////////////////////////////


class TConversione_archivi : public TApplication
{
  int _nconv;
  long _codditta;
  long _oldditta;
  int _error;

protected: // TApplication
  virtual bool create() ;                         
  virtual bool destroy() ;                        
  virtual bool menu(MENU_TAG);
  
public:
  bool convert_rmov(TLocalisamfile & rmov, TArray & recs, int nrecs);
  void contropartita_rmov();

  void liala(const char* table);
  bool patch_uff(TRectype & rec, const char * const fnames[]);
  bool collate(TRectype & rec, const char * f1, const char * f2);
  void patch_com(void);
  void zero_770(void);
  void convert_patty(void);
  void convert_codconc(void);
  void convert_profili(void);
  void convert_caus_attiv(void);
  void rebuild_indexes(void);
  void rebuild_dir_indexes(void);

  TConversione_archivi() : _oldditta(0), _codditta(0), _error(0) {}
};

bool TConversione_archivi::create()
{
  TApplication::create();

  if (argc() < 3)
  {
    _error = 101;
    TMessage msg("ba1100", 0, format("%d", _error));

    msg.send();
    return FALSE;
  }
  else
  {           
    _nconv = atoi(argv(1));
    if (_nconv > 1)
    {
      _oldditta = get_firm();
      _codditta = atol(argv(argc() - 1));
      if (_codditta != _oldditta) 
      {
        if (_codditta == 0) prefix().set("com");
        else set_firm(_codditta);
      }
    }
    dispatch_e_menu(MENU_ITEM(1));
    return TRUE;
  }
}

bool TConversione_archivi::destroy()
{
  if (_nconv > 1 && _codditta != _oldditta)
  {
    if (_oldditta == 0) prefix().set("com");
    else set_firm(_oldditta);
  }
  if (_error > 0)
  {
    TMessage msg("ba1100", 0, format("%d", _error));
    msg.send();
  }
  return TRUE;
}

bool TConversione_archivi::menu(MENU_TAG)
{
  switch (_nconv)
  {
  case 1:
  {
    TSystemisamfile f(atoi(argv(2)));
    TFilename lf;

    lf.format("%sstd/%s", __ptprf, argv(3));
    if (fexist(lf))
      f.load(lf, '|', '\0', '\n', TRUE, TRUE);
  }
  break;
 case 2:
  liala("LIA"); 
  liala("PLA"); 
  break;   
 case 3:
  if (_codditta == 0)
    patch_com();
 case 4:
  if (_codditta == 0)
    zero_770();
 case 5:
  convert_patty();    
 case 6:
  { 
    if (_codditta == 0) 
    {
      convert_codconc();

      TSystemisamfile comuni(LF_COMUNI);
   
      comuni.load(format("%sstd/ncom02.txt", __ptprf)); 
      
      //Cancella tutti i vecchi profili, sostituendoli con i nuovi
      convert_profili();
    }                 
  case 7:
   {
     if (_codditta == 0)
       convert_caus_attiv();
     break;
   }
  case 8:
   {
     if (_codditta == 0)
       rebuild_indexes();
     break;
   }
  }  
default:
  break;  
}
  return FALSE;
}

///////////////////////////////////////////////////////////
// Cambia i movimenti contabili in modo che abbiano un
// conto di contropartita e non una riga di riferimento
///////////////////////////////////////////////////////////

bool TConversione_archivi::convert_rmov(TLocalisamfile & rmov, TArray & recs, int nrecs)
{
  const TRecnotype pos = rmov.recno();

  for (int i = 0; i < nrecs; i++)
  {
    TRectype & r0 = (TRectype &) recs[i];
    const int rcontr = r0.get_int(RMV_RCONTR) - 1;

    if (rcontr >= 0 && rcontr < nrecs)
    {
      const TRectype & r1 = (const TRectype &) recs[rcontr];

      r0.put(RMV_TIPOCC, r1.get(RMV_TIPOC));
      r0.put(RMV_GRUPPOC, r1.get_int(RMV_GRUPPO));
      r0.put(RMV_CONTOC, r1.get_int(RMV_CONTO));
      r0.put(RMV_SOTTOCONTOC, r1.get_long(RMV_SOTTOCONTO));
    }
    r0.zero(RMV_RCONTR);
    if (rmov.rewrite(r0) != NOERR)
    {
      const long reg = r0.get_long(RMV_NUMREG);
      error_box("Non riesco ad aggiornare la riga contabile %ld / %d\nErrore n. %d", reg, i + 1, rmov.status());
      rmov.readat(pos);
      _error = 102;
      return FALSE;
    }
  }
  rmov.readat(pos);
  return TRUE;
}

void TConversione_archivi::contropartita_rmov()
{
  TDir d;
  d.get(LF_RMOV);
  if (d.eox() == 0) return;

  TLocalisamfile rmov(LF_RMOV);
  const TRecnotype nitems = rmov.items();
  TArray recs;
  long oldreg = -1;
  long reg = -1;
  int nrow = 0;
  TProgind p(nitems ? nitems : 1,
             format("Conversione righe di movimento della ditta %ld", get_firm()),
             FALSE, TRUE, 70);
  for (rmov.first(); rmov.good(); rmov.next())
  {
    p.addstatus(1);
    reg = rmov.get_long(RMV_NUMREG);
    if (oldreg != reg)
    {
      if (oldreg > 0)
        if (convert_rmov(rmov, recs, nrow) == FALSE)
          return;
      oldreg = reg;
      nrow = 0;
    }
    recs.add(rmov.curr(), nrow++);
    CHECKD(nrow == rmov.get_int(RMV_NUMRIG), "Missed row ", nrow); 
  } 
  if (oldreg > 0)
    if (convert_rmov(rmov, recs, nrow) == FALSE)
      return;
}


///////////////////////////////////////////////////////////
// Passa le tabelle LIA e PLA a %LIA e %PLA
///////////////////////////////////////////////////////////

void TConversione_archivi::liala(const char* table)
{                                                 
  TString16 tab(table);                                            
  TTable lia(tab);
  tab.insert("%", 0);
  TTable cia(tab);

  const long n = lia.items()+1;
  TProgind p(n, format("Conversione tabella %s della ditta %ld", table, get_firm()), FALSE, TRUE, 70);
  
  TString16 firm; firm.format("%05ld", get_firm());
  TString16 codtab;
  
  for (lia.first(); lia.good(); lia.next())
  {
    codtab = lia.get("CODTAB");
    codtab.insert(firm, 0);
    lia.put("CODTAB", codtab);
    cia.write(lia.curr());
  }
  
  for (lia.first(); lia.good(); lia.next())
    lia.remove();
}

///////////////////////////////////////////////////////////
// Sposta i codici uffici imposte e uffici IVA nei comuni
///////////////////////////////////////////////////////////

bool TConversione_archivi::collate(TRectype & rec, const char * f1, const char * f2)
{ 
  if (rec.get(f1).empty())
  {                              
    TString16 s(rec.get(f2)); 
    
    if (s.not_empty())
    {
      rec.put(f1, s);
      rec.zero(f2); 
      return TRUE;
    }   
  }               
  return FALSE;
}

bool TConversione_archivi::patch_uff(TRectype & rec, const char * const fnames[])
{  
  bool updated = collate(rec, fnames[1], fnames[2]);
  updated |= collate(rec, fnames[0], fnames[1]);
  updated |= collate(rec, fnames[1], fnames[2]);
  return updated;
}

void TConversione_archivi::patch_com()
{
  TLocalisamfile comuni(LF_COMUNI);    
  const char * const uff_iidd[] = {"UFFIIDD1", "UFFIIDD2", "UFFIIDD3"} ;
  const char * const uff_iva[] = {"UFFIVA1", "UFFIVA2", "UFFIVA3"} ;
  const TRecnotype nitems = comuni.items();
  TProgind p(nitems ? nitems : 1, format("Conversione comuni"), FALSE, TRUE, 70);
  
  for (comuni.first(); comuni.good(); comuni.next())
  {      
    p.addstatus(1);
    bool updated = patch_uff(comuni.curr(), uff_iidd);
    updated = patch_uff(comuni.curr(), uff_iva) || updated;
    if (updated)
      comuni.rewrite();
  }                                                    
}

void TConversione_archivi::zero_770()
{ 
  for (int i = LF_BASE ; i <= LF_DETH; i++)
  {
    TDir d;      
    
    d.get(i, _lock, _nordir, _sysdirop); 
    d.eod() = 0L;             
    d.eox() = 0L;
    d.put(i,  _nordir, _sysdirop);  
  }      
  TToken_string files;
  
  if (fexist(format("%scom/770", __ptprf)))
  {       
    files.format("%scom/770/%s", __ptprf, "*");   
    list_files(files);
    for (const char * s = files.get(); s != NULL; s = files.get())
      remove(s);               
    RMDIR(format("%scom/770", __ptprf)); 
  }
  if (fexist(format("%s770", __ptprf)))
  {       
    files.format("%s770/%s", __ptprf, "*");   
    list_files(files);
    for (const char * s = files.get(); s != NULL; s = files.get())
      remove(s);               
    RMDIR(format("%s770", __ptprf)); 
  }
}

void TConversione_archivi::convert_patty()
{                                      
{
  TTable ivd("%IVD");
  ivd.zero();
  ivd.put("CODTAB", "9E0023");
  if (ivd.read(_isequal, _lock) == NOERR)
    ivd.remove();
  ivd.put("CODTAB", "9E  23");
  if (ivd.read(_isequal, _lock) == NOERR)
    ivd.remove();  
  ivd.put("CODTAB", "9E    23");
  if (ivd.read(_isequal, _lock) == NOERR)
    ivd.remove();  
}
{
  TTable doc("%TPD");
  doc.zero();
  doc.put("CODTAB", "AN");
  if (doc.read(_isequal, _lock) == NOERR)
    doc.remove();
  doc.zero();
  doc.put("CODTAB", "IN");
  if (doc.read(_isequal, _lock) == NOERR)
    doc.remove();
  doc.zero();
  doc.put("CODTAB", "PG");
  if (doc.read(_isequal, _lock) == NOERR)
    doc.remove();
  doc.zero();
  doc.put("CODTAB", "NA");
  if (doc.read(_isequal, _lock) == NOERR)
    doc.remove();
  doc.zero();
  doc.put("CODTAB", "NC");
  if (doc.read(_isequal, _lock) == NOERR)
  {
    doc.put("S0", "Nota di credito");
    doc.put("I0", "9");
    doc.rewrite();
  }
} 
TAssoc_array causarr;

TDir d;
d.get(LF_CAUSALI,_nolock,_nordir,_sysdirop);
if (d.is_com())
  d.get(LF_CAUSALI,_nolock,_comdir);

  if (d.eod() > 0L)
{
  TLocalisamfile caus(LF_CAUSALI);
  for (caus.first(_lock); caus.good(); caus.next(_lock))
  {
    const TString16 tpd(caus.get("TIPODOC"));
    const TString16 incimm(caus.get("CODCAUSIM"));
    
    if (incimm.not_empty())
      causarr.add(incimm, incimm);
    if (tpd == "AN") caus.zero("TIPODOC");
    else
      if (tpd == "IN") caus.zero("TIPODOC");
      else
        if (tpd == "PG") caus.zero("TIPODOC");
        else
          if (tpd == "NA") caus.put("TIPODOC","NC");   
    
    caus.rewrite();
  }                  
}             
const bool topatch = causarr.items() > 0;

d.get(LF_MOV);
if (d.eod() > 0L)
{
  TLocalisamfile mov(LF_MOV);
  
  for (mov.first(_lock); mov.good(); mov.next(_lock))
  {
    const TString16 tpd(mov.get("TIPODOC"));
    if (topatch)
    {
      const TString16 codcaus(mov.get("CODCAUS"));
      
      if (causarr.objptr(codcaus) != NULL)
      {
        mov.zero("DATA74TER");
        mov.zero("REG");
        mov.zero("PROTIVA");
        mov.zero("UPROTIVA");
        mov.zero("REGST");
        mov.zero("TIPO");
        mov.zero("CODCF");
        mov.zero("TOTDOC");
        mov.zero("RITFIS");
        mov.zero("RITSOC");
        mov.zero("PROVVIS");
        mov.zero("CODVALI");
        mov.zero("CAMBIOI");
        mov.zero("CORRLIRE");
        mov.zero("CORRVALUTA");
        mov.zero("OCFPI");
        mov.zero("CODPAG");
      }
    }
    if (tpd == "AN") mov.zero("TIPODOC");
    else
      if (tpd == "IN") mov.zero("TIPODOC");
      else
        if (tpd == "PG") mov.zero("TIPODOC");
        else
          if (tpd == "NA") mov.put("TIPODOC","NC");
    mov.rewrite();
  }
}       
{

}
if (_codditta == 0)
{     
  TDir d;
  TSystemisamfile f(LF_FORM);
  TFilename lf;
         
  d.get(LF_FORM);
  lf.format("%sstd/lf0054.txt", __ptprf);
  if (fexist(lf) && fexist(d.filename()))
    f.load(lf);
}
}                                         

void TConversione_archivi::convert_caus_attiv()
{                                            
  {
    TLocalisamfile attiv(LF_ATTIV); 
    TProgind p(attiv.items(), "Conversione archivio attivita'", FALSE, TRUE,20);
    p.setstatus(1L);
    for (attiv.first(); !attiv.eof(); attiv.next())
    {
      bool val = attiv.get_bool("ART74/4");
      attiv.put("ART74_4", val);
      attiv.rewrite();
      p.addstatus(1L);
    }                           
  }    
  {
    TLocalisamfile ditte(LF_NDITTE);
    TProgind p(ditte.items(), "Conversione archivi causali", FALSE, TRUE,5);
    p.setstatus(1L);
    set_autoload_new_files(FALSE);
    for (ditte.first(); !ditte.eof(); ditte.next())
    {
      const long codditta = ditte.get_long("CODDITTA");
      if (prefix().exist(codditta))
      {
        p.set_text(format("Ditta: %ld",codditta));
        set_firm(codditta);
        TLocalisamfile caus(LF_CAUSALI);
        caus.zero();
        caus.put("CODCAUS","C08");      
        if (caus.read() == NOERR)       
           caus.put("TIPODOC","FS");    
        caus.rewrite();
      }             
      p.addstatus(1);
    }                               
    p.setstatus(ditte.items());
    prefix().set("com");
    set_autoload_new_files(TRUE);
  }
}

void TConversione_archivi::convert_profili()
{
  TSystemisamfile form(LF_FORM),rform(LF_RFORM);
  TDir d;
  TFilename lf;
       
  d.get(LF_FORM, _nolock, _comdir, _sysdirop);
  d.eod() = 0;
  d.put(LF_FORM, _comdir, _sysdirop);
  form.pack();
  lf.format("%sstd/lf0054.txt", __ptprf);
  if (fexist(lf)) form.load(lf);
  d.get(LF_RFORM, _nolock, _comdir, _sysdirop);
  d.eod() = 0;
  d.put(LF_RFORM, _comdir, _sysdirop);
  rform.pack();
}

void TConversione_archivi::convert_codconc()
{     
// costruisce le tabelle di confronto                                 
  TAssoc_array conc_cessate;
  TScanner oc(format("%sstd/oconc00.txt", __ptprf)); 
    
  for (TString16  s(oc.line()); s.not_empty(); s = oc.line()) 
    conc_cessate.add(s);
// (fase 1)
// scorre il file anagrafica  
  TLocalisamfile anagr(LF_ANAG);
  TLocalisamfile comuni(LF_COMUNI);
  int nerr = 0;
// se il file anagrafica non é vuoto
  const long anag_items = anagr.items();
  if (anag_items > 0)
  {
    TProgind p(anag_items, "Conversione archivio anagrafica", FALSE, TRUE, 70);
    
    p.setstatus(1L);

// per ogni anagrafica  blocca il record
    for (anagr.first(_lock); anagr.good(); anagr.next(_lock))
    {
//   legge il codice comune
      TString16 com = anagr.get("COMRF");

      p.addstatus(1);                           
      if (com.empty())
        com = anagr.get("COMRES");
//   se il comune non é vuoto recupera il comune       
      if (com.not_empty())
      {                                                                             
        comuni.zero();
        comuni.put("COM", com);
// se non é un comune di una nuova provincia e il comune esiste    
        if (!conc_cessate.is_key(com))
        {
          if (comuni.read() == NOERR)
          {                  
//   legge il codice concessione
            TString16 conc(comuni.get("UFFCONC"));
//   se il codice concessione é cessato
            if (conc_cessate.is_key(conc))
            {   
//     scrive il codice concessione sull' anagrafica
              anagr.put("UFFCONC", conc);
              anagr.rewrite();
            }
//   altrimenti sblocca il record              
            else
              anagr.read(_iscurr, _unlock);                  
         }
//   altrimenti sblocca il record e conteggia l' errore
          else
          {
            anagr.read(_iscurr, _unlock);
            nerr++;
          }  
        }
      } 
//   altrimenti sblocca il record              
      else
        anagr.read(_iscurr, _unlock);
    }
  }                              
// segnala gli errori
#ifdef DBG
  if (nerr)
    error_box("La conversione della anagrafiche non ha trovato %d comuni", nerr);
  nerr = 0; 
#endif

// (fase 2) 
// vuota la tabella concessioni
  {
    TTable uffconc("%UCC");
  
    for (uffconc.first(_lock); uffconc.good(); uffconc.next(_lock))
      uffconc.remove();
   }
// carica la nuova            
   {
     TSystemisamfile tabcom(LF_TABCOM);
   
     tabcom.load(format("%sstd/nconc00.txt", __ptprf)); 
   }  
// (fase 3)
// scorre il file con i codici comuni e le nuove concessioni
  TScanner nc(format("%sstd/ncom00.txt", __ptprf)); 
  TProgind p(comuni.items(), "Conversione archivio comuni", FALSE, TRUE, 70);  
  TToken_string comass;
#ifdef DBG   
  TTable uffconc("%UCC");
  TToken_string concerr;
#endif       

  p.setstatus(1L);
// per ogni comune
  for (TToken_string ts(nc.line()); ts.not_empty(); ts = nc.line()) 
  {                          
    p.addstatus(1);
//  cerca il comune
    comuni.zero();
    comuni.put("COM", ts.get());
// se esiste
    if (comuni.read(_isequal, _lock) == NOERR)                     
    {
//   aggiorna il codice concessione sul comune in oggetto
      comuni.put("UFFCONC", ts.get());
      comuni.rewrite();
#ifdef DBG   
      uffconc.zero();
      uffconc.put("CODTAB", comuni.get("UFFCONC"));
      if (uffconc.read() != NOERR)
        concerr.add(comuni.get("UFFCONC")); 
#endif       
    }
//   altrimenti sblocca il record e conteggia l' errore
    else                                               
    {
      comuni.read(_iscurr, _unlock);
      comass.add(ts.get(0));
      nerr++;    
    }
  } 
// segnala gli errori
#ifdef DBG
  if (nerr)
    error_box("La conversione dei comuni non ne ha trovati %d\n Codici : %s", nerr, (const char *) comass);
  if (concerr.not_empty())
    error_box("Le seguenti concessioni sono inesistenti %s", (const char *) concerr);
#endif       
}                                                      

void TConversione_archivi::rebuild_indexes()
{  
  do_events();
  begin_wait();
  prefix().set("com");
  rebuild_dir_indexes();
  TSystemisamfile ditte(LF_NDITTE);
  ditte.open();
  
  for (ditte.first(); !ditte.eof(); ditte.next())
  {
    const long codditta = ditte.get_long("CODDITTA");
    const TRecnotype rec = ditte.recno();
    
    if (prefix().exist(codditta))
    {
      ditte.close();
      set_firm(codditta);
      rebuild_dir_indexes();
      ditte.open();
    }
    ditte.readat(rec);
  }
  ditte.close();
  end_wait();
}                                            

void TConversione_archivi::rebuild_dir_indexes()
{                                            
  const TString pref(prefix().name());
  const bool is_com = prefix().is_com();
  TDir d;  
  
  d.get(LF_DIR);                 
  const int items = (int)d.eod();
  TString80 s("Ricostruzione indici ");

  if (is_com) s << "comuni";
  else s << " della ditta " << atol (pref);
  
  TProgind p(items ? items : 1, s, TRUE, TRUE, 70);

  p.setstatus(1);
  
  for (int i = 2; i <= items; i++)
  {  
    p.addstatus(1);
    if (d.len() > 0)
    { 
      d.get(i, _nolock, _nordir, _sysdirop); 
      bool to_create = (is_com ? d.is_com() : d.is_firm());
    
      if (to_create)
      {
        d.get(i);
        TFilename s(d.name());
        s.ext("dbf");
        if (fexist(s))
        {
          TSystemisamfile f(i);
          f.packindex();         
        }
      }
    }
  }
}

///////////////////////////////////////////////////////////
// Programma di conversione archivi speciale
///////////////////////////////////////////////////////////

int main(int argc,char** argv)
{
  const int r = (argc > 1) ? atoi(argv[1]) : 0;
  
  if (r < 0 || r > 8)
  {
    error_box(usage);
    return 100;
  }
  else
    if (r==0)
    {
      TConversione_xbase a;
      a.run(argc,argv, "Conversione archivi di xBase");
    }
    else
    {
      TConversione_archivi a ;
      a.run(argc, argv, "Conversione archivi");
    }

  return 0;
}

