//AB2102.CPP Trasferimento tabelle

#include <utility.h>    //Definizione di fexit
#include "movdett.h"    //Contiene le definizioni di costanti relative ai nomi dei campi di LF_MOVDETT
#include "saldi.h"      //Contiene le definizioni di costanti relative ai nomi dei campi di LF_SALDI
#include "relana.h"     //Contiene le definizioni di costanti relative ai nomi dei campi di LF_RELANA
#include "ab2100.h"   
#include "ab2100a.h"
#include <progind.h>
#include <assoc.h>
#include <varrec.h>

#define TABELLA_TIPO_BILANCI "NTBBB"

const char* get_ordinamento(TVariable_rectype & rec)
{     
  if (rec.get(ABMD_TIPODETT) == FLAG_DETT_DT || rec.get(ABMD_TIPODETT) == FLAG_COGE_CG )
  { //E' un record di MOVI3
    return (MOVIMENTO3);
  }             
  
  if (rec.get(ABMD_TIPODETT) == FLAG_CLIENTE_CL)
  {//E' un record di MOVI4
     return (MOVIMENTO4);
  }                       
  
  if (rec.get(ABMD_TIPODETT) == FLAG_FORNITORE_FO)
  {//E' un record di MOVI5
    return (MOVIMENTO5);
  }
  
  if (rec.get(ABMD_TIPODETT) == FLAG_MOVIMENTO_MO)
  {//Pu� essere MOVI 1 2
    real r(rec.get(ABMD_IMPORTO)); 
    if (r > 0)
    //Se � un saldo il record va in MOVI1
      return (MOVIMENTO1);
    //Se � un progressivo o una riclassificazione va in MOVI2
    return (MOVIMENTO2);
  } 
  //A questo punto la funzione non dovrebbe mai arrivare
  CHECK (FALSE,"La funzione get_ordinamento ritorna un valore non valido");
  return NULL;
}   

bool TInvio_AS400::cerca_padre(TLocalisamfile & padre, TRectype &node)
{
  padre.put(ABMD_CODDITTA,node.get(ABMD_CODDITTA));
  padre.put(ABMD_ANNO,node.get(ABMD_ANNO));
  padre.put(ABMD_CODPDB,node.get(ABMD_CODPDB));
  padre.put(ABMD_TIPOBIL,node.get(ABMD_TIPOBIL));
  padre.put(ABMD_CODCBL,node.get(ABMD_CODCBL));
  padre.put(ABMD_ID,node.get(ABMD_IDPADRE));
  if (padre.read() == NOERR)
    return TRUE;
  return FALSE;
}
                        
long TInvio_AS400::my_num(TLocalisamfile& mov, TAssoc_array& progressivi)
{
  long ret = 1;
  
  TToken_string my_key;
  my_key.add(mov.get(ABMD_CODDITTA));
  my_key.add(mov.get(ABMD_ANNO));
  my_key.add(mov.get(ABMD_CODPDB));
  my_key.add(mov.get(ABMD_TIPOBIL));
  my_key.add(mov.get(ABMD_CODCBL));
  my_key.add(mov.get(ABMD_ID));
  
  if (progressivi.is_key(my_key))
  { 
    ret = atol(*(TString*)progressivi.objptr(my_key));
  }
  else
  {                         
    long id_prec =mov.get_long(ABMD_IDPREC);
   // if (id_prec != ID_NULLO) // Se il padre di un movimento � nullo significa che � un movimento di un saldo
   // {                 
    mov.put(ABMD_ID,id_prec);
    if (mov.read()== NOERR)
    {
      ret=my_num(mov,progressivi)+1;
    }
     // else
     //   CHECK (FALSE,"Si � verificata una inconsistenza nei dati: � stato trovato un movimento senza il padre!");
    //}       
    TString16 str_ret;
    str_ret << ret;
    progressivi.add(my_key,str_ret);
  }  
  return ret;
}
                        
void TInvio_AS400::trasferisci_albero(TRectype &node, TRecord_text &rec, TAssoc_array &progressivi)
{  
  TLocalisamfile mov(LF_MOVDETT);   
  
  //Se � un COGE scrivo il CODICE_COGE nel relativo campo
  if (node.get(ABMD_TIPODETT) == FLAG_COGE_CG)
    rec.add(node.get(ABMD_CODDETT),CONTO_COGE_MOVDETT);
    
  //Se � un movimento ...
  if (node.get(ABMD_TIPODETT)== FLAG_MOVIMENTO_MO)
  { //... sono all'ultimo livello: trovo il padre
    if (cerca_padre(mov,node))
    {//Questo � il padre del movimento 
      if (mov.get(ABMD_TIPODETT) == FLAG_COGE_CG) //Se il padre � un COGE scrivo il CONTO COGE nel relativo campo
        rec.add(node.get(ABMD_CODDETT),CONTO_COGE_MOVDETT);
        //altrimenti, se il padre � un dettaglio, non scrivo nessuna informazione aggiuntiva
    }
  // Se il padre del movimento non esiste, allora � un movimento di un saldo
  //  else
  //  {//Non dovrebbe mai succedere: non esiste il padre del movimento
  //    CHECK (FALSE,"Si � verificata una inconsistenza nei dati: � stato trovato un movimento senza il padre!");
  //  }                         
    
    //Questa parte esegue la "numerazione progressiva" dei movimenti: assegna il numero di riga
    TString16 num_riga;
    mov.curr()=node;
    num_riga << my_num(mov,progressivi);
    rec.add(num_riga,NUMERO_RIGA_MOVDETT);
    
    //Trovo il padre se esiste      
    long id_padre = atol(node.get(ABMD_IDPADRE));
    real r(node.get(ABMD_CODDETT));
    if ((id_padre != ID_NULLO) && (r == 0)) //Se esiste il padre e non sono un COGE devo assegnarmi
                              //nel campo PROGRESSIVO_DETT il numero progressivo del padre
    {//Leggo il padre
      mov.curr()=node;
      mov.put(ABMD_ID,id_padre);
      if (mov.read()==NOERR)
      {
        TString16 num_prog;
        num_prog << my_num(mov,progressivi);
        rec.add(num_prog,PROGRESSIVO_DETT_MOVDETT);  //Questo � un record di tipo MOVIMENTI
      }
      else
        CHECK (FALSE,"Si � verificata una inconsistenza nei dati: � stato trovato un movimento senza il padre!");
    }
  }//Fine parte "ricostruzione" albero dei movimenti
  
  //Questa parte "ricostruisce" l'albero dei dettaglio
  if (node.get(ABMD_TIPODETT)== FLAG_DETT_DT)
  {                   
    mov.curr()=node;       
    TString16 num; 
    num << my_num(mov,progressivi);
    rec.add(num,PROGRESSIVO_DETT_MOVDETT);  //Questo � un record di tipo DETTAGLI
  }
}

bool TInvio_AS400::mov_da_scrivere(TRectype &node)
{
  TLocalisamfile dett(LF_MOVDETT);
  if (node.get_long(ABMD_IDPADRE) == ID_NULLO) //Sono al primo livello
    return TRUE;
    
  if (cerca_padre(dett,node))
  {
    if (dett.get_long(ABMD_IDPADRE) == ID_NULLO) //Sono al secondo livello
      return TRUE;
    else
    {
      if (dett.get(ABMD_TIPODETT) == FLAG_COGE_CG) //Sono al terzo livello, ma ammetto solo i COGE
        return TRUE;
    }
  }
  return FALSE; //Tutti i livelli superiori a 2 e tutti i casi che non riesco a gestire
}   

void TInvio_AS400::formatta(TRecord_text &rec, TRectype &node, int &logic_num)
{                                           
  if (logic_num == LF_MOVDETT)
  {
    if ((rec.type() == MOVIMENTO1) || (rec.type() == MOVIMENTO2))
    {//Se c'� un valore significativo in IMPORTO significa che questo valore va
     //inserito nel campo IMPORTO del file di testo e settato il flag D/A 
     //Il tipo record (gi� settato) � MOVI1
      real r(node.get(ABMD_IMPORTO));
      if (r > 0)
      {               
        TString imp = node.get(ABMD_IMPORTO);
        rec.add(node.get(ABMD_FLDA),FLAG_DA_MOVDETT);
        rec.add(imp.rtrim(4),IMPORTO_MOVDETT);
      }
      else
      {//Questi valori vanno inseriti in IMPORTO di MOVI2
        real rpd(node.get(ABMD_PDARE));
        real rpa(node.get(ABMD_PAVERE));
        real rrd(node.get(ABMD_RDARE));
        real rra(node.get(ABMD_RAVERE));
        if (rpd > 0)
        {                   
          TString imp =node.get(ABMD_PDARE);
          rec.add("D",FLAG_DA_MOVDETT);
          rec.add(imp.rtrim(4),IMPORTO_MOVDETT);
        }
        if (rpa > 0)  
        {
          TString imp = node.get(ABMD_PAVERE);
          rec.add("A",FLAG_DA_MOVDETT);
          rec.add(imp.rtrim(4),IMPORTO_MOVDETT);
        }
        if (rrd > 0)
        {            
          TString imp = node.get(ABMD_RDARE);
          rec.add("X",FLAG_RICLASSIFICAZIONE_MOVDETT);
          rec.add("D",FLAG_DA_MOVDETT);
          rec.add(imp.rtrim(4),IMPORTO_MOVDETT);
        }
        if (rra > 0)  
        {            
          TString imp = node.get(ABMD_RAVERE);
          rec.add("X",FLAG_RICLASSIFICAZIONE_MOVDETT);
          rec.add("A",FLAG_DA_MOVDETT);
          rec.add(imp.rtrim(4),IMPORTO_MOVDETT);
        }
      }
    }
    else
    {//Questi sono gli importi dei dettagli
      TString sld = rec.row(SALDO_INIZIO_ANNO_MOVDETT);
      rec.add(sld.rtrim(4),SALDO_INIZIO_ANNO_MOVDETT);
      TString pda = rec.row(PROGRESSIVO_DARE_MOVDETT);
      rec.add(pda.rtrim(4),PROGRESSIVO_DARE_MOVDETT);
      TString pav = rec.row(PROGRESSIVO_AVERE_MOVDETT);
      rec.add(pav.rtrim(4),PROGRESSIVO_AVERE_MOVDETT);
      TString rda = rec.row(RICLASSIFICAZIONE_DARE_MOVDETT);
      rec.add(rda.rtrim(4),RICLASSIFICAZIONE_DARE_MOVDETT);
      TString rav = rec.row(RICLASSIFICAZIONE_AVERE_MOVDETT);
      rec.add(rav.rtrim(4),RICLASSIFICAZIONE_AVERE_MOVDETT);
    }
  }// end if LF_MOVDETT
  if (logic_num == LF_ABSALDI)
  {
    TString sld = rec.row(SALDO_INIZIO_ANNO_SLD_MOVDETT);
    rec.add(sld.rtrim(4),SALDO_INIZIO_ANNO_SLD_MOVDETT);
    TString pda = rec.row(PROGRESSIVO_DARE_SLD_MOVDETT);
    rec.add(pda.rtrim(4),PROGRESSIVO_DARE_SLD_MOVDETT);
    TString pav = rec.row(PROGRESSIVO_AVERE_SLD_MOVDETT);
    rec.add(pav.rtrim(4),PROGRESSIVO_AVERE_SLD_MOVDETT);
    TString rda = rec.row(RICLASSIFICAZIONE_DARE_SLD_MOVDETT);
    rec.add(rda.rtrim(4),RICLASSIFICAZIONE_DARE_SLD_MOVDETT);
    TString rav = rec.row(RICLASSIFICAZIONE_AVERE_SLD_MOVDETT);
    rec.add(rav.rtrim(4),RICLASSIFICAZIONE_AVERE_SLD_MOVDETT);
  }// end if LF_ABSALDI
  if (logic_num == LF_TABCOM && rec.type() == TIPO_TABELLA_PERIODI)
  {
    rec.add(SIGLA_TABELLA_PERIODI,SIGLA_TAB_PER);
  }
}
                                          
void TObject_send::converti(int logic_num)
{
  TRelation *tr_relation=_trasfile->t_rec(logic_num)->relation();
  TRecord_text rec(_trasfile->t_rec(logic_num)->type());         //Istanzio un tipo record_text
  TCursor *cur=NULL;
  cur = new TCursor(tr_relation);
  
  //Leggo il numero di records da convertire
  long items =cur->items();
  //Barra scorrevole di attesa
  TProgind idle(items,TR("Attendere: conversione in corso ..."),TRUE,TRUE,60);
  
  //Ciclo principale di conversione
  for (*cur=0;cur->pos()<items;++*cur)
  {
     idle.addstatus(1);
     _trasfile->autoload(rec,logic_num);
     rec.add(rec.type(),0);
    _trasfile->write(rec);
  }
  delete cur;
}              

void TObject_send::converti(int main_file, const char * tabname)
{
  TRelation *tr_relation=_trasfile->t_rec(main_file,tabname)->relation();
  TRecord_text rec(_trasfile->t_rec(main_file,tabname)->type());         //Istanzio un tipo record_text
  TCursor *cur=NULL;
  cur = new TCursor(tr_relation);
  
// int logic_num= tr_relation->lfile().num();
  //Leggo il numero di records da convertire
  long items =cur->items();
  //Barra scorrevole di attesa
  TProgind idle(items,TR("Attendere: conversione in corso ..."),TRUE,TRUE,60);
  
  //Ciclo principale di conversione
  for (*cur=0;cur->pos()<items;++*cur)
  {
     idle.addstatus(1);
//     _trasfile->autoload(rec,logic_num);
     _trasfile->autoload(rec,tabname);
     rec.add(rec.type(),0);
    _trasfile->write(rec);
  }
  delete cur;
}              

void TInvio_AS400::converti(int logic_num)
{

  TRelation *tr_relation=trans_file()->t_rec(logic_num)->relation();
  TRecord_text rec(trans_file()->t_rec(logic_num)->type());         //Istanzio un tipo record_text
  TCursor *cur=NULL;
  TAssoc_array progressivi;
    
  if (logic_num == LF_MOVDETT)
  {
    TVariable_rectype *vrec_rmov= new TVariable_rectype(LF_MOVDETT);
    vrec_rmov->add_field(new TVariable_field (ABMD_TIPO_TRACCIATO,get_ordinamento,5));
    //Costruisco la chiave del TSorted_cursor
    TToken_string exp(ABMD_TIPO_TRACCIATO);
    exp.add(ABMD_CODDITTA);
    exp.add(ABMD_ANNO);
    exp.add(ABMD_CODPDB);
    exp.add(ABMD_TIPOBIL);
    exp.add(ABMD_CODCBL);
    exp.add(ABMD_ID);
    cur = new TSorted_cursor(tr_relation,exp);
    cur->file().set_curr(vrec_rmov);
  }
  else
    cur = new TCursor(tr_relation);

  //Leggo il numero di records da convertire
  long items =cur->items();
  //Barra scorrevole di attesa
  TProgind idle(items,TR("Attendere: conversione in corso ..."),TRUE,TRUE,60);
  
  //Ciclo principale di conversione
  for (*cur=0;cur->pos()<items;++*cur)
  {
    idle.addstatus(1);
    if (logic_num == LF_MOVDETT)
    {//In questo caso la conversione � un po' particolare
      rec.set_type(tr_relation->lfile().get(ABMD_TIPO_TRACCIATO));
      trans_file()->autoload(rec,*cur,&rec.type());
      if (mov_da_scrivere(tr_relation->lfile().curr()))
      {
        trasferisci_albero(tr_relation->lfile().curr(),rec,progressivi);
        formatta(rec,tr_relation->lfile().curr(),logic_num);
        trans_file()->write(rec);
      }
    } 
    else
    {//in tutti gli altri casi la conversione � semplice
      trans_file()->autoload(rec,logic_num);
      if (logic_num == LF_ABSALDI || logic_num == LF_TABCOM)
        formatta(rec,tr_relation->lfile().curr(),logic_num);
      trans_file()->write(rec);
    }
  }
  delete cur;
}

//Handler per l'inserimento del percorso completo
bool TInvio::inseriscipercorso(TMask_field& f, KEY k)
{
  TString percorso;
  percorso=f.get();       //Leggo il contenuto del campo
  return TRUE;
}


//Funzione membro che esegue la conversione di trasferimento
//bool TInvio_AS400::menu(MENU_TAG)
void TInvio::main_loop()
{
  TMask msk("AB2100A");                 //Maschera dove si chiede di immettere il percorso del file sorgente
  TFilename percorso;                   //Contiene il percorso completo del file sorgente
  
  
  msk.set_handler(F_PERCORSO, inseriscipercorso); //Assegno un handler al campo F_PERCORSO
                                        //inseriscipercorso controlla che il percorso (e il file) esista e sia corretto
  msk.set_handler(F_PERCORSO_UTENTE, inseriscipercorso);
  msk.hide(F_TIPO_BILANCIO);  //nascondo questo campo poich� non mi serve
  msk.hide(F_TESTO_TIPOBIL);  //nascondo questo campo poich� non mi serve
  msk.enable(-1,TRUE);
  if (msk.run()== K_ENTER)     //Eseguo la maschera
  {     
    //A questo punto il percorso e' corretto
    percorso=msk.get(F_PERCORSO); //Leggo il contenuto di F_PERCORSO
    
    if (msk.get_int(F_TIPO_RICE) == RICEZIONE_AS400)
    {
      if ((msk.get_bool(F_VOCI) == TRUE) ||
          (msk.get_bool(F_RELAZ) == TRUE) || 
          (msk.get_bool(F_SRELAZ) == TRUE))
        {
          message_box(TR("L'invio a AS400 delle VOCI, RELAZIONI e SOTTORELAZIONI non � attualmente previsto"));
        }  
      _invio = new TInvio_AS400(percorso);
    }
    
    if (msk.get_int(F_TIPO_RICE) == RICEZIONE_INTERNA)
    {                                     
      _invio = new TObject_send(percorso);
    }
    if (msk.get_int(F_TIPO_RICE) == RICEZIONE_USER_DEFINED)
    {
      TString config_file(msk.get(F_PERCORSO_UTENTE));                  //Nome del file di configurazione
      _invio = new TInvio_user_defined(config_file,percorso);
    }
    
// Parte di invio    
    if (msk.get_bool(F_PIANO_CONTI)==TRUE)                //Controllo se si � scelto di convertire il piano dei conti
    {
      _invio->converti(LF_ABPCON);                                //Conversione
    }
    
    
    if (msk.get_bool(F_PERIODI_BILANCI)==TRUE)          //Scelta di convertire la tabella periodi bilanci
    {
      if (msk.get_int(F_TIPO_RICE) == RICEZIONE_AS400)
      {//Se eseguo un invio a AS400 converto passando il numero del file
        _invio->converti(LF_TABCOM);
      }
      else
      { //Se eseguo un invio interno converto passando il nome della tabella comune
        _invio->converti(LF_TABCOM,"%PDB");
        _invio->converti(LF_TABCOM,"%NTB");
      }
    }
    
    if (msk.get_bool(F_ANALISI)==TRUE)                  //scelta di cnverite la tabella tipi analisi di bilancio
    {
      _invio->converti(LF_ANALISI);
    }

    if (msk.get_bool(F_MOVIMENTI)==TRUE)                  //scelta di cnverite la tabella tipi analisi di bilancio
    {
      _invio->converti(LF_MOVDETT);
    }
    
    if (msk.get_bool(F_SALDI)==TRUE)                  //scelta di cnverite la tabella tipi analisi di bilancio
    {
      _invio->converti(LF_ABSALDI);
    }
    
    if (msk.get_int(F_TIPO_RICE) != RICEZIONE_AS400)
    {// Solo se non � un invio ad AS400
      if (msk.get_bool(F_VOCI)==TRUE)                  //scelta di cnverite la tabella tipi analisi di bilancio
      {
        _invio->converti(LF_VOCI);
      }
      
      if (msk.get_bool(F_RELAZ)==TRUE)                  //scelta di cnverite la tabella tipi analisi di bilancio
      {
        _invio->converti(LF_RELVOCI);
      }
      
      if (msk.get_bool(F_SRELAZ)==TRUE)                  //scelta di cnverite la tabella tipi analisi di bilancio
      {     
        if (msk.get_int(F_TIPO_RICE) == RICEZIONE_INTERNA)
        {
          _invio->converti(LF_CARADD);
          _invio->converti(LF_COLLDICH);
        }
        _invio->converti(LF_RELANA);
      }
    }
    delete _invio;

    //messaggio finale

  message_box(" ... aggiornamento delle tabelle effettuato");
  } //end if (msk.run())
//  return FALSE;
} 

int ab2102(int argc, char **argv)
{
  TInvio a;
  a.run(argc,argv,TR("Trasferimento su file di testo"));
  return 0;
}

TObject_send::TObject_send(const TFilename &percorso)
{ 
  if (_trasfile != NULL)
    delete _trasfile;
  _trasfile = new TFile_text(percorso, "ab2100b.ini");  /*DA CAMBIARE*/
  _trasfile->open('w');     //apro il TFile_text in lettura
}

TInvio_AS400::TInvio_AS400(const TFilename &percorso)
{
  if (_trasfile != NULL)
    delete _trasfile;
  _trasfile = new TFile_text(percorso, "ab2100a.ini");  /*DA CAMBIARE*/
  _trasfile->open('w');     //apro il TFile_text in lettura

}

TInvio_user_defined::TInvio_user_defined(const TString & config, const TFilename &percorso)
{
  if (_trasfile != NULL)
    delete _trasfile;
  _trasfile = new TFile_text(percorso, config);  //Leggo il file di configurazione
  _trasfile->open('w');     //apro il TFile_text in lettura
}