// cg1100.cpp
// Stampa piano dei conti

#include <execp.h>
#include <mailbox.h>
#include <mask.h>
#include <printapp.h>
#include <relation.h>
#include <sort.h>
#include <tabutil.h>
#include <utility.h>
#include <progind.h>

#include <nditte.h>
#include <pconti.h>

#include "cg1.h"
#include "cg1100.h"

const char * TAB_ANABIL = "%IVD";
const char * TAB_IVD = "%IVD";

const int CODTABLEN = 15;

enum stampe {
  completa=1,
  con_IV_direttiva,
  senza_IV_direttiva,
  completa_bil,
  con_ana_bil,
  senza_ana_bil
  };

class CG1100_application : public TPrintapp
{                                              
  struct bil_ivd
  {
    char   sez;
    char   let;
    char   numr[5];
    char   num[4];
    char   gruppo[4];
    char   conto[4];
    char   sottoc[8];
    char   descr[52];
    char   sez_opp;
    char   let_opp;
    char   numr_opp[5];
    int    num_opp;
  };
  
  bil_ivd*            _bil;
  TTable*             _tab;           // tabella codici IV direttiva
  TIsamtempfile*      _tpcon;
  TLocalisamfile*     _pcon;
  TRectype*           _rec;
  TSort*              _sort;
  TRelation*          _rel, *_relt;
  TMask*              _msk;           
  TParagraph_string   _d1, _d2;            // qui
  const char*         _buf;
  stampe              _tipo_stampa;
  bool                _salto_pag,_resetta_righe_stampa;
  int                 _old_gruppo;
  int                 _pcont_reclen,_i;
  int                 _cur_c1, _cur_c2, _cur_c3;
  TString             _clivd, _clivdo;  
  char                _sez_da_stamp,_sez_stamp,_let_da_stamp,_let_stamp;
  TString             _numr_da_stamp,_numr_stamp;
  int                 _gruppo,_conto,_num_da_stamp,_num_stamp,_g_prec,_c_prec;
  long                _sottoc,_s_prec;
  TString             _classe_da_stampare,_classe_stampata,_codcbl_da_stamp,_codcbl_stamp; 
  bool                _conto_classificato,_sottoc_classificato,_stampa_riga_vuota;
  bool                _prima_volta, _stampa_g, _stampa_c;
  TDate               _data_stampa;
  
public:

  virtual bool user_destroy() ;
  virtual bool user_create() ;                        

  virtual void set_page (int,int);
  virtual bool preprocess_print (int,int);
  virtual bool preprocess_page (int,int);
  virtual print_action postprocess_page (int,int);  
  virtual void postclose_print ();

  virtual bool set_print(int);

  void intesta (stampe);
  
  bool elabora_riga();  // decide se fare salto pagina o no
  void do_sort();
  void set_completa ();
  void set_con_IV ();
  void set_senza_IV_ana ();
  void set_con_ana ();
//  void set_senza_ana ();       
  void prepara_pcon_temp();
  void cancella(int,int,long);
  void init_sort();
  const char* descrizione_numero(char, char, int, int);
  const char* descrizione_codcbl(TString&);
  // void setta_righe_descr(TParagraph_string*);
  int  leggo_sottoc(int,int,long);
  void riempi_record(char,char,const TString&,int,int,int,long,const TString&,char,char,const TString&,int);
  void set_bil_key(bil_ivd* b, char sezione, char lettera,
                   const char* numero_romano, int numero,
                   int gruppo = 0, int conto = 0, long sottoconto = 0L);
  void set_bil_val(bil_ivd* b, const char* descr,char sez_opp,char let_opp,
                   const char* numr_opp,int num_opp);

  void process_link(int id, const char* txt);

  CG1100_application() : _clivd(8), _clivdo(8), _d1("", 30), _d2("", 40) {}
};

void CG1100_application::process_link(int id, const char* txt)
{
  TString ss = "1|"; ss << txt;
  TMessage fs(cmd2name("cg0","-0"), MSG_LN, ss);
  TMailbox m;
  m.send(fs);              
  TExternal_app cg0("cg0 -0");
  if (cg0.run()) beep();
}

void CG1100_application::init_sort()
{
  switch (_tipo_stampa)
  {
  case con_IV_direttiva:
    _sort->reset(sizeof(bil_ivd));
    
    _sort -> addsortkey ((char*)&(_bil->sez)    - (char*)&(_bil->sez),1);
    _sort -> addsortkey ((char*)&(_bil->let)    - (char*)&(_bil->sez),1);
    _sort -> addsortkey ((char*)&(_bil->numr)   - (char*)&(_bil->sez),4);
    _sort -> addsortkey ((char*)&(_bil->num)    - (char*)&(_bil->sez),2);
    _sort -> addsortkey ((char*)&(_bil->gruppo) - (char*)&(_bil->sez),3);
    _sort -> addsortkey ((char*)&(_bil->conto)  - (char*)&(_bil->sez),3);
    _sort -> addsortkey ((char*)&(_bil->sottoc) - (char*)&(_bil->sez),6);
    break;
  case con_ana_bil:
  {
    TRecfield codcbl  (*_rec, PCN_CODCBL);
    TRecfield gruppo  (*_rec, PCN_GRUPPO);
    TRecfield conto   (*_rec, PCN_CONTO);
    TRecfield sottoc  (*_rec, PCN_SOTTOCONTO);

    _sort->reset(_rec->len());
    _sort->addsortkey (codcbl);
    _sort->addsortkey (gruppo);
    _sort->addsortkey (conto);
    _sort->addsortkey (sottoc);
    
    break;
  } 
  default:
    break;
  }
}

void CG1100_application::set_bil_key(bil_ivd* b, char sezione, char lettera,
                                     const char* numero_romano, int numero,
                                     int gruppo, int conto,long sottoconto)
{
  b->sez = sezione;
  b->let = lettera;
  strcpy(b->numr, numero_romano);
  sprintf(b->num , "%2d", numero);
  sprintf(b->gruppo , "%3d", gruppo);
  sprintf(b->conto , "%3d", conto);
  sprintf(b->sottoc , "%6ld", sottoconto);
}

void CG1100_application::set_bil_val(bil_ivd* b, const char* descr, 
                                     char sez_opp,char let_opp,
                                     const char* numr_opp,int num_opp)
{
  strcpy(b->descr, descr);
  b->sez_opp           = sez_opp;
  b->let_opp           = let_opp;
  strcpy(b->numr_opp, numr_opp);
  b->num_opp           = num_opp;
}

void CG1100_application::riempi_record(char sez,char let,const TString& numr,
                                       int numero,int g,int c,long s,
                                       const TString& descr,char sez_opp,
                                       char let_opp,const TString& numr_opp,
                                       int num_opp)
{
  set_bil_key(_bil, sez, let, numr, numero, g, c, s);
  set_bil_val(_bil, descr, sez_opp, let_opp, numr_opp, num_opp);
  _sort->sort ((const char*) _bil);
}

void CG1100_application::postclose_print()
{     
  if (_tipo_stampa == senza_ana_bil)
  {
    delete _tpcon;
    delete _relt;
  }
}

print_action CG1100_application::postprocess_page(int file,int counter)
{    
  switch (_tipo_stampa)
  {
    case completa:
    case senza_IV_direttiva:   
    case completa_bil:
    case senza_ana_bil:
    break;
    case con_IV_direttiva:
    {
      struct bil_ivd* bil = (struct bil_ivd*) _buf;

      _sez_stamp  = _sez_da_stamp;
      _let_stamp  = _let_da_stamp;
      _numr_stamp = _numr_da_stamp;
      _num_stamp  = _num_da_stamp; 
      _classe_stampata.format("%c%c%s%2d",_sez_stamp,_let_stamp,(const char*)_numr_stamp,_num_stamp);
    
      if ( (_buf = _sort->retrieve()) != NULL)
      { 
        bil = (struct bil_ivd*) _buf;
        _sez_da_stamp  = bil->sez;
        _let_da_stamp  = bil->let;
        _numr_da_stamp = bil->numr;
        _numr_da_stamp.ltrim();
        _num_da_stamp  = atoi(bil->num);
        _gruppo        = atoi(bil->gruppo);
        _conto         = atoi(bil->conto);
        _sottoc        = atol(bil->sottoc); 
        _classe_da_stampare.format("%c%c%s%2d",_sez_da_stamp,_let_da_stamp,(const char*)_numr_da_stamp,_num_da_stamp);
      
        //set_auto_ff(FALSE);
      
        return REPEAT_PAGE; 
      }
    }  
    break;
    case con_ana_bil:
    {                    
      TRectype rec (LF_PCON);

      _codcbl_stamp  = _codcbl_da_stamp;
    
      if ( (_buf = _sort->retrieve()) != NULL)
      { 
        rec = _buf;
        _codcbl_da_stamp = rec.get(PCN_CODCBL);
        _gruppo          = rec.get_int(PCN_GRUPPO);
        _conto           = rec.get_int(PCN_CONTO);
        _sottoc          = rec.get_long(PCN_SOTTOCONTO); 
  
      return REPEAT_PAGE;
    }
    break;  
  }
  default:
    break;
  }
  return NEXT_PAGE;
}

void CG1100_application::set_page(int file,int counter)
{   
  //intesta (_tipo_stampa);
  switch (_tipo_stampa) 
  {
    case con_IV_direttiva: 
    { 
      reset_print();
      _i = 1;
     
      if (_sez_da_stamp != _sez_stamp)
        set_con_IV ();
      else
        if (_buf != NULL)
          set_con_IV();
    }
    break;
    case con_ana_bil:
    {      
      reset_print();
      _i = 1;
     
      if (_codcbl_da_stamp != _codcbl_stamp)
        set_con_ana ();
      else
        if (_buf != NULL)
          set_con_ana();
    }
    break;
    case senza_IV_direttiva:
      set_senza_IV_ana();
    break;
    case senza_ana_bil:
      set_senza_IV_ana();
    break;
    default:
    break;
  }
}     

//////////////////////////////////////////////////////////////
// Crea sort se necessario e seleziona il cursore opportuno
//////////////////////////////////////////////////////////////
void CG1100_application::do_sort()
{ 
  if (_tipo_stampa == con_IV_direttiva)
  {
    char    sez_conto,let_conto;
    TString numr_conto;
    int     num_conto;
    bool    classe_conto = FALSE;
    
    _sort->init();
    select_cursor (_cur_c1);

    TCursor * cursor = current_cursor();
    TRectype & rec = cursor->curr();

    long last =  cursor->items();   
    
    TProgind prg (last, "Elaborazione Piano dei Conti... Prego attendere", FALSE, TRUE, 30);

    for ( *cursor = 0; cursor->pos() < last; ++(*cursor) )
    {
      prg.addstatus(1);
        
      int  g = rec.get_int(PCN_GRUPPO);
      int  c = rec.get_int(PCN_CONTO);
      long s = rec.get_int(PCN_SOTTOCONTO);
      
      if (g != 0 && c == 0 && s == 0) continue;

      char    sez      = rec.get_char(PCN_SEZIVD);       
      char    let      = rec.get_char(PCN_LETTIVD); 
      TString numr     = rec.get     (PCN_NUMRIVD);
      int     num      = rec.get_int (PCN_NUMIVD); 
      TString descr    = rec.get     (PCN_DESCR);
      char    sez_opp  = rec.get_char(PCN_SEZIVDOPP);
      char    let_opp  = rec.get_char(PCN_LETTIVDOPP);
      TString numr_opp = rec.get     (PCN_NUMRIVDOPP);
      int     num_opp  = rec.get_int (PCN_NUMIVDOPP);       
      
      if ((g != 0) && (c != 0) && (s == 0))
      {
        if (sez != '\0' && sez != '0')
        {
          sez_conto  = sez;
          
          if (let != '\0')
            let_conto  = let;
          else
            if ((sez == '1')||(sez == '2'))  
              let_conto  = 'Z';  
            else
              let_conto = let;
          
          numr_conto   = numr;
          num_conto    = num;
          classe_conto = TRUE;  
          riempi_record(sez_conto,let_conto,numr_conto,num_conto,g,c,s,descr,sez_opp,let_opp,numr_opp,num_opp);
        }
        else
          classe_conto      = FALSE; 
      }
      
      if ((g != 0) && (c != 0) && (s != 0))
      {       
        if (classe_conto)  
          riempi_record(sez_conto,let_conto,numr_conto,num_conto,g,c,s,descr,sez_opp,let_opp,numr_opp,num_opp);
        else
        { 
          if (sez != '\0' && sez != '0')
          {
            if (let == '\0')
              if ((sez == '1')||(sez == '2'))  
                let = 'Z';
            
            riempi_record(sez,let,numr,num,g,c,s,descr,sez_opp,let_opp,numr_opp,num_opp);   
          }
        }
      }
    }
    
    _sort->endsort();     
    select_cursor (_cur_c2);
  }
  
  if (_tipo_stampa == con_ana_bil)
  {        
    bool livello_conto = FALSE;
       
    _sort->init();

    select_cursor (_cur_c1);

    TCursor * cursor = current_cursor();
    TRectype & rec = cursor->curr();

    long last =  cursor->items();
    
    TProgind prg (last, "Elaborazione Piano dei Conti... Prego attendere", FALSE, TRUE, 30);
    
    TString c1(12);
    
    int conto_p = -1;
    
    for ( *cursor = 0; cursor->pos() < last; ++(*cursor) )
    { 
      prg.addstatus(1);
                                  
      int  gruppo = rec.get_int (PCN_GRUPPO);
      int  conto  = rec.get_int (PCN_CONTO);
      long sottoc = rec.get_long(PCN_SOTTOCONTO);
      
      if (livello_conto && (conto != conto_p) )
      {
        c1 = "";
        livello_conto = FALSE;
      }
        
      conto_p = conto;
        
      if (conto == 0)                // Si tratta di un gruppo
        c1 = rec.get(PCN_CODCBL);
      else
        if (sottoc == 0)             // Si tratta di un conto
        { 
          if (rec.get(PCN_CODCBL).empty())
            rec.put(PCN_CODCBL, c1);  
          else
          {
            c1 = rec.get(PCN_CODCBL);
            livello_conto = TRUE;
          }
        }
        else                         // Si tratta di un sottoconto
          if (rec.get(PCN_CODCBL).empty())
            rec.put(PCN_CODCBL, c1);
      
      if (rec.get(PCN_CODCBL).not_empty() )
        _sort->sort (rec.string());
    }
    
    _sort->endsort();
    select_cursor (_cur_c2);
  }
}

void CG1100_application::cancella(int g, int c, long s)
{
  _tpcon->setkey(1);
  _tpcon->zero();
  _tpcon->put(PCN_GRUPPO,     g);
  _tpcon->put(PCN_CONTO,      c);
  _tpcon->put(PCN_SOTTOCONTO, s);
  if (_tpcon->read() == NOERR)
    _tpcon->remove();
}

void CG1100_application::prepara_pcon_temp()
{
  TLocalisamfile pcon (LF_PCON);
  TRectype       rec  (LF_PCON);
  bool gruppo_riclassificato = FALSE;
  bool conto_riclassificato  = FALSE;
  
  int g_prec = -1;
  int c_prec = -1;      
  
  long items = pcon.items();
  
  TProgind prog (items,"Elaborazione Piano dei Conti... Prego attendere", FALSE, TRUE, 30);
  
  for (pcon.first(); !pcon.eof(); pcon.next())
  {
    prog.addstatus(1);
    
    int  g = pcon.get_int (PCN_GRUPPO);
    int  c = pcon.get_int (PCN_CONTO);
    long s = pcon.get_long(PCN_SOTTOCONTO);
    
    if (gruppo_riclassificato && g == g_prec) 
      continue;
    else
      gruppo_riclassificato = FALSE;
    
    if (conto_riclassificato && (g == g_prec && c == c_prec) )
      continue;
    else
      conto_riclassificato = FALSE;
    
    TString16 codcbl = pcon.get(PCN_CODCBL);
    
    if (c == 0)      // Se si tratta di un gruppo    
    {
      if (codcbl.empty())
      {
        rec = pcon.curr();
        
        _tpcon->zero();
        _tpcon->curr() = rec;
        _tpcon->write();
      }  
      else
        gruppo_riclassificato = TRUE;
    }
    else
      if (s == 0)    // Se si tratta di un conto
      {
        if (codcbl.empty())
        {
          rec = pcon.curr();
          
          _tpcon->zero();
          _tpcon->curr() = rec;
          _tpcon->write();
        }                
        else 
        {
          int gruppo = pcon.get_int(PCN_GRUPPO);
          
          cancella(gruppo,0,0);   // Cancella l'eventuale gruppo
          
          conto_riclassificato = TRUE;
        }
      }
      else           // Se si tratta di un sottoconto
      {
        if (codcbl.empty())
        {
          rec = pcon.curr();
          
          _tpcon->zero();
          _tpcon->curr() = rec;
          _tpcon->write();
        }                
        else 
        {
          int gruppo = pcon.get_int(PCN_GRUPPO);
          int conto  = pcon.get_int(PCN_CONTO);
          
          cancella(gruppo,0,0);      // Cancella l'eventuale gruppo
          cancella(gruppo,conto,0);  // Cancella l'eventuale conto
        }
      }
  }
  select_cursor(_cur_c3);  // Seleziono il cursore definito sul piano dei conti temporaneo
  _tpcon->first();
}

bool CG1100_application::preprocess_print (int file,int counter)
{
  switch (_tipo_stampa)
  {
    case completa:
    case completa_bil:
    case senza_IV_direttiva:
    break;
    case con_IV_direttiva:
    { 
      struct bil_ivd* bil = (struct bil_ivd*) _buf;
    
      if ((_buf = _sort->retrieve()) != NULL)
      {
        bil = (struct bil_ivd*) _buf;
        _sez_da_stamp  = bil->sez;
        _let_da_stamp  = bil->let;
        _numr_da_stamp = bil->numr;
        _numr_da_stamp.ltrim();
        _num_da_stamp  = atoi(bil->num);
        _gruppo        = atoi(bil->gruppo);
        _conto         = atoi(bil->conto);
        _sottoc        = atol(bil->sottoc); 
        _classe_da_stampare.format("%c%c%s%2d",_sez_da_stamp,_let_da_stamp,(const char*)_numr_da_stamp,_num_da_stamp);
      
        return TRUE;
      }
      else
        return FALSE; 
    }
    break;
    case con_ana_bil: 
    { 
      TRectype rec (LF_PCON);
    
      if ((_buf = _sort->retrieve()) != NULL)
      {
        rec = _buf;
        _codcbl_da_stamp  = rec.get(PCN_CODCBL);
        _gruppo           = rec.get_int(PCN_GRUPPO);
        _conto            = rec.get_int(PCN_CONTO);
        _sottoc           = rec.get_long(PCN_SOTTOCONTO); 
      
        return TRUE;
      }
      else
        return FALSE;
    }        
    break;    
    case senza_ana_bil:
    break;
    default:
    break;
  }
  return TRUE;
}

void CG1100_application::set_con_IV()
{                                                
  struct bil_ivd* bil = (struct bil_ivd*) _buf;
  
  TString descrizione,descr;
  char    sez_opp,let_opp;
  int     num_opp,numr_opp;
  bool stampa_classe = TRUE;    
  int     numr       = atoi(_numr_da_stamp);
  TString numrom     = itor(numr); 
  
  sez_opp  = bil->sez_opp;
  let_opp  = bil->let_opp;
  numr_opp = atoi(bil->numr_opp);
  TString  numrom_opp = itor(numr_opp);
  num_opp  = bil->num_opp;
  
  descrizione  = descrizione_numero(_sez_da_stamp,_let_da_stamp,numr,_num_da_stamp);
  descr    = bil->descr;
  
  //Se la classe prelevata dal record corrente del sort e' diversa dalla classe
  //prelevata dal record precedente, allora stampo la nuova classe con i relativi
  //sottoconti. In caso contrario continuo a stampare solo i sottoconti.
  
  if (_classe_da_stampare != _classe_stampata)
  {
    if (_sez_da_stamp != _sez_stamp)
    {
      if ((_sez_da_stamp == '1')&&(_let_da_stamp == 'Z'))
      {
        char app = ' ';
        set_row (_i++,"@0g%c", app);   
        set_row (_i++,"@0gCONTI D' ORDINE ATTIVI");
        set_row (_i++,"@0g%c", app);
        stampa_classe = FALSE;
      } 
      else
        if ((_sez_da_stamp == '1')&&(_let_da_stamp != 'Z'))
        {
          char app = ' ';
          set_row (_i++,"@0g%c", app);   
          set_row (_i++,"@0gATTIVO");
          set_row (_i++,"@0g%c", app);
        }
      
      if ((_sez_da_stamp == '2')&&(_let_da_stamp == 'Z'))
      {
        char app = ' ';
        set_row(_i++,"@0g%c", app); 
        set_row (_i++,"@0gCONTI D' ORDINE PASSIVI");
        set_row(_i++,"@0g%c", app); 
        stampa_classe = FALSE;
      } 
      else
        if ((_sez_da_stamp == '2')&&(_let_da_stamp != 'Z'))
        {
          char app = ' ';
          set_row(_i++,"@0g%c", app); 
          set_row (_i++,"@0gPASSIVO");
          set_row(_i++,"@0g%c", app); 
        }
      
      if (_sez_da_stamp == '5')
      {
        char app = ' ';
        set_row(_i++,"@0g%c", app); 
        set_row (_i++,"@0gCONTI D' ORDINE");
        set_row(_i++,"@0g%c", app); 
        stampa_classe = FALSE;
      }                                  
      
      if (_sez_da_stamp == '9')
      {
        char app = ' ';
        set_row(_i++,"@0g%c", app); 
        set_row (_i++,"@0gCONTO ECONOMICO");
        set_row(_i++,"@0g%c", app); 
      }
    }
    else
      if ((_let_da_stamp!=_let_stamp)&&(_sez_da_stamp==_sez_stamp))
      {
        if ((_sez_da_stamp == '1')&&(_let_da_stamp == 'Z'))
        {
          char app = ' ';
          set_row (_i++,"@0g%c", app);   
          set_row (_i++,"@0gCONTI D' ORDINE ATTIVI");
          set_row (_i++,"@0g%c", app);
          stampa_classe = FALSE;
        }
        if ((_sez_da_stamp == '2')&&(_let_da_stamp == 'Z'))
        {
          char app = ' ';
          set_row(_i++,"@0g%c", app); 
          set_row (_i++,"@0gCONTI D' ORDINE PASSIVI");
          set_row(_i++,"@0g%c", app); 
          stampa_classe = FALSE;
        }
      }
    
    if (stampa_classe)
    {
      if ((_sez_da_stamp=='1')||(_sez_da_stamp=='2')||(_sez_da_stamp== '9'))
      {      
        char app = ' ';
        set_row (_i++,"@0g%c", app);
        if (_let_da_stamp != ' ')
          set_row(_i,"@0g%c", _let_da_stamp); 

        if (_numr_da_stamp != "")
          set_row(_i,"@2g%8s", (const char*) numrom);

        if (_num_da_stamp != 0)
          set_row(_i,"@11g%2d", _num_da_stamp);   
        
        _d2 = (const char*) descrizione;
        set_row(_i,"@14g#a", &_d2);   
        //    setta_righe_descr(_descr);
      }
    }  
  }                                            
  set_row (_i,"@58g$[r]%3d$[n]", _gruppo);
  set_row (_i,"@62g$[r]%3d$[n]", _conto);
  if (_sottoc != 0)
    set_row (_i,"@66g$[r]%6ld$[n]", _sottoc);
  set_row (_i,"@73g%.40s", (const char*) descr); 

  if (sez_opp != '0')
  {
    set_row (_i,"@116g%c", sez_opp); 
    
    if (let_opp != '\0')
      set_row (_i,"@118g%c", let_opp);
    
    if (numr_opp != 0)
      set_row (_i,"@120g%8s", (const char*) numrom_opp);
    
    if (num_opp != 0)
      set_row (_i++,"@129g%2d", num_opp);
  }
  else
    _i++;
}

/*void CG1100_application::setta_righe_descr(TParagraph_string* str)
  {
  const char* r;

  while ((r = str->get()) != NULL)
  { 
  set_row (_i,"@14g%s",r);
  _i++;           
  }  
  _i--;
  } */

void CG1100_application::set_senza_IV_ana()
{  
  int i;

  TRectype & rec = current_cursor()->curr();      

  int  gruppo = rec.get_int (PCN_GRUPPO);
  int  conto  = rec.get_int (PCN_CONTO);
  long sottoc = rec.get_long(PCN_SOTTOCONTO); 
  
  reset_print ();
  i = 1;
  
  if (_prima_volta)
  {
    _g_prec = gruppo;
    _c_prec = conto;
    _prima_volta = FALSE;
  }
  
  if (sottoc == 0L) // Se si tratta di un conto  
  {
    if (gruppo != _g_prec)
      _stampa_riga_vuota = TRUE;
  }
  else
  {   
    if (gruppo != _g_prec || conto != _c_prec)
      _stampa_riga_vuota = TRUE;
  }

  if (_stampa_riga_vuota)
  {                            
    char app = ' ';
    set_row (i++,"@0g%c", app);
    _stampa_riga_vuota = FALSE;
  }
  
  set_row (i, "$[r]@pn$[n] $[r]@pn$[n] $[r]@pn$[n]",
           FLD(LF_PCON, PCN_GRUPPO, "###"), FLD(LF_PCON,PCN_CONTO, "###"),
           FLD(LF_PCON, PCN_SOTTOCONTO, "######"));
  
  
  set_row (i, "@16g@50s", FLD(LF_PCON,PCN_DESCR) );
  
  if (conto != 0 && sottoc == 0l)
  {
    set_row (i, "@76g@pn", FLD(LF_PCON, PCN_INDBIL, "#") );
    set_row (i, "@82g@1s", FLD(LF_PCON, PCN_TMCF) );
    set_row (i, "@89g@f",  FLD(LF_PCON, PCN_STSOTTBIL) );
    set_row (i, "@98g@f",  FLD(LF_PCON, PCN_COMPENS) );  
    set_row (i, "@121g@f", FLD(LF_PCON, PCN_STSOTTAB) );
  }
  if (sottoc != 0l) 
  {                                                       
    char tipospric = rec.get_char(PCN_TIPOSPRIC); 
    if (tipospric == '\0') tipospric = '0'; 
    set_row (i, "@104g@1n", FLD(LF_PCON, PCN_RICSER) );
    set_row (i, "@109g%c", tipospric);
    set_row (i, "@115g@1s", FLD(LF_PCON, PCN_SEZSALDI) );
    set_row (i, "@129g@f",  FLD(LF_PCON, PCN_STSOTTAB) );
  }
}

void CG1100_application::set_con_ana()
{
  TRectype rec (LF_PCON); 
  TString16 val;
  
  rec = _buf;
  
  TString descrizione,descr;
  bool stampa_codcbl = TRUE;    
  
  TString codcbl = rec.get(PCN_CODCBL);
  int     gruppo = rec.get_int (PCN_GRUPPO);
  int     conto  = rec.get_int (PCN_CONTO);
  long    sottoc = rec.get_long(PCN_SOTTOCONTO);
  bool    stsobi = rec.get_bool(PCN_STSOTTAB);
  if (stsobi)
    val = "Si";
  else
    val = "No";
  
  descrizione  = descrizione_codcbl(codcbl);
  descr        = rec.get(PCN_DESCR);

  char app = ' ';
  set_row (_i++,"@0g%c", app);
  
  if (_codcbl_da_stamp != _codcbl_stamp)
  {
    set_row (_i,"@0g%10s", (const char*) _codcbl_da_stamp);
    set_row (_i,"@11g%s",  (const char*) descrizione);   
  }                                            

  set_row (_i,"@62g$[r]%3d$[n]", _gruppo);
  
  if (_conto != 0)
    set_row (_i,"@66g$[r]%3d$[n]", _conto);
  
  if (_sottoc != 0)
    set_row (_i,"@70g$[r]%6ld$[n]", _sottoc);
  
  if (_gruppo > 99 || _conto > 99)
    set_row(_i,"@76g*");
      
  set_row (_i,"@78g%.40s", (const char*) descr); 

  if (conto != 0 && sottoc == 0l)
    set_row (_i, "@121g%s", (const char*) val);
  else
    if (sottoc != 0l) 
      set_row (_i, "@129g%s", (const char*) val);

  _i++;
}

/*********
void CG1100_application::set_senza_ana()
{
  reset_row (1);

  set_row (1, "$[r]@pn$[n] $[r]@pn$[n] $[r]@pn$[n]",
           FLD(LF_PCON, PCN_GRUPPO, "###"), FLD(LF_PCON,PCN_CONTO, "###"),
           FLD(LF_PCON, PCN_SOTTOCONTO, "######"));
  
  set_row (1, "@16g@50s", FLD(LF_PCON,PCN_DESCR) );

  set_row (1, "@69g@1s", FLD(LF_PCON, PCN_SEZIVD) );
  set_row (1, "@71g@1s", FLD(LF_PCON, PCN_LETTIVD) );
  set_row (1, "@73g#-8t", &_clivd);
  set_row (1, "@82g@pn", FLD(LF_PCON, PCN_NUMIVD, "@@") );

  set_row (1, "@87g@pn", FLD(LF_PCON, PCN_INDBIL, "#") );
  set_row (1, "@92g@1s", FLD(LF_PCON, PCN_TMCF) );
  set_row (1, "@99g@f", FLD(LF_PCON, PCN_STSOTTBIL) );
  set_row (1, "@107g@f", FLD(LF_PCON, PCN_COMPENS) );
  set_row (1, "@120g@1s", FLD(LF_PCON, PCN_SEZSALDI) );
}
*********/

void CG1100_application::set_completa()
{
  TRectype&  rec = current_cursor()->curr();  
  char       sezione;
  int        i;
  
  int  gruppo = rec.get_int (PCN_GRUPPO);
  int  conto  = rec.get_int (PCN_CONTO);
  long sottoc = rec.get_long(PCN_SOTTOCONTO);      
  sezione     = rec.get_char(PCN_SEZIVD);    
  TString desc = rec.get(PCN_DESCR);
  
  if (_prima_volta)      
  {
    _s_prec = 0;
    _prima_volta = FALSE;
  }
  
  if (sottoc != 0l && _s_prec != 0l)                                      
    i = 1;
  else
  {
    i = 1;
    char app = ' ';
    set_row (i++,"@0g%c", app);
  }                            
  
  reset_print ();

  set_row (i, "$[r]@pn$[n] $[r]@pn$[n] $[r]@pn$[n]",
           FLD(LF_PCON, PCN_GRUPPO, "###"), FLD(LF_PCON,PCN_CONTO, "###"),
           FLD(LF_PCON, PCN_SOTTOCONTO, "######"));
  
  
  set_row (i, "@16g%.40s", (const char*) desc);         //  ???
  
  if (_tipo_stampa == completa)
  {
    if (sezione != '0' && sezione != '9')                                  
      set_row (i, "@58g@1s", FLD(LF_PCON, PCN_SEZIVD) );
    set_row (i, "@60g@1s", FLD(LF_PCON, PCN_LETTIVD) );
    set_row (i, "@62g#-8t", &_clivd );
    set_row (i, "@71g@pn", FLD(LF_PCON, PCN_NUMIVD, "@@") );
  }
  else
    if (_tipo_stampa == completa_bil)
      set_row (i, "@60g@10s", FLD(LF_PCON, PCN_CODCBL) );
  
  if (conto != 0 && sottoc == 0l)
  {
    set_row (i, "@76g@pn", FLD(LF_PCON, PCN_INDBIL, "#") );
    set_row (i, "@82g@1s", FLD(LF_PCON, PCN_TMCF) );
    set_row (i, "@89g@f", FLD(LF_PCON, PCN_STSOTTBIL) );
    set_row (i, "@98g@f", FLD(LF_PCON, PCN_COMPENS) );  
    set_row (i, "@121g@f", FLD(LF_PCON, PCN_STSOTTAB) );
  }
  if (sottoc != 0l) 
  {                                                       
    char tipospric = rec.get_char(PCN_TIPOSPRIC); 
    if (tipospric == '\0') tipospric = '0'; 
    set_row (i, "@104g@1n", FLD(LF_PCON, PCN_RICSER) );
    set_row (i, "@109g%c", tipospric);
    set_row (i, "@114g@1s", FLD(LF_PCON, PCN_SEZSALDI) );
    set_row (i, "@129g@f",  FLD(LF_PCON, PCN_STSOTTAB) );
  }
  _s_prec = sottoc;
}

bool CG1100_application::elabora_riga()
{
  TRectype& curr_rec = *_rec;

  switch (_tipo_stampa)
  {
  case completa:
  case senza_IV_direttiva:
    curr_rec = current_cursor()->curr(); 
    break;
  case senza_ana_bil:
  {
    curr_rec = current_cursor()->curr(); 
    int conto  = curr_rec.get_int(PCN_CONTO);
    long sottoc = curr_rec.get_long(PCN_SOTTOCONTO);
    if (conto != 0)
    {
      // se e' un sottoconto stampo sotttab in 127
      if (sottoc != 0)
      {
        char tipospric = curr_rec.get_char(PCN_TIPOSPRIC); 
        if (tipospric == '\0') tipospric = '0';        
        set_row (1, "@114g%c", tipospric);
        set_row (1, "@127g@f", FLD(LF_PCON, PCN_STSOTTAB));
        set_row (1, "@117g  ");
      }
      else
        // se e' un conto stampo sotttab in 124
      {
        set_row (1, "@117g@f", FLD(LF_PCON, PCN_STSOTTAB));
        set_row (1, "@127g  ");
      }
    }
    break;
  }
  case con_ana_bil:
  case con_IV_direttiva:
    curr_rec = *_rec;
    break;
  default:
    break;
  }

  // Gestione salto pagina
  if (_tipo_stampa == con_ana_bil) // || _tipo_stampa == con_IV_direttiva)
    return FALSE;

  int new_gruppo = curr_rec.get_int(PCN_GRUPPO);

  if (_salto_pag && new_gruppo != _old_gruppo)
  {
    const bool salta = _old_gruppo > 0;
    _old_gruppo = new_gruppo;
    return salta;
  }
  return FALSE;
}

int CG1100_application::leggo_sottoc(int gruppo,int conto,long sottoc)
{                
  TLocalisamfile pconti (LF_PCON,FALSE);
  char sez;
  int  gr,co;
  int  esito = 0;
  bool esiste_conto_classificato     = FALSE;
  bool esiste_conto_non_classificato = FALSE;
  
  pconti.zero();
  pconti.put(PCN_GRUPPO,     gruppo);
  pconti.put(PCN_CONTO,      conto);
  pconti.put(PCN_SOTTOCONTO, sottoc);
  
  for (pconti.read(); !pconti.eof() ;pconti.next())
  {              
    gr = pconti.get_int (PCN_GRUPPO);
    co = pconti.get_int (PCN_CONTO);

    if (gruppo != gr || conto != co) break;
    
    sez = pconti.get_char(PCN_SEZIVD);
    
    if (sez != '0') 
      esiste_conto_classificato = TRUE;
    
    if (sez == '0')
      esiste_conto_non_classificato = TRUE;              
  }
  
  if (!esiste_conto_classificato && esiste_conto_non_classificato)
    esito = 0;
  
  if (esiste_conto_classificato && esiste_conto_non_classificato)
    esito = 1;          
  
  if (esiste_conto_classificato && !esiste_conto_non_classificato)
    esito = 2;
  
  return esito;
}              

bool CG1100_application::preprocess_page(int file,int counter)
{
  static int c1 = 0;
  static TString16 a1;
  char   sez;
  TString16 codcbl;                                   

  if (_tipo_stampa == completa || _tipo_stampa == completa_bil)
    set_completa();
  
  if (_tipo_stampa == senza_IV_direttiva)
  { 
    if (file == LF_PCON)
    {
      TRectype& rec = current_cursor()->curr();
      int  gruppo = rec.get_int (PCN_GRUPPO);
      int  conto  = rec.get_int (PCN_CONTO);
      long sottoc = rec.get_long(PCN_SOTTOCONTO);  
      
      force_setpage();
      
      if (conto == 0) return FALSE; //Scarto i gruppi
       
      if (sottoc == 0L) // Se si tratta di un conto
      { 
        sez = rec.get_char(PCN_SEZIVD);

        if (sez == '0')
        {                           
          _sottoc_classificato = leggo_sottoc(gruppo,conto,sottoc);  
          if (_sottoc_classificato == 0)
            _conto_classificato = TRUE;
          else
            if (_sottoc_classificato == 1)
            {  
              _conto_classificato  = FALSE;
              return FALSE;
            }   
            else
              if (_sottoc_classificato == 2)
              {
                _conto_classificato = TRUE;
                return FALSE;
              }
        }
        else                        
        {
          _conto_classificato = TRUE;
          return FALSE;                
        }
      }
      else                              // Se si tratta di un sottoconto
      {   
        if (!_conto_classificato) 
        {
          char sezione = rec.get_char(PCN_SEZIVD);
          
          if (sezione != '0')
            return FALSE;
        }
        else
          return FALSE;    
      }
      _g_prec = gruppo;
      _c_prec = conto; 
    }
  }    
  
  if (_tipo_stampa == senza_ana_bil)
  {
    if (file == LF_PCON)
    {
      TRectype& rec = current_cursor()->curr();
      int  gruppo = rec.get_int (PCN_GRUPPO);
      int  conto  = rec.get_int (PCN_CONTO);
      long sottoc = rec.get_long(PCN_SOTTOCONTO);  
      
      force_setpage();

      if (gruppo != _g_prec)
      {
        _stampa_g = TRUE; 
        _stampa_c = TRUE;
      }
        
      if ( (gruppo != _g_prec || conto != _c_prec) && _stampa_g)
        _stampa_c = TRUE;
   
      _g_prec = gruppo;  
      _c_prec = conto;
      
      if (conto == 0)      // Si tratta di un gruppo
      {
        _stampa_g = FALSE;
        _stampa_c = FALSE;
        return TRUE;
      }
      
      if (sottoc == 0)     // Si tratta di un conto
      { 
        if (_stampa_g)
        {
          _stampa_c = FALSE;
          return TRUE;
        }
        else
          return FALSE;
      }             
        
      if (sottoc != 0)     // Si tratta di un sottoconto
      {
        if (_stampa_c)
          return TRUE;
        else
          return FALSE;
      }
    }
  }    

  if (elabora_riga())
    printer().formfeed();

  const int c3 = atoi(_rec->get(PCN_NUMRIVD));
  const int o3 = atoi(_rec->get(PCN_NUMRIVDOPP));

  _clivd = itor(c3);
  _clivdo = itor(o3);

  return TRUE;
}

bool CG1100_application::set_print(int)
{
  KEY   tasto;

  _old_gruppo = 0;
  tasto = _msk->run();

  if (tasto == K_ENTER)
  {
    _tipo_stampa = (stampe)_msk->get_int(F_SCELTA_STAMPA);
    _salto_pag   = _msk->get_bool (F_SALTO_PAGINA);
    _data_stampa = _msk->get      (F_DATA_STAMPA);

    // scegli_cur();
    enable_link("Collegamento Piano dei conti : ", 'r');
    set_multiple_link(TRUE);
    
    _sez_stamp  = ' ';
    _let_stamp  = ' ';
    _numr_stamp = "";
    _num_stamp  = 0; 
    _classe_stampata = "";               
    
    _resetta_righe_stampa = TRUE;
    
    reset_footer();
    if (_tipo_stampa == con_ana_bil)
      set_footer(2,"* Conti collegati ma non trasferibili");
    else
      set_footer(2,"");
          
    if (_tipo_stampa == senza_IV_direttiva)
    {
      _conto_classificato  = TRUE;
      _sottoc_classificato = 0;
      _stampa_riga_vuota = FALSE;
      _prima_volta = TRUE;  
    }
    
    switch (_tipo_stampa) 
    {
    case completa: 
    case completa_bil:
    case senza_IV_direttiva:
      select_cursor(_cur_c1);
      break;
    case senza_ana_bil: 
    { 
      _tpcon = new TIsamtempfile (LF_PCON, "ab", TRUE);
      _relt  = new TRelation (_tpcon);
      TCursor *tcursor = new TCursor (_relt);
  
      _cur_c3 = add_cursor (tcursor);
 
      select_cursor(_cur_c1);
      prepara_pcon_temp(); 
      break;
    }
    case con_IV_direttiva:
    case con_ana_bil:     
      init_sort();
      do_sort();
      select_cursor (_cur_c2); break;
    default:
      break;
    }
    //init_sort();
    
    intesta (_tipo_stampa);
    
    printer().footerlen(5);
    
    return TRUE;
  }
  return FALSE;
}

void CG1100_application::intesta (stampe tipo)
{
  int soh = 1;       // riga d'inizio dell'intestazione
  const long firm = get_firm();

  reset_header ();
  TLocalisamfile ditte(LF_NDITTE);
  ditte.zero();
  ditte.put(NDT_CODDITTA, firm);
  ditte.read();
  if (ditte.bad()) ditte.zero();

  TString s(132);
  s = ditte.get(NDT_RAGSOC);    
  TString data = _data_stampa.string();

  set_header (soh++, "Ditta : %ld %s@110gData@115g%s  Pag. @#", firm, (const char *) s, (const char*) data);


  set_header (soh,"@0gPIANO DEI CONTI");

  switch (tipo)
  {
  case completa:  
    set_header (soh++, "@20gStampa completa per IV direttiva");
    s.fill('-');
    set_header (soh++, (const char *) s);
    set_header (soh++, "Conto @59gSez. Classe@75gTipo@86gNo Dettaglio@104gT@107gSpesa@118gDet.alleg.bil.");
    set_header (soh++, "Sottoconto @16gDescrizione@61gIV  dir.@75gConto@81gC/F@86gBilancio@97gComp.@104gA@107gRicavo@114gSez@118gSot.con * Mov.");
    break;

  case con_IV_direttiva:
    set_header (soh++, "@20gStampa conti riclassificati per IV direttiva");
    s.fill('-');
    set_header (soh++, (const char *) s);
    set_header (soh++, "@58gCodici Piano@116gSez. e Classe");
    set_header (soh++, "Classe@14gDescrizione@58gdei Conti @73gDescrizione@116gdi segno opposto");

    break;

  case senza_IV_direttiva:                          
    set_header (soh++, "@20gStampa conti non collegati per IV direttiva");
    s.fill('-');
    set_header (soh++, (const char *) s);
    set_header (soh++, "Conto @75gTipo@86gNo Dettaglio@104gT@107gSpesa@118gDet.alleg.bil.");
    set_header (soh++, "Sottoconto @16gDescrizione@75gConto@81gC/F@86gBilancio@97gComp.@104gA@107gRicavo@114gSez@118gSot.con * Mov.");
    break;

  case completa_bil:
    set_header (soh++, "@20gStampa completa per analisi di bilancio");     
    s.fill('-');                         
    set_header (soh++, (const char *) s);    
    set_header (soh++, "Conto@60gCod.tabella@75gTipo@86gNo Dettaglio@104gT@107gSpesa@118gDet.alleg.bil.");
    set_header (soh++, "Sottoconto @16gDescrizione@60gAnalis.bil.@75gConto@81gC/F@86gBilancio@97gComp.@104gA@107gRicavo@114gSez@118gSot.con * Mov.");
    break;
    
  case con_ana_bil:
    set_header (soh++, "@20gStampa conti riclassificati per analisi di bilancio");    
    s.fill('-');
    set_header (soh++, (const char *) s);
    set_header (soh++, "Codice @62gCodici Piano@118gDet.alleg.bil.");
    set_header (soh++, "Tabella@11gDescrizione@62gdei Conti @78gDescrizione@118gSot.con * Mov.");
    break;

  case senza_ana_bil:
    set_header (soh++, "@20gStampa conti non collegati per analisi di bilancio");    
    s.fill('-');
    set_header (soh++, (const char *) s);
    set_header (soh++, "Conto@74gTipo@86gNo Dettaglio@107gSpesa@114gT@116gDett.alleg.bil.");
    set_header (soh++, "Sottoconto@16gDescrizione@74gConto@81gC/F@86gBilancio@96gCompensaz.@107gRicavo@114gA@116gSot.con * Movim.");
    break;

  default:
    break;
  }

  set_header (soh++,(const char*)s);
  set_header (soh, "");

}

const char* CG1100_application::descrizione_numero(char sezione, char lettera, int numr, int numero)
{
  TTable& tabivd = *_tab;
  TString dep,dep2;

  tabivd.zero();   
  if (numr == 0 && numero == 0)
    dep = format("%c%c",sezione,lettera);
  else                        
    if (numero == 0)
    {
      if (numr != 0)
        dep = format("%1c%1c%04d",sezione, lettera, numr);
      else
        dep = format("%c%c    ",sezione,lettera);
    }
    else                                         
    {
      if (numr != 0)
        dep = format("%1c%1c%04d%02d",sezione, lettera, numr,numero);
      else
        dep = format("%c%c    %02d",sezione,lettera,numero);
    }
  
  tabivd.put("CODTAB", dep);
  tabivd.read();   
  dep2 = tabivd.get("CODTAB");
  if (dep == dep2)
    tmp = tabivd.get("S0");
  else
    tmp = "";
  return tmp;
}     

const char* CG1100_application::descrizione_codcbl(TString& codcbl)
{
  TLocalisamfile abpcon (LF_ABPCON);

  abpcon.setkey(1);
  abpcon.zero();   
  abpcon.put("CODCBL", codcbl);
  if (abpcon.read() == NOERR)   
    tmp = abpcon.get("DESCRIZ");
  else
    tmp = "";
  return tmp;
}     

bool CG1100_application::user_create()
{
  _rel = new TRelation (LF_PCON);
  _tab = new TTable(TAB_IVD);
  _msk = new TMask ("cg1100a") ;
  
  _pcon = new TLocalisamfile (LF_PCON);

  TCursor *cursor = new TCursor (_rel);

  _cur_c1 = add_cursor (cursor);
  
//  _tpcon = new TIsamtempfile (LF_PCON, "ab", TRUE);
//  _relt  = new TRelation (_tpcon);
//  TCursor *tcursor = new TCursor (_relt);
  
//  _cur_c3 = add_cursor (tcursor);
  
  _rec = new TRectype (cursor->curr());  

  _pcont_reclen = _rec->len();
  _sort = new TSort(_pcont_reclen);

  _cur_c2 = add_cursor (NULL);

  add_file(LF_PCON);             

  //set_print_zero();
  
  _tipo_stampa = completa;
  _salto_pag   = FALSE;
  _bil  = new bil_ivd;
  _sort = new TSort();
  return TRUE;
}

bool CG1100_application::user_destroy()
{
  delete _rel;   
  delete _tab;                         
  delete _pcon;
  //delete _tpcon;
  delete _msk;
  delete _rec;                      
  //  delete _descr;
  delete _bil;
  delete _sort;
  return TRUE;
}

int cg1100(int argc, char* argv[])
{
  CG1100_application a;
  a.run(argc, argv, "Stampa Piano dei Conti");
  return 0;
}
