#include "77stq.h" 
#include "77stba.h"
#include "77stqab.h"
#include "77stqc.h"

// Quadro D
#define QD_FORMLEN       72
#define POS_DITTA       120
#define QD_PAGINE         4
#define QD_RIGHE_PRIMA    4
#define QD_RIGHE_SECONDA  7
#define QD_RIGHE_TERZA    7
#define QD_RIGHE_QUARTA   6
 
// 
// Lista modifiche
//
// 3.4.96 Nella stampa per Modulaser, aggiunto all'inizio un comando per settare
//      il font della stampante a 17cpi (v.riga 176)
// 

const char* get_ragsoc_anagr(char tipo, long codanagr)
{
  TLocalisamfile anagr (LF_ANAG);
              
  anagr.setkey(1);            
  anagr.zero();
  anagr.put(ANA_TIPOA,    tipo);
  anagr.put(ANA_CODANAGR, codanagr);
  if (anagr.read() == NOERR)
    __dep80 = anagr.get(ANA_RAGSOC);
  else
    __dep80 = "";
    
  return __dep80;  
}

const char* get_ragsoc(const long codditta)
{
  TLocalisamfile ndt(LF_NDITTE);
  ndt.zero();
  ndt.put("CODDITTA",(long)codditta);
  if (ndt.read() == NOERR)
    __dep80=ndt.get("RAGSOC");
  else
    __dep80="";
  return __dep80;
}

int TDicForm::prima_riga(PaginaQuadro p) const
{
  return p == PRIMA ? 9 : 8;
}

void TDicForm::set_cofi_dic(const char* cofi)
{ 
  _cofi_dic = cofi;                   
// salva il cod.dich. (serve per modulaser)  
  _codditta_dic = sogg_estinto(_codditta);  
}

/*TCursor& TDicForm::cur() 
{ 
  return *_cur; 
} */

void TDicForm::set_cursor(TCursor* cur) 
{  
  CHECK(cur, "NULL cursor in TDicForm");
  _cur = cur; 
} 

TDicForm::TDicForm(const char* form, const char* quadro) 
        : TForm(form), _quadro(quadro), _prog(NULL), _cur(NULL)
{
  _can_print_tot_fis = _can_print_tot_nofis = FALSE;
  _GiaStampatiFis = _GiaStampatiNoFis = _GiaMessoStartDoc = FALSE;
  _GiaPosizionato = _posiziona = _modulaser = FALSE;          
  _LastDitta = _EndPrintDitta = _PaginaPosizionamento = FALSE;
  ClearFlagModulaser();
}

long TDicForm::filtra(const long codditta)
{
  TString filtr(24); 
  _codditta=codditta;
  filtr.format("CODDITTA=%ld", codditta);
  _cur->setfilter(filtr, TRUE);   
  const long items = _cur->items();
  return items;
}


bool TDicForm::InitPrint(const long codditta)
{
  _codditta = codditta;
  _RigaCorr = 0;  
  
  TPrinter& pr = printer();
  _posiziona=pr.printtype()==winprinter;
//  if (_posiziona && !_GiaPosizionato && pr.printtype() == winprinter)  
  if (_posiziona && !_GiaPosizionato && pr.printtype() == winprinter) 
  {
    posiziona();
#ifdef DBG
    if (!yesno_box("Proseguire con la stampa ?"))
      return FALSE;
#endif
  }
  
  const bool was_open = pr.isopen();
  
  set_last_page(FALSE);   
//  set_background(1, TRUE);
  set_curr_page(PRIMA);
  
  if (!was_open && !pr.open())
    return FALSE;
  do_events();

  _Items = filtra(codditta);
  
  if (_Items == 0L) // Se non ci sono record non stampa
    return FALSE;

  if (_prog) 
  {
    delete _prog;
    _prog = NULL;
  }  
  if (pr.printtype() != screenvis)
  {
    TString msg(60);
    msg.format("Elaborazione in corso ditta %ld", codditta);
    _prog = new TProgind(_Items, msg, FALSE,TRUE);
  }
  return TRUE;
}

void TDicForm::close_print()
{
  if (_prog)
  {
    delete _prog;
    _prog = NULL;
  }  
}

bool TDicForm::print(const long codditta, const long NumFis, const long NumNoFis)
{  
  bool StabilitaInesistenzaNoFis = FALSE;
  bool StabilitaInesistenzaFis = FALSE;  
  long CtrFis   = NumFis;
  long CtrNoFis = NumNoFis;
  long PtrFis = -1L, PtrNoFis=-1L;
  TPrinter& pr = printer();
    
  _CtrFisStampati = _CtrNoFisStampati = 0;
  _finite_fis = _finite_nofis = FALSE;
  _GiaStampatiFis = _GiaStampatiNoFis = FALSE;
  _EndPrintDitta = FALSE;  // Vero se stampato l'ultimo record
  bool LastRecord = FALSE; // Vero se letto l'ultimo record

  _PaginaCorrente = PRIMA;      
  
  if (!InitPrint(codditta))
    return FALSE;
  
  TCursor* cur = cursor();
  
  while (!_EndPrintDitta)
  {
    for (int pagina=1; pagina <= QD_PAGINE; pagina++, next_page(pr))
    {
      pr.formlen(QD_FORMLEN);             
    
      if (_PaginaCorrente == PRIMA)
      {                      
        if (_modulaser) ClearFlagModulaser();
        attiva_totali('F');

        for (int righe=0; righe < QD_RIGHE_PRIMA; righe++)
        {
// Stampa intestazione, solo sul primo foglio.
          if (!righe)    
          {
            (*cur) = PtrFis >= 0L ? PtrFis : 0L;
            stampa_testata(pr);
          }
        
          if (_finite_fis || StabilitaInesistenzaFis)
            break;
          
// La prima volta si deve posizionare sul primo record di p.f.
          if (PtrFis<0L && !StabilitaInesistenzaFis)
          {
            bool Trovato = FALSE;

            while (!Trovato)
            {
              const long ditta = cur->curr().get_long(QUD_CODDITTA);
              if (ditta != codditta)
                break;
              const char tipo = cur->curr().get(QUD_TIPOA)[0];
              if (tipo != 'G')
              {
                PtrFis = cur->pos();
                Trovato = TRUE;
                break;
              } 
              else
                ++(*cur);            
            }                                        
            StabilitaInesistenzaFis = _finite_fis = !Trovato;
          }

          if (StabilitaInesistenzaFis)
            break;
         
          (*cur) = PtrFis;
          const char tipo = cur->curr().get(QUD_TIPOA)[0];
      
          if (tipo != 'F')      
            break;
          else
          {
            CtrFis--;
            if (CtrFis == 0L) _finite_fis = TRUE;
            set_body(pr, 'F');
// La stampa e' finita se ho STAMPATO l'ultimo record
            LastRecord = cur->pos() >= _Items-1;
//            _EndPrintDitta = LastRecord;
            if (!LastRecord)
            {
              ++(*cur);
              PtrFis = cur->pos();
              LastRecord = cur->pos() >= _Items-1;
            }
          }
        }   // for righe..
        PtrFis = cur->pos();
      }

      if (_PaginaCorrente == SECONDA)
      {
// Reset del flag di pagina con posiz.      
        if (_posiziona && _PaginaPosizionamento) _PaginaPosizionamento = FALSE;
        for (int righe=0; righe < QD_RIGHE_SECONDA; righe++)
        {
          if (!righe)
            fill_page(pr, HEADER_SECONDA);
          
          if (_finite_fis || StabilitaInesistenzaFis)
            break;

          (*cur) = PtrFis;
          const char tipo = cur->curr().get(QUD_TIPOA)[0];

          if (tipo != 'F')      
            break;
          else
          {
            CtrFis--;
            if (CtrFis == 0L) _finite_fis = TRUE;
            set_body(pr, 'F');
            LastRecord = cur->pos() >= _Items-1;                    
//            _EndPrintDitta = LastRecord;
            if (!LastRecord)
            {
              ++(*cur);
              PtrFis     = cur->pos();
              LastRecord = cur->pos() >= _Items-1;          
            }
          }
        }          
        PtrFis = cur->pos();
      }

      if (_PaginaCorrente == TERZA)
      { 
        for (int righe=0; righe < QD_RIGHE_TERZA; righe++)
        {
          if (!righe)
          {
            fill_page(pr, HEADER_TERZA);
            _CtrFisStampati = 0;  // conta quelli che stampo sulla terza                    
          }

          if (_finite_fis || StabilitaInesistenzaFis)
            break;

          (*cur) = PtrFis;
          const char tipo = cur->curr().get(QUD_TIPOA)[0];

          if (tipo != 'F')      
            break;
          else
          {
            CtrFis--;                            
            if (CtrFis == 0L) _finite_fis = TRUE;          
            set_body(pr, 'F');
            LastRecord = cur->pos() >= _Items-1;                    
//            _EndPrintDitta = LastRecord;  
            _CtrFisStampati++;
            if (!LastRecord)
            {
              ++(*cur);                      
              PtrFis     = cur->pos();
              LastRecord = cur->pos() >= _Items-1;          
            }
          }
        }          
        PtrFis = cur->pos();
      }

      if (_PaginaCorrente == QUARTA)
      {  
        attiva_totali('G');
        for (int righe=0; righe < QD_RIGHE_QUARTA; righe++)
        {
          if (!righe)
            _CtrNoFisStampati = 0;

// All'inizio salta le righe in alto
          if (!righe)
            fill_page(pr, HEADER_QUARTA);

          if (_finite_nofis || StabilitaInesistenzaNoFis)
            break;

// La prima volta si deve posizionare sul primo record di p.g.
          if (PtrNoFis<0L && !StabilitaInesistenzaNoFis)
          {
            bool Trovato = FALSE;
            bool eof = FALSE;
            (*cur) = PtrFis-1 > 0L ? PtrFis-1 : 0L;  // parti dall'inizio
            while (!Trovato && !eof)
            {
              eof = cur->pos() >= _Items-1;                    
              const long ditta = cur->curr().get_long(QUD_CODDITTA);
              if (ditta != codditta)
                break;
              const char tipo = cur->curr().get(QUD_TIPOA)[0];
              if (tipo != 'F')
              {
                PtrNoFis = cur->pos();
                Trovato = TRUE;
                break;
              }
              else
                ++(*cur);            
            }                                        
            StabilitaInesistenzaNoFis = _finite_nofis = !Trovato;
          }
        
          if (StabilitaInesistenzaNoFis)
            break;
        
          (*cur) = PtrNoFis;
          const char tipo = cur->curr().get(QUD_TIPOA)[0];

          if (tipo != 'G')      
            break;
          else
          {
            CtrNoFis--;                          
            if (CtrNoFis == 0L) 
              _finite_nofis = TRUE;          
            set_body(pr, 'G'); 
            LastRecord     = cur->pos() >= _Items-1;                    
//            _EndPrintDitta = LastRecord;
            _CtrNoFisStampati++;   
            if (!LastRecord)
            {
              ++(*cur);
              PtrNoFis   = cur->pos();
              LastRecord = cur->pos() >= _Items-1;          
            }
          }
        }          
        PtrNoFis = cur->pos();
        _EndPrintDitta = _finite_fis && _finite_nofis;
      } 
      
    }  // for pagina..
  }  // while !_EndPrintDitta   
  close_print();
  return TRUE;
}


void TDicForm::ClearFlagModulaser()
{
  for (int i=0; i<=QD_PAGINE; i++)
    _GiaMessoStartPage[i] = FALSE;
}

bool TDicForm::ultima_fis()
{
  return _can_print_tot_fis && _finite_fis && !_GiaStampatiFis;   
}

bool TDicForm::ultima_nofis()
{
  return _can_print_tot_nofis && _finite_nofis && !_GiaStampatiNoFis;
}
                                   
void TDicForm::inc_curr_page()
{                      
  if (_PaginaCorrente == PRIMA)
    _PaginaCorrente = SECONDA;
  else
    if (_PaginaCorrente == SECONDA)
      _PaginaCorrente = TERZA;
    else
      if (_PaginaCorrente == TERZA)
        _PaginaCorrente = QUARTA; 
      else
        if (_PaginaCorrente == QUARTA)
          _PaginaCorrente = PRIMA;
}

const char* TDicForm::BuildModulaserStartPage()
{
  __dep16="<VK>*";
  if (_quadro=="Base")
    __dep16<<"1";
  else if (_quadro=="A")
    __dep16<<"2";
  else if (_quadro=="A1")
    __dep16<<"3";
  else if (_quadro=="A2")
    __dep16<<"4";
  else if (_quadro=="A3")
    __dep16<<"5";
  else if (_quadro=="B")
    __dep16<<"6";
  else if (_quadro=="B1")
    __dep16<<"7";
  else if (_quadro=="C")
    __dep16<<"8";
  else if (_quadro=="D")
    __dep16<<"9";
  else if (_quadro=="D1")
    __dep16<<"10";
  else if (_quadro=="E")
    __dep16<<"11";
  else if (_quadro=="E1")
    __dep16<<"12";
  else if (_quadro=="E2")
    __dep16<<"13";
  else if (_quadro=="F")
    __dep16<<"14";
  else if (_quadro=="F1")
    __dep16<<"15";
  else if (_quadro=="F2")
    __dep16<<"16";
  else if (_quadro=="G")
    __dep16<<"17";
  else if (_quadro=="G1")
    __dep16<<"18";
  else if (_quadro=="H")
    __dep16<<"19";
  else if (_quadro=="La")
    __dep16<<"20";
  else if (_quadro=="Na")
    __dep16<<"21";
  else if (_quadro=="Es")
    __dep16<<"22";

  __dep16<<"*";
  return __dep16;
}

void TDicForm::put_modulaser(TPrintrow& row, ModulaserKey Cmd, int page)
{
  TString riga(80);
  
  switch (Cmd)
  {
    case STARTDOC:
      if (!_GiaMessoStartDoc)
      {
          riga = "\xf";   // Printer escape: font 17cpi
          riga << VK_STARTDOC;
          _GiaMessoStartDoc = TRUE;
      }
      break;
    case STARTDITTA:
      {
        riga = "<VK>$";
        TString cofi(16);            
        TString ragsoc(50);        
// Legge il codice fisc.e la rag.soc. del sogg.dich. oppure della ditta corrente              
        if (_tipo_ditta == estinto)        
        {
          cofi = _cofi_dic;
          ragsoc = get_ragsoc(_codditta_dic);
        }
        else    
        {    
          cofi = cod_fis(_codditta);
          ragsoc = get_ragsoc(_codditta);  
        }
        riga << cofi;     // Cod.Fiscale     
        riga << "$00/";    // Cod.Studio/ 
        if (_tipo_ditta == estinto)        
          riga << _codditta_dic;    // Cod.Cliente        
        else
          riga << _codditta;
        riga << "$";
        riga << ragsoc;   // RagSoc
      }
      break;
    case STARTPAGE:
      riga = BuildModulaserStartPage();
      riga << page;                                     
      _GiaMessoStartPage[page] = TRUE;
      break;
    case ENDDOC:
      riga = VK_ENDDOC;
      break;      
    default:
      break;
  }        
  riga.rtrim();
  riga << '\r';
  row.put(riga);
}                  


bool TDicForm::PaginaPosizionamento() const
{
   return _PaginaPosizionamento && curr_page() == PRIMA;
}

int TDicForm::dic_form_len() const
{                       
//  if (curr_page() == PRIMA && _PaginaPosizionamento && !_GiaPosizionato) 
  if (curr_page() == PRIMA && _PaginaPosizionamento)
    return QD_FORMLEN-HEADER_PRIMA_NOPOS;
  else
    return QD_FORMLEN;
}

// Stampa "righe" righe vuote. Se righe e' -1 fa un formfeed mettendo
// il codice ditta sull'ultima riga
void TDicForm::fill_page(TPrinter& pr, const int righe)
{
  TPrintrow row;   
  PaginaQuadro pagina = curr_page();
  
// form feed
  if (righe < 0)
  {
    const int stop = dic_form_len();
    for (int i = _RigaCorr; i < stop; i++)
    {
      if (i == 0)
        if (_modulaser)
        {
          if (!_GiaMessoStartPage[pagina])
            put_modulaser(row, STARTPAGE, pagina);
        }
// Sull'ultima riga metto il codice ditta 
      if (i == stop - 1)
      {  
//        if (_modulaser && EndJob() && curr_page() == QUARTA) 
        if (_modulaser && EndJob() && ultima_pagina())
          put_modulaser(row, ENDDOC);

        TString16 ditta; ditta << _codditta;
        row.put(ditta, POS_DITTA);
      }  
      pr.print(row);                     
      row.reset();        
    }
    _RigaCorr = 0;
    return;
  }    
  else      // righe > 0           
  {
    for (int i=0; i < righe; i++)
    {
      if (i == 0 && _modulaser && !_GiaMessoStartPage[pagina])
        put_modulaser(row, STARTPAGE, pagina);    
      else
        row.reset();
      pr.print(row);
      row.reset();
      _RigaCorr++;
    }
  }  
}

void TDicForm::jump_to_line(TPrinter& pr, const int lin)
{
  if (_RigaCorr > lin)           
    fill_page(pr, -1);
  fill_page(pr, lin - _RigaCorr);
}


int TDicForm::firma_dichiarante()
{ 
  TPrint_section& footer = section('F', last_page);
  TForm_item& firma = footer.find_field(FIRMADIC);  
  
  const int y = firma.y()-1;

  TString cognome = firma.get();
  if (cognome.len() > 30 && cognome[29] == ' ')
  {
    TString nome = cognome.mid(30, -1);
    cognome.cut(30); cognome.trim();
    cognome << ' ' << nome;
    firma.set(cognome);
        
    footer.row(y).reset();
    footer.row(y).put(cognome, firma.x()-1);   
  }  
  
  return y;
}

void TDicForm::attiva_totali(char tipo)
{
  TPrint_section& foot = section('F', last_page);  
  for (int f = foot.fields()-1; f >= 0; f--)
  {                
    TForm_item& item = foot.field(f);
    if (tipo == 'F')
    {
      _tot_giu.add(item.get(), f);
      if (_tot_fis.items())
        item.set(_tot_fis.row(f));
      else
        item.set("");  
    } 
    else
    {
      _tot_fis.add(item.get(), f);
      if (_tot_giu.items())
        item.set(_tot_giu.row(f));
      else
        item.set("");  
    } 
  }
}

void TDicForm::stampa_totali(TPrinter& pr, bool tot, bool fir)
{ 
  TPrint_section& totali = section('F', last_page);
  totali.update();
  
  const int y = firma_dichiarante();
  for (int i = 0; i <= y; i++)
  {               
    TPrintrow& row = totali.row(i);
    if ((i < y && !tot) || (i == y && !fir))
      row.reset();
    pr.print(row);
    _RigaCorr++;
  }
}

void TDicForm::stampa_testata(TPrinter& pr)
{
  TPrint_section& head = section('H', first_page);
  const word r = head.height()-1;
  TPrintrow& head_row = head.row(r-1);                    

// Setta il numero di pagina e poi lo incrementa
  TForm_item& nf = head.find_field(H_NUM_FOGLIO);          
  TString fstr(10); fstr << _num_foglio;
  nf.set(fstr);      
  _num_foglio++;
  
// Setta il cod.fis. del dichiarante se necessario
  if (tipo_ditta() == estinto)
  {
    TForm_item& cfd = head.find_field(H_COFI_DIC);
    cfd.set(_cofi_dic);
  }  
// Righe da saltare nelle prime pag. dei moduli successivi al primo (che' son
// senza le righe del posizionamento...)
  int righedasaltare=HEADER_PRIMA_NOPOS;
  head.update();  
  for (word j = 0; j <= r; j++)
  {
    if (j==0)
    {        
      if (_modulaser)
      {
        TPrintrow& r = head.row(j);
        if (!_GiaMessoStartDoc)
          put_modulaser(r, STARTDOC);     
        put_modulaser(r, STARTDITTA);
        put_modulaser(r, STARTPAGE, 1);
        pr.print(r);
        _RigaCorr++;
        r.reset();
        righedasaltare--;
      }
      if (!PaginaPosizionamento())
        fill_page(pr, righedasaltare);
    }             
    pr.print(head.row(j));
    _RigaCorr++;
  }
}

void TDicForm::next_page(TPrinter& pr)
{
  fill_page(pr, -1);   // formfeed "adattato"  
  inc_curr_page();
}

void TDicForm::azzera_totali()
{
  TPrint_section& foot = section('F', last_page);  
  foot.reset();
  for (int f = foot.fields()-1; f >= 0; f--)
    foot.field(f).set("");
    
  _tot_fis.destroy();
  _tot_giu.destroy();
}

void TDicForm::set_body(TPrinter& pr, const char tipo)
{
  TPrint_section& body = section('B', odd_page);
  body.reset();
  body.update();       
//  aggiorna_totali(tipo);
  const int body_righe = body.height();
  for (int i=0; i < body_righe; i++)
  {
    pr.print(body.row(i));
    _RigaCorr++;
  }
  if (usa_progind())
    progind()->addstatus(1);
}

void TDicForm::posiziona()
{
  _GiaPosizionato = TRUE;
  _PaginaPosizionamento = TRUE;

  arrange_form();
}

///////////////////////////////////////////////////////////////////////////////////////////
//
// Quadro G                                                                                
//
///////////////////////////////////////////////////////////////////////////////////////////

HIDDEN const int QG_FORMLEN = 72;
HIDDEN const int QG_PAGINE  = 2;
HIDDEN const int HEADER_SECONDA_G = 8;

class TQuadroG : public TDicForm
{
  private:  
    long  _items_g, _items_gd;
    void    stampa_prospetti1_2(TPrinter& pr);
    void    stampa_prospetti3_4(TPrinter& pr);

  protected:  
    virtual bool ultima_pagina() const { return _PaginaCorrente==SECONDA; }                                                                           
    virtual void inc_curr_page();
    virtual void next_page(TPrinter& pr);
    virtual void stampa_totali(TPrinter& pr) {}
    virtual void aggiorna_totali(const char tipo) {}
    virtual void set_body(TPrinter& pr, const char tipo) {}

  public:                 
    virtual bool  print(const long codditta, const long NumFis, const long NumNoFis);
    void set_items_gd(const long itg, const long itgd) { _items_g = itg; _items_gd = itgd; }
    
    TQuadroG(const char* form, const char* quadro)  : TDicForm(form, quadro), 
                                                      _items_g(0L), _items_gd(0L) {}
    virtual ~TQuadroG() {}
};      


void TQuadroG::inc_curr_page()
{
  if (_PaginaCorrente == PRIMA)
    _PaginaCorrente = SECONDA;
  else
    _PaginaCorrente = PRIMA;
}


void TQuadroG::next_page(TPrinter& pr)
{
  PaginaQuadro PagCorr = curr_page();
  fill_page(pr, -1);
  inc_curr_page();
}


void TQuadroG::stampa_prospetti1_2(TPrinter& pr)
{
  TPrint_section& head = section('H', 1);
  const word rr = head.height()-1;
  TPrintrow& head_row = head.row(rr-1);                    
  
// Setta il numero di pagina e poi lo incrementa
  TForm_item& nf = head.find_field(H_NUM_FOGLIO);          
  TString fstr(10); fstr << _num_foglio;
  nf.set(fstr);      
  _num_foglio++;

// Setta il cod.fis. del dichiarante se necessario
  if (tipo_ditta() == estinto)
  {
    TForm_item& cfd = head.find_field(H_COFI_DIC);
    cfd.set(_cofi_dic);
  }  

  TCursor* cur = cursor();

// Prospetto n. 2        
  TRectype& r = cur->curr();
  TToken_string p22(r.get("P22"));
  TToken_string p23(r.get("P23"));
  TToken_string p24(r.get("P24"));    
  TToken_string p25(r.get("P25"));    
  TToken_string p26(r.get("P26"));        
  
  const int START_P2 = 56;
  const int RIGHE_P2 = 5;
  const int COL_P2 = 5;
  int cols = 0;        
  for (int i = 0; i < RIGHE_P2; i++)
  {
    const int fc2 = START_P2 + cols;
    TForm_item& c2 = head.find_field(fc2);
    c2.set(p22.get(i));
    
    const int fc3 = fc2 + 1;     
    TForm_item& c3 = head.find_field(fc3);    
    c3.set(p23.get(i));    

    const int fc4 = fc3 + 1;  
    TForm_item& c4 = head.find_field(fc4);    
    c4.set(p24.get(i));    

    const int fc5 = fc4 + 1;     
    TForm_item& c5 = head.find_field(fc5);    
    c5.set(p25.get(i));    

    const int fc6 = fc5 + 1;     
    TForm_item& c6 = head.find_field(fc6);    
    c6.set(p26.get(i));            
    
    cols += COL_P2;
  }

// Righe da saltare nelle prime pag. dei moduli successivi al primo (che' son
// senza le righe del posizionamento...)
  int HEADER_PRIMA_NOPOS = 3;
  head.update();  
  for (word j = 0; j <= rr; j++)
  {
    if (j==0)
    {        
      if (_modulaser)
      {
        TPrintrow& r = head.row(j);
        if (!_GiaMessoStartDoc)
          put_modulaser(r, STARTDOC);     
        put_modulaser(r, STARTDITTA);
        put_modulaser(r, STARTPAGE, 1);
        pr.print(r);
        _RigaCorr++;
        r.reset();
        HEADER_PRIMA_NOPOS--;
      }
      if (!PaginaPosizionamento())
        fill_page(pr, HEADER_PRIMA_NOPOS);
    }             
    pr.print(head.row(j));
    _RigaCorr++;
  }
//  fill_page(pr, -1);   // formfeed "adattato"  
//  inc_curr_page();
}                   

void TQuadroG::stampa_prospetti3_4(TPrinter& pr)
{
  TPrint_section& sez = section('B');
  const word rr = sez.height()-1;
  sez.reset();
  TPrintrow& head_row = sez.row(rr-1);                    

// Prospetto n. 3
  TCursor* cur = cursor();
  TRectype& r = cur->curr();
  TToken_string p33a(r.get("P33A"));
  TToken_string p33b(r.get("P33B"));
  TToken_string p35a(r.get("P35A"));    
  TToken_string p35b(r.get("P35B"));    
  TToken_string p36a(r.get("P36A"));        
  TToken_string p36b(r.get("P36B"));        

  TString dep1,dep2,dep3,dep4;
// Stabilisce se ci vuole l'aggiuntivo    
  dep1=p35a.get(6);
  dep2=p35a.get(10);
  dep3=p35a.get(13);
  dep4=p35a.get(16);
  bool bAggiuntivo=!dep1.blank() || !dep2.blank() || !dep3.blank() || !dep4.blank();
        
// colonna 2 e 7  
  int  k = 1;    
  real tot2,tot7,tot_tot2,tot_tot7;
  
  tot2     = ZERO;
  tot7     = ZERO;                    
  tot_tot2 = ZERO;
  tot_tot7 = ZERO;
  
  for (int i=0; i<19; i++)
  { 
    if (i == 6 || i == 10 || i == 13 || i ==16) continue;
    
    real token2 (p33a.get(i));
    real token7 (p36b.get(i));
    tot2     += token2;
    tot7     += token7;             
    tot_tot2 += token2;
    tot_tot7 += token7;
    if (i == 5 || i == 9 || i == 12 || i == 15 || i == 18)
    {
      TForm_item& c2 = sez.find_field(k);  
      TForm_item& c7 = sez.find_field(k+54);  
    
      c2.set(tot2.string());
      c7.set(tot7.string());   
      k++;
      tot2 = ZERO;
      tot7 = ZERO;  
// Stampa totali  
      TForm_item& t2       = sez.find_field(k);  
      TForm_item& allegato = sez.find_field(90);      
      if (i == 18)
      {
        if (!bAggiuntivo)
        {                  
          t2.show();
          allegato.hide();
          TForm_item& t7 = sez.find_field(k+54);  
          t2.set(tot_tot2.string());
          t7.set(tot_tot7.string());   
        }
        else
        { 
          allegato.show();
          t2.hide();          
          allegato.set("VEDI ALLEGATO");                
        }  
      }
    }
  }

  const int RIGHE_P3 = 21;
  
// Colonna 3 
  const int START_P3_COL3 = 7;
  int c3=0;                    
  real totale = ZERO;
  for (i = 0, k = 0; i < RIGHE_P3; i++)
  {            
// Salta le righe dell'aggiuntivo             
    if (i == 6 || i == 10 || i == 13 || i ==16 || i == 19) continue;
    
    c3 = START_P3_COL3 + k;
    TForm_item& c5a = sez.find_field(c3); 
    real importo (p33b.get(i));
    if (i != 20)
      c5a.set(importo.string());  
    else
      if (!bAggiuntivo) c5a.set(totale.string());  
    totale += importo;  
    k++;  
  }                        

// Colonna 5
  const int START_P3_COL5 = c3 + 1;        
  int c5=0;                   
  totale = ZERO;
  for (i = 0, k = 0; i < RIGHE_P3; i++)
  { 
    if (i == 6 || i == 10 || i == 13 || i ==16 || i == 19) continue;
      
    c5 = START_P3_COL5 + k;
    TForm_item& c5a = sez.find_field(c5);
    real importo (p35b.get(i));
    if (i != 20)
      c5a.set(importo.string());  
    else
      if (!bAggiuntivo) c5a.set(totale.string());  
    totale += importo;  
    k++;
  }                                                                             

// Colonna 6
  const int START_P3_COL6 = c5 + 1;
  int c6=0;     
  totale = ZERO;
  for (i = 0, k = 0; i < RIGHE_P3; i++)
  { 
    if (i == 6 || i == 10 || i == 13 || i ==16 || i == 19) continue;
      
    c6 = START_P3_COL6 + k;
    TForm_item& c6a = sez.find_field(c6);
    real importo (p36a.get(i));
    if (i != 20)
      c6a.set(importo.string());  
    else
      if (!bAggiuntivo) c6a.set(totale.string());  
    totale += importo;  
    k++;
  }                                                                             

  sez.update();       
  const int sez_righe = sez.height();
  for (i=0; i < sez_righe; i++)
  {
    pr.print(sez.row(i));
    _RigaCorr++;
  }
  if (usa_progind())
    progind()->addstatus(1);
//  fill_page(pr, -1);   // formfeed "adattato"  
//  inc_curr_page();
}


bool TQuadroG::print(const long codditta, const long NumFis, const long NumNoFis)
{  
  TCursor* cur = cursor();
  
  bool StabilitaInesistenzaNoFis = FALSE;
  bool StabilitaInesistenzaFis = FALSE;  
  long CtrFis   = NumFis;
  long CtrNoFis = NumNoFis;
  long PtrFis = -1L, PtrNoFis=-1L;
  TPrinter& pr = printer();
    
  _CtrFisStampati = _CtrNoFisStampati = 0;
  _finite_fis = _finite_nofis = FALSE;
  _GiaStampatiFis = _GiaStampatiNoFis = FALSE;
  _EndPrintDitta = FALSE;  // Vero se stampato l'ultimo record
  bool LastRecord = FALSE; // Vero se letto l'ultimo record

  _PaginaCorrente = PRIMA;      
  
/*  if (! */InitPrint(codditta); /*)*/
//    return FALSE;

  for (int pagina=1; pagina <= QG_PAGINE; pagina++, next_page(pr))
  {
    pr.formlen(dic_form_len());             
  
    if (_PaginaCorrente == PRIMA)
    {                      
//      if (!_PaginaPosizionamento)
//        fill_page(pr,HEADER_PRIMA_NOPOS);
      
      if (_modulaser) ClearFlagModulaser();
     
      (*cur) = PtrFis >= 0L ? PtrFis : 0L;
      stampa_prospetti1_2(pr);
    }

    if (_PaginaCorrente == SECONDA)
    {
// Reset del flag di pagina con posiz.      
      if (_posiziona && _PaginaPosizionamento) _PaginaPosizionamento = FALSE;
      pr.formlen(dic_form_len());             
      fill_page(pr, HEADER_SECONDA_G);
      stampa_prospetti3_4(pr);          
    }
  }  // for pagina..

  return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////////////
//
//                                      Distinta G                                                                                
//
///////////////////////////////////////////////////////////////////////////////////////////

HIDDEN const int QGD_FORMLEN       = 72;
HIDDEN const int QGD_PAGINE        = 2;  
HIDDEN const int HEADER_SECONDA_GD = 16;
HIDDEN const int QGD_RIGHE_PRIMA   = 5;
HIDDEN const int QGD_RIGHE_SECONDA = 6;

class TDistintaG : public TQuadroG
{
  private:  
    virtual void  stampa_totali(TPrinter& pr, bool tot);
    virtual void  next_page(TPrinter& pr);
    virtual void  set_body(TPrinter& pr, const char tipo);
    int calcola_firma();
  public:                 
    virtual bool  print(const long codditta, const long NumFis, const long NumNoFis);

    void stampa_testata_quadroG(TPrinter& pr);
    
    TDistintaG(const char* form, const char* quadro) : TQuadroG(form,quadro) {}
    virtual ~TDistintaG() {} 
};      

int TDistintaG::calcola_firma()
{
  TPrint_section& totali = section('F', even_page);
  TForm_item& signature = totali.find_field(16);
  const int y = signature.y();
  TString spazi(50); spazi.fill(' ');  
  TString cognome = signature.get();
  if (cognome.len() > 30 && cognome[29] == ' ')
  {
    TString nome = cognome.mid(30, -1);
    cognome.cut(30); cognome.trim();
    cognome << ' ' << nome;
    signature.set(cognome);
  }   
  totali.row(y-1).put(spazi, signature.x()-1);
  totali.row(y-1).put(cognome, signature.x()-1);
  return y;
}

void TDistintaG::stampa_totali(TPrinter& pr, bool tot)
{ 
  PaginaQuadro PagCorr = curr_page();
  if (PagCorr == PRIMA)
  {
    TPrint_section& totali = section('F', odd_page);
    totali.update();
    for (int i = 0; i < totali.items(); i++)
    {
      pr.print(totali.row(i));
      _RigaCorr++;
    }
    totali.reset();
    for (int f = totali.fields()-1; f >= 0; f--)
      totali.field(f).set("");
  }
  else
    if (PagCorr == SECONDA)
    {
      TPrint_section& totali = section('F', even_page);
      totali.update();
      const int lasty = calcola_firma() - 1;      
      for (int i = 0; i < totali.items(); i++)
      {      
        TPrintrow& row = totali.row(i);
        if (i < lasty && !tot)
          row.reset();
        pr.print(row);
        _RigaCorr++;
      }            
      totali.reset();
      for (int f = totali.fields()-1; f >= 0; f--)
        totali.field(f).set("");
    }
}

void TDistintaG::next_page(TPrinter& pr)
{
  PaginaQuadro PagCorr = curr_page();
  
  fill_page(pr, -1);   // formfeed "adattato"  
  inc_curr_page();
}

void TDistintaG::set_body(TPrinter& pr, const char tipo)
{
  if (tipo == 'F')   
  {
    TPrint_section& body = section('B', odd_page); 
    body.reset();
    body.update();       
    const int body_righe = body.height();
    for (int i=0; i < body_righe; i++)
    {
      pr.print(body.row(i));
      _RigaCorr++;
    } 
  }
  else
    if (tipo == 'G')
    {
      TPrint_section& body = section('B', even_page); 
      body.reset();
      body.update();       
      const int body_righe = body.height();
      for (int i=0; i < body_righe; i++)
      {
        pr.print(body.row(i));
        _RigaCorr++;
      } 
    }  
    if (usa_progind())
    progind()->addstatus(1);
}

void TDistintaG::stampa_testata_quadroG(TPrinter& pr)
{
  TPrint_section& head = section('H', last_page);
  const word r = head.height()-1;
  TPrintrow& head_row = head.row(r-1);                    

// Setta il cod.fis. del dichiarante se necessario
  if (tipo_ditta() == estinto)
  {
    TForm_item& cfd = head.find_field(H_COFI_DIC);
    cfd.set(_cofi_dic);
  }  
// Righe da saltare nelle prime pag. dei moduli successivi al primo (che' son
// senza le righe del posizionamento...)
  int righedasaltare=HEADER_PRIMA_NOPOS;
  head.update();  
  for (word j = 0; j <= r; j++)
  {
    if (j==0)
    {        
      if (_modulaser)
      {
        TPrintrow& r = head.row(j);
        if (!_GiaMessoStartDoc)
          put_modulaser(r, STARTDOC);     
        put_modulaser(r, STARTDITTA);
        put_modulaser(r, STARTPAGE, 1);
        pr.print(r);
        _RigaCorr++;
        r.reset();
        righedasaltare--;
      }
      if (!PaginaPosizionamento())
        fill_page(pr, righedasaltare);
    }             
    pr.print(head.row(j));
    _RigaCorr++;
  }
}

bool TDistintaG::print(const long codditta, const long NumFis, const long NumNoFis)
{                             
  TCursor* cur = cursor();
  
  bool StabilitaInesistenzaNoFis = FALSE;
  bool StabilitaInesistenzaFis = FALSE;  
  long CtrFis   = NumFis;
  long CtrNoFis = NumNoFis;
  long PtrFis = -1L, PtrNoFis=-1L;
  TPrinter& pr = printer(); 
  
  bool StampatiTotaliFis = FALSE;
  bool StampatiTotaliGiu = FALSE;
      
  _CtrFisStampati = _CtrNoFisStampati = 0;
  _finite_fis = _finite_nofis = FALSE;
  _GiaStampatiFis = _GiaStampatiNoFis = FALSE;
  _EndPrintDitta = FALSE;  // Vero se stampato l'ultimo record
  bool LastRecord = FALSE; // Vero se letto l'ultimo record
  _PaginaCorrente = PRIMA;      
  
  _codditta = codditta;  
  _RigaCorr = 0;  

  const long items = filtra(codditta);    

  while (!_EndPrintDitta)
  {
    for (int pagina=1; pagina <= QGD_PAGINE; pagina++, next_page(pr))
    {
      pr.formlen(QGD_FORMLEN);             
      
      if (_PaginaCorrente == PRIMA)
      {                     
        attiva_totali('F');
        if (_modulaser) ClearFlagModulaser();

        for (int righe=0; righe < QGD_RIGHE_PRIMA; righe++)
        {
// Stampa intestazione, solo sul primo foglio.
          if (!righe)    
          {
            (*cur) = PtrFis >= 0L ? PtrFis : 0L;
            stampa_testata(pr);
            _CtrFisStampati = 0; // conta quelli che stampo sulla prima
          }
          
          if (_finite_fis || StabilitaInesistenzaFis)
            break;
// La prima volta si deve posizionare sul primo record di p.f.
          if (PtrFis < 0L && !StabilitaInesistenzaFis)
          {
            const char tipo = cur->curr().get(QGD_TIPOA)[0];
            const bool Trovato = tipo == 'F';
            StabilitaInesistenzaFis = _finite_fis = !Trovato;
            PtrFis  = 0L;
          }                                        
          
          if (StabilitaInesistenzaFis)
            break;
                          
          (*cur) = PtrFis;
                                    
          const char tipo = cur->curr().get(QGD_TIPOA)[0];
      
          if (tipo != 'F')      
            break;
          else
          {
            CtrFis--;
            if (CtrFis == 0L) _finite_fis = TRUE;
            set_body(pr, 'F');
// La stampa e' finita se ho STAMPATO l'ultimo record
            LastRecord     = cur->pos() >= items-1;
//            _EndPrintDitta = LastRecord;
            _CtrFisStampati++;
            if (!LastRecord)
            {
              ++(*cur);
              PtrFis     = cur->pos();
              LastRecord = cur->pos() >= items-1;
            }
          }
        }   // for righe..
        PtrFis = cur->pos();  
        
        if (_finite_fis && !StampatiTotaliFis)
        {
          jump_to_line(pr,58);
          stampa_totali(pr,TRUE);
          StampatiTotaliFis = TRUE;
        }
      }

      if (_PaginaCorrente == SECONDA)
      {
// Reset del flag di pagina con posiz.      
        if (_posiziona && _PaginaPosizionamento) _PaginaPosizionamento = FALSE;
        for (int righe=0; righe < QGD_RIGHE_SECONDA; righe++)
        {
          if (!righe)
          {
            _CtrNoFisStampati = 0;
            // All'inizio salta le righe in alto
            fill_page(pr, HEADER_SECONDA_GD);
          }  

          if (_finite_nofis || StabilitaInesistenzaNoFis)
            break;

// La prima volta si deve posizionare sul primo record di p.g.
          if (PtrNoFis<0L && !StabilitaInesistenzaNoFis)
          {
            bool Trovato = FALSE;
            bool eof = FALSE;
            (*cur) = PtrFis-1 > 0L ? PtrFis-1 : 0L;  // parti dall'inizio
            while (!Trovato && !eof)
            {
              eof = cur->pos() >= items-1;                    
              const char tipo = cur->curr().get(QGD_TIPOA)[0];
              if (tipo == 'G')
              {
                PtrNoFis = cur->pos();
                Trovato = TRUE;
                break;
              }
              else
                ++(*cur);            
            }                                        
            StabilitaInesistenzaNoFis = _finite_nofis = !Trovato;
          }

// Gestisce i casi in cui non ci sono percipienti nella distinta..
//          if (items==0) _EndPrintDitta=TRUE;                    
          
          if (StabilitaInesistenzaNoFis)
            break;             
        
          (*cur) = PtrNoFis;
          const char tipo = cur->curr().get(QGD_TIPOA)[0];

          if (tipo != 'G')      
            break;
          else
          {
            CtrNoFis--;                          
            if (CtrNoFis == 0L) _finite_nofis = TRUE;          
            set_body(pr, 'G'); 
            LastRecord     = cur->pos() >= items-1;                    
//            _EndPrintDitta = LastRecord;
            _CtrNoFisStampati++;   
            if (!LastRecord)
            {
              ++(*cur);
              PtrNoFis   = cur->pos();
              LastRecord = PtrNoFis >= items-1;          
            }
          }
        }          
        PtrNoFis = cur->pos();     
        jump_to_line(pr,52);
        const bool stampa = _finite_nofis && !StampatiTotaliGiu;
        if (stampa)
        {
          stampa_totali(pr,TRUE);
          StampatiTotaliGiu = TRUE;
        }
        else
          stampa_totali(pr,FALSE);
          
        _EndPrintDitta = _finite_fis && _finite_nofis;  
        if (!_EndPrintDitta)           
        {                             // Se la distinta occupa piu' di un modulo devo fare in modo
          next_page(pr);              // che vengano stampate la testata del quadro G piu' le prime
          stampa_testata_quadroG(pr); // due pagine vuote prima di continuare a stampare la distinta
          next_page(pr);
        }
      }
    }  // for pagina..
  } // while !EndPrintDitta
  
  if (usa_progind()) 
  {
    delete _prog;
    _prog = NULL;
  }  
  
  return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////  
////////////////////////////////////////////////////////////////////////////////////////////
//  
//                                        TStDicArray                                                                                    
//
// Array delle ditte da stampare. Contiene una riga per ogni ditta che si vuole stampare
// Il formato della riga e': 
//   codditta|estinti|numfis|numnofis|ultimafis|ultimanofis  
//
/////////////////////////////////////////////////////////////////////////////////////////////

TToken_string& TStDicArray::operator[](int i) const
{ 
  return ((TString_array&)_store).row(i);
}

void TStDicArray::set_ultima_con_fis(const int index, const bool ultima_fis)
{  
  TToken_string riga((TString&)_store[index]);
  riga.add(ultima_fis, 4);
  _store.add(riga,index);
}

void TStDicArray::set_ultima_con_nofis(const int index, const bool ultima_nofis)
{  
  TToken_string riga((TString&)_store[index]);
  riga.add(ultima_nofis, 5);
  _store.add(riga,index);
}

void TStDicArray::set_flag_tipi(const int index, const bool ultima_fis, const bool ultima_nofis)
{
  TToken_string riga((TString&)_store[index]);
  riga.add(ultima_fis,4);
  riga.add(ultima_nofis,5);
  _store[index] = riga;
}

void TStDicArray::set_ctr_tipi(const int index, const int num_fis, const int num_nofis)
{
  TToken_string riga((TString&)_store[index]);
  riga.add(num_fis,2);
  riga.add(num_nofis,3);
  _store[index] = riga;
}

void TStDicArray::set(const int index, const TipoDitta tipo, const int num_fis, const int num_nofis,
                      bool ultima_con_fis, bool ultima_con_nofis, const char* cofi_dic)
{
  TToken_string riga((TString&)_store[index]);
  riga.add(tipo,1);
  riga.add(num_fis,2);
  riga.add(num_nofis,3);
  riga.add(ultima_con_fis,4);
  riga.add(ultima_con_nofis,5);
  TString codfis(20); codfis = cofi_dic ? cofi_dic : "";
  riga.add((const char*)codfis,6);
  _store[index] = riga;
}            

void TStDicArray::add(const long codditta, const TipoDitta tipo, const int num_fis, const int num_nofis,
             bool ultima_con_fis, bool ultima_con_nofis, const char* cfdic)
{
  TString key(40);
// Il formato della riga e': codditta|estinti|numfis|numnofis|ultimafis|ultimanofis  
  key.format("%ld|%d|%d|%d|%d|%d|%s", codditta, tipo, num_fis, num_nofis, ultima_con_fis, ultima_con_nofis, cfdic ? cfdic : "");
  _store.add(key);
}

//////////////////////////////////////////////////////////////////////////////////////////
//                        TStampaQuadro
//////////////////////////////////////////////////////////////////////////////////////////

TStampaQuadro::TStampaQuadro(const char* quad, char liv)
              : _quadro(quad), _livello(liv)
{ 
  _title = "Stampa Quadro "; _title << _quadro;
} 

// La maschera e' uguale per tutti i quadri
const char* TStampaQuadro::mask_name() const
{
  return "77STQD";
}

const char* TStampaQuadro::form_name() const
{
  __dep16 = "77Q";
  __dep16 << _quadro;
  return __dep16;
}

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

  _section = name(); 
  _section.cut(2); 
  _cnf = new TConfig(CONFIG_USER, _section);

  _m = new TMask(mask_name()); 
  _m->set_caption(taitol());

  if (singola_ditta())
  {
    _codditta = get_firm_770();  
    _m->set(F_CODDITTA, _codditta);
  } 
  else
  {
    _m->hide(F_RAGDITTA);
    _m->set(F_TEXT, "Ditte selezionate");
    _m->show(F_TEXT);
  }

  user_create();
    
  dispatch_e_menu(BAR_ITEM(1));  
  return TRUE;
}

bool TStampaQuadro::destroy()
{ 
  user_destroy();

  delete _m;
  delete _cnf;
  return TApplication::destroy();
}

void TStampaQuadro::on_config_change()
{ 
  TConfig conf(singola_ditta() ? CONFIG_STUDIO : CONFIG_USER);
  _anno_dic = (int)conf.get_long(ANNO_SEL, _section); 
}

bool TStampaQuadro::menu(MENU_TAG)
{
  KEY k;
  _m->set(F_ANNO, _anno_dic);
  while ((k = _m->run()) == K_ENTER) 
  {
    const bool modulaser = _m->get_bool(F_MODULASER);
    print(modulaser);
  }  
  return FALSE;
}

void TStampaQuadro::fill_estinti(const long CodDic)
{ 
  int NumFisiche=0, NumNoFisiche=0;
  TString CodFiDic(20);
    
// Salva il cod.fis. del dichiarante
  CodFiDic = cod_fis(CodDic);

  if (conta_tipi_per())        
  {
    conta_tipiper(CodDic, _quadro, &NumFisiche, &NumNoFisiche);      
    _ditte.add(CodDic, dichiarante, NumFisiche, NumNoFisiche);
  } 
  else                                                        
    _ditte.add(CodDic, dichiarante);
  
  const int index_dich = _ditte.curr_index();
  bool gia_trovata_ultima_fis = FALSE;
  bool gia_trovata_ultima_nofis = FALSE;
  int index = index_dich;

// Leggo gli estinti
  TLocalisamfile base(LF_BASE);
  base.setkey(2);
  base.zero();   
  base.put(BSE_CODDIC, (long)CodDic);
  TRectype dep(base.curr()); 

  for (base.read(); !base.eof(); base.next())
  {
    if (base.curr() > dep)
      break;

// Scarta il record del quadro I "globale" del dichiarante            
    const char tipoqua = base.get(BSE_TIPOQUA)[0];
    if (tipoqua == COD_QUA_I_DIC)
      continue;

    const long DittaEstinta = base.get_long(BSE_CODDITTA);

    if (conta_tipi_per())
    {
      conta_tipiper(DittaEstinta, _quadro, &NumFisiche, &NumNoFisiche);
      _ditte.add(DittaEstinta, estinto, NumFisiche, NumNoFisiche, FALSE, FALSE, CodFiDic);
    }
    else
      _ditte.add(DittaEstinta, estinto, 0L, 0L, FALSE, FALSE, CodFiDic);    

    if (conta_tipi_per())
    {
      // Determina se con questa ditta finiscono le persone f. o g.
      if (NumFisiche == 0 && !gia_trovata_ultima_fis) 
      {
        _ditte.set_ultima_con_fis(index, TRUE);
        gia_trovata_ultima_fis = TRUE;
      }
   
      if (NumNoFisiche == 0 && !gia_trovata_ultima_nofis)          
      {
        _ditte.set_ultima_con_nofis(index, TRUE);
        gia_trovata_ultima_nofis = TRUE;
      }
    }
    index++;
  }

  if (conta_tipi_per())
  {
// Finiti gli estinti. L'ultima ditta deve avere i totali se non gia' trovati
    if (!gia_trovata_ultima_fis)
      _ditte.set_ultima_con_fis(index, TRUE);        

    if (!gia_trovata_ultima_nofis)
      _ditte.set_ultima_con_nofis(index, TRUE);        
  }
}

// _ditte e' fatto di righe siffatte:
// codditta, flag 2 dichiarante, 1 normale, 0 estinto, num_fis, num_nofis, ultima_con_fis, ultima_con_nofis

bool TStampaQuadro::print_quadro(const int OffsetDitta, const bool modulaser)
{
  TDicForm* ff = get_form();
  int start=0, last=0;
// Setta formlen prima di printer.open per avere la lunghezza giusta nel caso di 
// stampa a video
  printer().formlen(QD_FORMLEN);               
  bool ok = printer().open();

  ff->set_cursor(get_cursor());
  ff->azzera_totali();
  ff->set_modulaser(modulaser);
  
// Dice se deve eseguire il posizionamento del foglio.
// Se stampa piu' ditte va eseguito solo sulla prima
// Occhio a non spostarlo nel ciclo.
  ff->set_posiziona(TRUE);
    
  if (OffsetDitta >= 0)
  {
    start = OffsetDitta;
    last = OffsetDitta;  
  }
  else
    last = _ditte.items() - 1;
    
  for (int i = start; i <= last; i++)
  {
    TString CoFiDic(20);
    TToken_string riga(ditte()[i]);
    const long codditta = atol(riga.get(0));
    const TipoDitta  tipo = (TipoDitta)riga.get_int(1);
    const long fis      = riga.get_long(2);
    const long nofis    = riga.get_long(3);
    const bool LastFis  = (bool)riga.get_int(4);
    const bool LastNoFis = (bool)riga.get_int(5);

// I gruppi dich-estinti hanno totali comuni  
// Si presume che nell'array vengano messi nell'ordine dich-estinti
    if (tipo == normale || tipo == dichiarante)
      ff->azzera_totali();

    if (tipo == estinto)
      CoFiDic = riga.get(6);

    if (conta_tipi_per())
    {      
// Se e' un dichiarante i totali vanno sull'estinto in cui finiscono o le F o le G
      const bool StampaTotaliFis = tipo == normale || 
                                  (tipo == estinto && LastFis);

      const bool StampaTotaliNoFis = tipo == normale || 
                                    (tipo == estinto && LastNoFis);

// Dice al form se e' questa ditta e' l'ultima con f. o g.
      ff->can_print_tot_fis(StampaTotaliFis);
      ff->can_print_tot_nofis(StampaTotaliNoFis);
    }

// Dice al form che tipo di ditta si stampa
    ff->set_tipo_ditta(tipo);

// Numera i fogli a partire da 1 per ogni ditta normale e da 1 e di seguito negli estinti
// per i sogg. dichiaranti
    if (tipo == normale || tipo == dichiarante)
      ff->set_num_foglio(1);
      
// Se la ditta e' estinta dice al form il cod.fis. del dichiarante
    if (tipo == estinto)
      ff->set_cofi_dic(CoFiDic);

// Dice al form che e' l'ultima ditta
    if (i == last)
      ff->set_last_ditta(TRUE);
      
    ff->print(codditta, fis, nofis);
  }                       
  
  printer().close();
  return ok;
}

void TStampaQuadro::print(const bool modulaser)
{
  int NumFisiche=0, NumNoFisiche=0;

  _ditte.destroy();  // Pulisce l'array delle ditte
  
  if (singola_ditta())           
  {
    if (sogg_estinto(_codditta))
    {
      warning_box("La ditta %ld e' un soggetto estinto", _codditta);
      return;
    }

// Se e' un dichiarante va a prendere tutti i suoi estinti.
    bool dich = sogg_dic(_codditta);
    if (dich)             
      fill_estinti(_codditta);    
    else
    {                                                                    
      if (conta_tipi_per())
      {
        conta_tipiper(_codditta, _quadro, &NumFisiche, &NumNoFisiche);            
        _ditte.add(_codditta, normale, NumFisiche, NumNoFisiche);      
      }
      else
        _ditte.add(_codditta, normale);            
    }
  }
  else    // stampa ditte selezionate
  {     
// Costruisco un'array delle ditte da stampare. 
// Tolgo i sogg. estinti, e dopo un dichiarante metto tutti i suoi estinti.
    long codditta_prec = get_firm_770();
    long codditta = 0L;
    int i=0;
    while ((codditta = _cnf->get_long(DITTE_SEL, _section, i++)) != 0L) 
    {  
      if (sogg_estinto(codditta))
        continue;

// Se e' un dichiarante va a prendere tutti i suoi estinti.
      bool dich = sogg_dic(codditta);
      if (dich)             
        fill_estinti(codditta);
      else
      {                                                                    
        if (conta_tipi_per())
        {
          conta_tipiper(codditta, _quadro, &NumFisiche, &NumNoFisiche);            
          _ditte.add(codditta, normale, NumFisiche, NumNoFisiche);      
        }
        else                                                            
          _ditte.add(codditta, normale);              
      }
    }  
    set_firm_770(codditta_prec);
  }
  
  print_quadro(-1, modulaser);
}


/////////////////////////////////////////////////////////////////////////////////////////////
//
//                                     STAMPA QUADRO D
//
/////////////////////////////////////////////////////////////////////////////////////////////

class TQuadroD : public TDicForm
{
  real    _totale, _somme, _imponibile, _importo, _netto;
  bool    _devo_sommare;
  
protected:
  virtual void next_page(TPrinter& pr);  
  virtual bool print(const long codditta, const long NumFis, const long NumNoFis);
  
public:
  bool     controlla_percentuale(TCursor& cur);
  void     set_body(TPrinter& pr, const char tipo);
  void     setta_importi(TPrint_section& body);
  void     leggi_importi();  

  TQuadroD(const char* form, const char* quadro)  : TDicForm(form, quadro) {}
  virtual ~TQuadroD() {} 
};      

bool TQuadroD::controlla_percentuale(TCursor& cur)
{ 
  bool stampa = TRUE;
  
  const TRectype& rec = cur.curr();
  
  long    ditta_p   = rec.get_long(QUD_CODDITTA);
  char    tipo_p    = rec.get_char(QUD_TIPOA);
  long    codana_p  = rec.get_long(QUD_CODANAGR);
  real    perc_p    = rec.get_real(QUD_PERC);
  TString codcaus_p = cur.curr(-14).get("S2");       
    
  ++cur;   
  long    ditta   = rec.get_long(QUD_CODDITTA);
  char    tipo    = rec.get_char(QUD_TIPOA);
  long    codana  = rec.get_long(QUD_CODANAGR);
  real    perc    = rec.get_real(QUD_PERC);
  TString codcaus = cur.curr(-14).get("S2");       
              
  if (ditta == ditta_p && tipo == tipo_p && 
      codana == codana_p && codcaus == codcaus_p &&
      perc == perc_p)
  {
    stampa = FALSE; 
    _devo_sommare = TRUE;
  } 

  --cur;

  return stampa;
}

void TQuadroD::leggi_importi()
{
  TCursor* cur = cursor();    
  
  _totale     = cur->curr().get_real(QUD_TOTALE);
  _somme      = cur->curr().get_real(QUD_SOMME);
  _imponibile = cur->curr().get_real(QUD_IMPONIBILE);
  _importo    = cur->curr().get_real(QUD_IMPORTO);
  _netto      = cur->curr().get_real(QUD_NETTO);
}

void TQuadroD::setta_importi(TPrint_section& body)
{
  TCursor* cur = cursor();    
  
  real totale     = cur->curr().get_real(QUD_TOTALE);
  real somme      = cur->curr().get_real(QUD_SOMME);
  real imponibile = cur->curr().get_real(QUD_IMPONIBILE);
  real importo    = cur->curr().get_real(QUD_IMPORTO);
  real netto      = cur->curr().get_real(QUD_NETTO);
// Setta l'aliquota da programma perche' nel frm non si vede la virgola in "0.00"
  real perc      = cur->curr().get_real("PERC");  
  
  if (_devo_sommare)
  {
    totale     += _totale;
    somme      += _somme;
    imponibile += _imponibile;
    importo    += _importo;
    netto      += _netto;  
    _devo_sommare = FALSE;    
  }

  TForm_item& ftotale     = body.find_field(D_TOTALE);
  TForm_item& fsomme      = body.find_field(D_SNSRIT);
  TForm_item& fimponibile = body.find_field(D_IMPONIBILE);
  TForm_item& fimporto    = body.find_field(D_IMPORTO);        
  TForm_item& fnetto      = body.find_field(D_NETTO);          
  TForm_item& fperc      = body.find_field(19);          
    
  TString stotale    (totale.string());
  TString ssomme     (somme.string());
  TString simponibile(imponibile.string());
  TString simporto   (importo.string());
  TString snetto     (netto.string());
// Setta i campi
  ftotale.set(stotale);
  fsomme.set(ssomme);
  fimponibile.set(simponibile);
  fimporto.set(simporto);            
  fnetto.set(snetto);
  fperc.set(perc == ZERO ?  "  0,00" : perc.string("##@,@@"));  
}

void TQuadroD::set_body(TPrinter& pr, const char tipo)
{
  TPrint_section& body = section('B', odd_page);
  body.reset();  
//  body.update();       
  setta_importi(body);   
  TForm_item& stato_estero = body.find_field(QD_STATO_ESTERO);  
  TCursor* cur = cursor();    
  TString codice = cur->curr(-24).get("CODTAB");
  codice.trim();
  if (codice.empty())  
    stato_estero.hide();
  else
    stato_estero.show();
  body.update();
  const int body_righe = body.height();
  for (int i=0; i < body_righe; i++)
  {
    pr.print(body.row(i));
    _RigaCorr++;
  } 
  body.reset();
  if (usa_progind())
    progind()->addstatus(1);
}

void TQuadroD::next_page(TPrinter& pr)
{
  fill_page(pr, -1);   // formfeed "adattato"  
  inc_curr_page();
}

bool TQuadroD::print(const long codditta, const long NumFis, const long NumNoFis)
{  
  bool StabilitaInesistenzaNoFis = FALSE;
  bool StabilitaInesistenzaFis   = FALSE;  
  long CtrFis   = NumFis;
  long CtrNoFis = NumNoFis;
  long PtrFis   = -1L, PtrNoFis=-1L;
  TPrinter& pr  = printer();
  
  bool StampatiTotaliFis = FALSE;
  bool StampatiTotaliGiu = FALSE;
    
  _CtrFisStampati = _CtrNoFisStampati = 0;
  _finite_fis     = _finite_nofis = FALSE;
  _GiaStampatiFis = _GiaStampatiNoFis = FALSE;  
  _EndPrintDitta  = FALSE;  // Vero se stampato l'ultimo record
  bool LastRecord = FALSE;  // Vero se letto l'ultimo record
  bool stampa     = TRUE;
  
  _PaginaCorrente = PRIMA;      
  
  if (!InitPrint(codditta))
    return FALSE;
  
  TCursor* cur = cursor();
  
  while (!_EndPrintDitta)
  {
    for (int pagina=1; pagina <= QD_PAGINE; pagina++, next_page(pr))
    {
      pr.formlen(dic_form_len());                     

      if (_PaginaCorrente == PRIMA)
      { 
        attiva_totali('F');
        if (_modulaser) ClearFlagModulaser();
        
        bool testata = TRUE;
        for (int righe=0; righe < QD_RIGHE_PRIMA; righe++)
        {                    
          stampa = TRUE;
// Stampa intestazione, solo sul primo foglio.
          if (testata)    
          {
            (*cur) = PtrFis >= 0L ? PtrFis : 0L; 
            fill_page(pr, 9);
            stampa_testata(pr); 
            testata = FALSE;
          }
        
          if (_finite_fis || StabilitaInesistenzaFis)
            break;
// La prima volta si deve posizionare sul primo record di p.f.
          if (PtrFis < 0L && !StabilitaInesistenzaFis)
          {
            const char tipo = cur->curr().get(QUD_TIPOA)[0];
            const bool Trovato = tipo == 'F';
            StabilitaInesistenzaFis = _finite_fis = !Trovato;
            PtrFis = 0L;
          }

          if (StabilitaInesistenzaFis)
            break;
         
          (*cur) = PtrFis;
          const char tipo = cur->curr().get(QUD_TIPOA)[0];
      
          if (tipo != 'F')      
            break;
          else
          {
            CtrFis--;
            if (CtrFis == 0L) _finite_fis = TRUE;

            stampa = controlla_percentuale(*cur);
            if (stampa)
              set_body(pr, 'F');  
            else  
            {                  // Siccome questo record non viene stampato perche' va sommato
              leggi_importi(); // con quello successivo, non e' giusto incrementare l'indice
              righe--;         // delle righe per foglio. Siccome pero' l'ho gia' incrementato
            }                  // all'inizio del ciclo ora lo devo decrementare.
// La stampa e' finita se ho STAMPATO l'ultimo record
            LastRecord = cur->pos() >= _Items-1;
//            _EndPrintDitta = LastRecord;
            if (!LastRecord)
            {
              ++(*cur);
              PtrFis = cur->pos();
              LastRecord = cur->pos() >= _Items-1;
            }
          }
        }   // for righe..
        PtrFis = cur->pos();
      }

      if (_PaginaCorrente == SECONDA)
      {
// Reset del flag di pagina con posiz.      
        if (_posiziona && _PaginaPosizionamento) 
          _PaginaPosizionamento = FALSE;

        bool testata = TRUE;
        for (int righe=0; righe < QD_RIGHE_SECONDA; righe++)
        {  
          stampa = TRUE;
          if (testata)
          {
            fill_page(pr, HEADER_SECONDA);
            testata = FALSE;
          }
          
          if (_finite_fis || StabilitaInesistenzaFis)
            break;

          (*cur) = PtrFis;
          const char tipo = cur->curr().get(QUD_TIPOA)[0];

          if (tipo != 'F')      
            break;
          else
          {
            CtrFis--;
            if (CtrFis == 0L) _finite_fis = TRUE;

            stampa = controlla_percentuale(*cur);
            if (stampa)
              set_body(pr, 'F');  
            else 
            {
              leggi_importi();  
              righe--;
            }
            LastRecord = cur->pos() >= _Items-1;                    
  //          _EndPrintDitta = LastRecord;
            if (!LastRecord)
            {
              ++(*cur);
              PtrFis     = cur->pos();
              LastRecord = cur->pos() >= _Items-1;          
            }
          }
        }          
        PtrFis = cur->pos();
      }

      if (_PaginaCorrente == TERZA)
      {  
        bool testata = TRUE;     
        for (int righe=0; righe < QD_RIGHE_TERZA; righe++)
        {  
          stampa = TRUE;
          if (testata)
          {
            fill_page(pr, HEADER_TERZA);
            _CtrFisStampati = 0;  // conta quelli che stampo sulla terza                    
            testata = FALSE;
          }

          if (_finite_fis || StabilitaInesistenzaFis)
            break;

          (*cur) = PtrFis;
          const char tipo = cur->curr().get(QUD_TIPOA)[0];

          if (tipo == 'F')      
          {
            CtrFis--;                            
            if (CtrFis == 0L) 
              _finite_fis = TRUE;          

            stampa = controlla_percentuale(*cur);
            if (stampa)
              set_body(pr, 'F');  
            else
            {
              leggi_importi();  
              righe--;
            }
            LastRecord = cur->pos() >= _Items-1;                    
//            _EndPrintDitta = LastRecord;  
            _CtrFisStampati++;
            if (!LastRecord)
            {
              ++(*cur);                      
              PtrFis     = cur->pos();
              LastRecord = cur->pos() >= _Items-1;          
            } 
            
          }
          else
            break;
        }          
        PtrFis = cur->pos();
        
        if (_finite_fis && !StampatiTotaliFis)  
        {
          jump_to_line(pr, 64);
          stampa_totali(pr, TRUE, FALSE);
          StampatiTotaliFis = TRUE;
        }  
      }

      if (_PaginaCorrente == QUARTA)
      {  
        attiva_totali('G');
        bool testata = TRUE;
        
        for (int righe=0; righe < QD_RIGHE_QUARTA; righe++)
        {  
          stampa = TRUE;
// All'inizio salta le righe in alto
          if (testata) 
          {
            _CtrNoFisStampati = 0;          
            fill_page(pr, HEADER_QUARTA); 
            testata = FALSE;  
          }

          if (_finite_nofis || StabilitaInesistenzaNoFis)
            break;

// La prima volta si deve posizionare sul primo record di p.g.
          if (PtrNoFis<0L && !StabilitaInesistenzaNoFis)
          {
            bool Trovato = FALSE;
            bool eof = FALSE;
            (*cur) = PtrFis-1 > 0L ? PtrFis-1 : 0L;  // parti dall'inizio
            while (!Trovato && !eof)
            {
              eof = cur->pos() >= _Items-1;                    
              const long ditta = cur->curr().get_long(QUD_CODDITTA);
              if (ditta != codditta)
                break;
              const char tipo = cur->curr().get(QUD_TIPOA)[0];
              if (tipo != 'F')
              {
                PtrNoFis = cur->pos();
                Trovato = TRUE;
                break;
              }
              else
                ++(*cur);            
            }                                        
            StabilitaInesistenzaNoFis = _finite_nofis = !Trovato;
          }
        
          if (StabilitaInesistenzaNoFis)
            break;
        
          (*cur) = PtrNoFis;
          const char tipo = cur->curr().get(QUD_TIPOA)[0];

          if (tipo == 'G')      
          {
            CtrNoFis--;                          
            if (CtrNoFis == 0L) _finite_nofis = TRUE;          
            
            stampa = controlla_percentuale(*cur);
            if (stampa)
              set_body(pr, 'G');  
            else  
            {
              leggi_importi();  
              righe--;
            }
            LastRecord     = cur->pos() >= _Items-1;                    
//            _EndPrintDitta = LastRecord;
            _CtrNoFisStampati++;   
            if (!LastRecord)
            {
              ++(*cur);
              PtrNoFis   = cur->pos();
              LastRecord = PtrNoFis >= _Items-1;          
            }
          }
          else
            break;
        }          
        PtrNoFis = cur->pos();  
        
        jump_to_line(pr, 61);
        const bool stampa = _finite_nofis && !StampatiTotaliGiu;
        if (stampa)
        {
          stampa_totali(pr, TRUE, TRUE);
          StampatiTotaliGiu = TRUE;
        }  
        else
          stampa_totali(pr, FALSE, TRUE);
          
        _EndPrintDitta = _finite_fis && _finite_nofis;
      }
    }  // for pagina..
  }  // while !_EndPrintDitta   
  close_print();
  return TRUE;
}

class TStampaQuadroD : public TStampaQuadro
{
  TQuadroD*  _form;
  TCursor*   _cur;        

protected:   
  virtual bool  user_create();
  virtual bool  user_destroy();

  virtual TDicForm* get_form() const   { return _form; }
  virtual TCursor*  get_cursor() const { return _cur; }
        
public:
  TStampaQuadroD(const char* quadro, char livel);
  virtual ~TStampaQuadroD() { }
};

TStampaQuadroD::TStampaQuadroD(const char* quadro, char liv) 
              : TStampaQuadro(quadro, liv)
{
}

bool TStampaQuadroD::user_create()
{   
  _form = new TQuadroD("77QD", quadro());
                                                                
  TString sortkey(80);
  sortkey.format("CODDITTA|TIPOA|216@->RAGSOC|CODANAGR|14@->S2|PERC", LF_QUAD, LF_QUAD);
  _cur = new TSorted_cursor(_form->TForm::relation(), sortkey);

  return TRUE;  
}

bool TStampaQuadroD::user_destroy()
{
  delete _form;
  delete _cur;

  return TRUE;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// QUADRO D1
/////////////////////////////////////////////////////////////////////////////////////////////

#define QD1_RIGHE_PRIMA   6
#define QD1_RIGHE_SECONDA 9
#define QD1_RIGHE_TERZA   9
#define QD1_RIGHE_QUARTA  8

class TQuadroD1 : public TDicForm
{
  real    _totale, _quotapro, _speseant, _imponibile, _importo, _netto;
  bool    _devo_sommare;
  
protected:                                                             
  virtual bool print(const long codditta, const long NumFis, const long NumNoFis);
  
public:  
  bool     controlla_percentuale(TCursor& cur);
  void     set_body(TPrinter& pr, const char tipo);
  void     setta_importi(TPrint_section& body);
  void     leggi_importi();
  
  TQuadroD1(const char* form, const char* quadro)  : TDicForm(form, quadro) {}
  virtual ~TQuadroD1() {} 
};      

bool TQuadroD1::controlla_percentuale(TCursor& cur)
{ 
  bool stampa = TRUE;

  const TRectype& rec = cur.curr();
  long    ditta_p   = rec.get_long(QD1_CODDITTA);
  char    tipo_p    = rec.get_char(QD1_TIPOA);
  long    codana_p  = rec.get_long(QD1_CODANAGR);
  real    perc_p    = rec.get_real(QD1_PERC);
  TString codcaus_p = cur.curr(-14).get("S3");
              
  ++cur;   
  long    ditta   = rec.get_long(QD1_CODDITTA);
  char    tipo    = rec.get_char(QD1_TIPOA);
  long    codana  = rec.get_long(QD1_CODANAGR);
  real    perc    = rec.get_real(QD1_PERC);
  TString codcaus = cur.curr(-14).get("S3");
              
  if (ditta == ditta_p && tipo == tipo_p && 
      codana == codana_p && codcaus == codcaus_p &&
      perc == perc_p)
  {
    stampa = FALSE; 
    _devo_sommare = TRUE;
  } 
  --cur;

  return stampa;
}

void TQuadroD1::leggi_importi()
{
  const TRectype& rec = cursor()->curr();    
  _totale     = rec.get_real(QD1_TOTALE);
  _quotapro   = rec.get_real(QD1_QUOTAPRO);
  _speseant   = rec.get_real(QD1_SPESEANT);
  _imponibile = rec.get_real(QD1_IMPONIBILE);
  _importo    = rec.get_real(QD1_IMPORTO);
  _netto      = rec.get_real(QD1_NETTO);
}

void TQuadroD1::setta_importi(TPrint_section& body)
{
  const TRectype& rec = cursor()->curr();    
  
  real totale     = rec.get_real(QD1_TOTALE);
  real quotapro   = rec.get_real(QD1_QUOTAPRO);
  real speseant   = rec.get_real(QD1_SPESEANT);
  real imponibile = rec.get_real(QD1_IMPONIBILE);
  real importo    = rec.get_real(QD1_IMPORTO);
  real netto      = rec.get_real(QD1_NETTO);
// Setta l'aliquota da programma perche' nel frm non si vede la virgola in "0.00"
  real perc      = rec.get_real("PERC");  

  if (_devo_sommare)
  {
    totale     += _totale;
    quotapro   += _quotapro;
    speseant   += _speseant;
    imponibile += _imponibile;
    importo    += _importo;
    netto      += _netto;  
    _devo_sommare = FALSE;    
  }

  TForm_item& ftotale     = body.find_field(D1_TOTALE);
  TForm_item& fquotapro   = body.find_field(D1_QUOTAPRO);
  TForm_item& fspeseant   = body.find_field(D1_SPESEANT);
  TForm_item& fimponibile = body.find_field(D1_IMPONIBILE);
  TForm_item& fimporto    = body.find_field(D1_IMPORTO);        
  TForm_item& fnetto      = body.find_field(D1_NETTO);          
  TForm_item& fperc      = body.find_field(16);          
    
  TString stotale    (totale.string());
  TString squotapro  (quotapro.string());
  TString sspeseant  (speseant.string());
  TString simponibile(imponibile.string());
  TString simporto   (importo.string());
  TString snetto     (netto.string());
 
// Setta i campi
  ftotale.set(stotale);
  fquotapro.set(squotapro);
  fspeseant.set(sspeseant);
  fimponibile.set(simponibile);
  fimporto.set(simporto);            
  fnetto.set(snetto);
  fperc.set(perc == ZERO ?  "  0,00" : perc.string("##@,@@"));  
}

void TQuadroD1::set_body(TPrinter& pr, const char tipo)
{
  TPrint_section& body = section('B', odd_page);
  body.reset();  

  setta_importi(body);                
  body.update();
  const int body_righe = body.height();
  for (int i=0; i < body_righe; i++)
  {
    pr.print(body.row(i));
    _RigaCorr++;
  } 
  body.reset();
  if (usa_progind())
    progind()->addstatus(1);
}

bool TQuadroD1::print(const long codditta, const long NumFis, const long NumNoFis)
{  
  if (!InitPrint(codditta))
    return FALSE;

  TPrinter& pr  = printer();
    
  TRecnotype UltimoRitenutaAcconto  = -1L;
  TRecnotype UltimoRitenutaImposta  = -1L;
  bool StampatiTotaliFis = FALSE; 
  bool StampatiTotaliGiu = FALSE;

  TRecnotype PtrFis = -1L, PtrNoFis = -1L;
  
  _finite_fis = _finite_nofis = FALSE;

  _EndPrintDitta  = FALSE;  // Vero se stampato l'ultimo record

  _PaginaCorrente = PRIMA;      
  
  TCursor& cur = *cursor();
  cur = 0L;
// La prima volta si deve posizionare sul primo record di p.f.
  const TRectype& cur_rec = cur.curr();
  char tipo = cur_rec.get(QD1_TIPOA)[0];
  if (tipo == 'F')
  {
    PtrFis = 0L;
    while (tipo == 'F')
    { 
      const bool rit_acc = cur.curr(-14).get_bool("B0");
      if (rit_acc)
      {
#ifdef DBG      
        if (UltimoRitenutaImposta >= 0L)
          /*NF*/ CHECK(FALSE,"Bad sorting on cursor");
#endif          
        UltimoRitenutaAcconto = cur.pos();
      }  
      else  
        UltimoRitenutaImposta = cur.pos();
      
      ++cur;  
      if (cur.ok())
      {
        tipo = cur_rec.get(QD1_TIPOA)[0];
        if (tipo == 'G')
        {
          PtrNoFis = cur.pos();
          break;
        }  
      }  
      else
      {
        _finite_nofis = PtrNoFis < 0L; 
        break;
      }  
    } 
  }  
  else                                        
  {
    _finite_fis = TRUE; 
    if (tipo == 'G')
      PtrNoFis = 0L;
    else
    {
      _finite_nofis = TRUE;
      _EndPrintDitta = TRUE;
    }  
  }  
  
  for (cur = 0L; !_EndPrintDitta; next_page(pr))
  {
    pr.formlen(dic_form_len());
        
    if (_PaginaCorrente == PRIMA)
    {  
      if (_modulaser) ClearFlagModulaser();
      
      // Stampa intestazione, solo sul primo foglio.
      attiva_totali('F');
      
      cur = _finite_fis ? 0L : PtrFis;
      const char tipo = cur_rec.get(QD1_TIPOA)[0];
      TPrint_section& head = section('H', first_page);
      if (tipo == 'F' && !_finite_fis)
      {
        const bool rit_acc = cur.curr(-14).get_bool("B0");
        head.find_field(21).set(rit_acc ? "X" : ""); 
        head.find_field(22).set(rit_acc ? "" : "X");
      }
      else
      {
        head.find_field(21).set("");
        head.find_field(22).set("");
        _finite_fis = TRUE;
      }
      fill_page(pr,9);
      stampa_testata(pr); 
        
      for (int righe = 0; righe < QD1_RIGHE_PRIMA && !_finite_fis; righe++)
      {
        cur = PtrFis;

        const char tipo = cur_rec.get(QD1_TIPOA)[0];
        if (tipo == 'F')      
        {      
          if (righe > 0 && PtrFis == UltimoRitenutaAcconto+1) 
            break;

          const bool stampa = controlla_percentuale(cur);
          if (stampa)
            set_body(pr, 'F');  
          else                          
          {
            leggi_importi();            
            righe--;
          }
          PtrFis++;
        }
        else
          _finite_fis = TRUE;
      }   // for righe..
    }

    if (_PaginaCorrente == SECONDA)
    {
// Reset del flag di pagina con posiz.      
      if (_posiziona && _PaginaPosizionamento) 
        _PaginaPosizionamento = FALSE;

      fill_page(pr, HEADER_D1_SECONDA);
        
      for (int righe=0; righe < QD1_RIGHE_SECONDA && !_finite_fis; righe++)
      {  
        cur = PtrFis;
        const char tipo = cur_rec.get(QD1_TIPOA)[0];
        if (tipo == 'F')      
        {
          if (PtrFis == UltimoRitenutaAcconto+1) 
            break;

          const bool stampa = controlla_percentuale(cur);
          if (stampa)
            set_body(pr, 'F');  
          else                          
          {
            leggi_importi();
            righe--;
          }  
          PtrFis++;
        }
        else
          _finite_fis = TRUE;
      }          
    }

    if (_PaginaCorrente == TERZA)
    {    
      for (int righe = 0; righe < QD1_RIGHE_TERZA && !_finite_fis; righe++)
      {  
        fill_page(pr, HEADER_D1_TERZA);

        cur = PtrFis;

        const char tipo = cur_rec.get(QD1_TIPOA)[0];
        if (tipo == 'F')      
        {
          if (PtrFis == UltimoRitenutaAcconto+1) 
            break;

          const bool stampa = controlla_percentuale(cur);
          if (stampa)
            set_body(pr, 'F');  
          else                          
          {
            leggi_importi();
            righe--;
          }
          PtrFis++;  
        }
        else
          _finite_fis = TRUE;
      }          
      if (!StampatiTotaliFis &&
          PtrFis == UltimoRitenutaAcconto+1 || 
          PtrFis == UltimoRitenutaImposta+1)
      {
        jump_to_line(pr, 62);
        stampa_totali(pr, TRUE, FALSE);
        
        if (PtrFis > UltimoRitenutaImposta)
        {
          _finite_fis = TRUE;
          StampatiTotaliFis = TRUE;
        }  
        else
        {
          // Azzera i totali delle persone fisiche con ritenuta d'acconto
          TPrint_section& totali = section('F', last_page);
          for (int f = totali.fields()-1; f >= 0; f--)
            totali.field(f).set("");
        }  
      }  
    }

    if (_PaginaCorrente == QUARTA)
    {  
      fill_page(pr, HEADER_D1_QUARTA);   
      attiva_totali('G');
      
      for (int righe = 0; righe < QD1_RIGHE_QUARTA && !_finite_nofis; righe++)
      {  
        cur = PtrNoFis;
 
        const char tipo = cur_rec.get(QD1_TIPOA)[0];
        if (tipo == 'G')      
        {
          const bool stampa = controlla_percentuale(cur);
          if (stampa)
            set_body(pr, 'G');  
          else                          
          {
            leggi_importi();  
            righe--;
          }
          PtrNoFis++;
        }
        else
          _finite_nofis = TRUE;
      }          
      if (PtrNoFis >= cur.items() || _finite_nofis)
      {
        _finite_nofis = TRUE;
        jump_to_line(pr, 62);
        
        if (!StampatiTotaliGiu)
        {
          stampa_totali(pr, TRUE, TRUE);
          StampatiTotaliGiu = TRUE;
        }  
        else  
          stampa_totali(pr, FALSE, TRUE);
      }  
    
      _EndPrintDitta = _finite_fis && _finite_nofis;
    }
  }
  close_print();
  return TRUE;
}

class TStampaQuadroD1 : public TStampaQuadro
{
  TQuadroD1* _form;
  TCursor*   _cur;        
protected:   
  virtual bool  user_create();
  virtual bool  user_destroy();
  virtual TDicForm* get_form() const   { return _form; }
  virtual TCursor*  get_cursor() const { return _cur; }
public:
  TStampaQuadroD1(const char* quadro, char livel);
  virtual ~TStampaQuadroD1() { }
};

TStampaQuadroD1::TStampaQuadroD1(const char* quadro, char liv) 
              : TStampaQuadro(quadro, liv)
{}

bool TStampaQuadroD1::user_create()
{   
  _form = new TQuadroD1("77QD1", quadro());
  TString sortkey(80);
  sortkey.format("CODDITTA|TIPOA|14@->B0-|216@->RAGSOC|CODANAGR|PERC");
  _cur = new TSorted_cursor(_form->TForm::relation(), sortkey);
  return TRUE;  
}

bool TStampaQuadroD1::user_destroy()
{
  delete _form;
  delete _cur;
  return TRUE;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//                                         STAMPA QUADRO G
//
/////////////////////////////////////////////////////////////////////////////////////////////
class TStampaQuadroG : public TStampaQuadro
{
  private:
    TQuadroG*   _form_g;
    TDistintaG*   _form_gd;
    TCursor*    _cur_g, * _cur_gd;
  protected:    
    virtual bool user_create();
    virtual bool user_destroy();
    virtual TDicForm* get_form() const { return _form_g; }    
    virtual TCursor* get_cursor() const { return _cur_g; }    
    virtual bool print_quadro(const int OffsetDitta, const bool modulaser);
  public:
    TStampaQuadroG(char livel) : TStampaQuadro("G", livel) { }
};

bool TStampaQuadroG::user_create()
{
  _form_g  = new TQuadroG("77QG", quadro());
  _form_gd = new TDistintaG("77QGD", quadro());
  _cur_g = new TCursor(_form_g->TForm::relation());
  TString sortkey(80);
  sortkey.format("CODDITTA|TIPOA|216@->RAGSOC|CODANAGR", LF_QUAGD, LF_QUAGD);
  _cur_gd = new TSorted_cursor(_form_gd->TForm::relation(), sortkey);    
  _form_gd->set_num_foglio(1);
  return TRUE;
}

bool TStampaQuadroG::user_destroy()
{
  delete _form_gd;
  delete _form_g;
  delete _cur_gd;       
  delete _cur_g;
  return TRUE;
}

// _ditte e' fatto di righe siffatte:
// codditta, flag 2 dichiarante, 1 normale, 0 estinto, num_fis, num_nofis, ultima_con_fis, ultima_con_nofis
bool TStampaQuadroG::print_quadro(const int OffsetDitta, const bool modulaser)
{
  int start=0, last=0;                
  long items_g, items_gd;
  
  items_g = items_gd = 0L;
// Setta formlen prima di printer.open per avere la lunghezza giusta nel caso di 
// stampa a video
  printer().formlen(QG_FORMLEN);               
  bool ok = printer().open();

  _form_g->set_cursor(_cur_g);
  _form_gd->set_cursor(_cur_gd);    

  _form_g->set_modulaser(modulaser);
  _form_gd->set_modulaser(modulaser);

  _form_gd->azzera_totali();
      
// Dice se deve eseguire il posizionamento del foglio.
// Se stampa piu' ditte va eseguito solo sulla prima
// Occhio a non spostarlo nel ciclo.
  _form_g->set_posiziona(TRUE);
    
  if (OffsetDitta >= 0)
  {
    start = OffsetDitta;
    last = OffsetDitta;  
  }
  else
    last = ditte().items() - 1;
    
  for (int i = start; i <= last; i++)
  {
    TString CoFiDic(20);
    TToken_string riga(ditte()[i]);
    const long codditta = atol(riga.get(0));
    const TipoDitta  tipo = (TipoDitta)riga.get_int(1);
    const long fis      = riga.get_long(2);
    const long nofis    = riga.get_long(3);
    const bool LastFis  = (bool)riga.get_int(4);
    const bool LastNoFis = (bool)riga.get_int(5);

// I gruppi dich-estinti hanno totali comuni  
// Si presume che nell'array vengano messi nell'ordine dich-estinti
    if (tipo == normale || tipo == dichiarante)
      _form_g->azzera_totali();

    if (tipo == estinto)
      CoFiDic = riga.get(6);
      
// Se e' un dichiarante i totali vanno sull'estinto in cui finiscono o le F o le G
    const bool StampaTotaliFis = tipo == normale || 
                                (tipo == estinto && LastFis);

    const bool StampaTotaliNoFis = tipo == normale || 
                                  (tipo == estinto && LastNoFis);

// Dice al form se e' questa ditta e' l'ultima con f. o g.
    _form_gd->can_print_tot_fis(StampaTotaliFis);
    _form_gd->can_print_tot_nofis(StampaTotaliNoFis);

// Dice al form che tipo di ditta si stampa
    _form_g->set_tipo_ditta(tipo);

// Numera i fogli a partire da 1 per ogni ditta normale e da 1 e di seguito negli estinti
// per i sogg. dichiaranti
    if (tipo == normale || tipo == dichiarante) 
    {
      _form_g->set_num_foglio(1);   
      _form_gd->set_num_foglio(1);
    }      
      
// Se la ditta e' estinta dice al form il cod.fis. del dichiarante
    if (tipo == estinto)
      _form_g->set_cofi_dic(CoFiDic);

// Dice al form che e' l'ultima ditta
    if (i == last)
      _form_gd->set_last_ditta(TRUE);

    items_g  = _form_g->filtra(codditta);
    items_gd = _form_gd->filtra(codditta);
    if (items_g == 0 && items_gd == 0) continue;
    
// Dice al form quanto e' lunga la progress-bar      
    _form_g->set_items_gd(items_g, items_gd);  
    
    _form_g->print(codditta, fis, nofis);
// La progind deve essere la stessa tra G e distinta...
    
    _form_gd->set_progind(_form_g->progind()); // Passa la progind al form gd ...
    _form_g->set_progind(NULL);                // ... e la toglie dal form g
    
    _form_gd->print(codditta, fis, nofis);
  }                       
                                                              
  printer().close();
  return ok;
}

///////////////////////////////////////////////////////////////////////////////////////////
//
// Quadro G-1
//
///////////////////////////////////////////////////////////////////////////////////////////
HIDDEN const int QG1_FORMLEN = 72;
HIDDEN const int QG1_PAGINE  = 1;

class TQuadroG1 : public TDicForm
{
  private:  
    long  _items;
    void  stampa_prospetto(TPrinter& pr);

  public:                 
    virtual bool  print(const long codditta, const long NumFis=0L, const long NumNoFis=0L);
    //virtual bool  print(const long codditta);

    TQuadroG1(const char* form, const char* quadro)  : TDicForm(form, quadro) {}
    virtual ~TQuadroG1() {}
};      

bool TQuadroG1::print(const long codditta, const long NumFis, const long NumNoFis)
{  
  TCursor* cur = cursor();
  TPrinter& pr = printer();
  
  if (!InitPrint(codditta))
    return FALSE;

  pr.formlen(QG1_FORMLEN);             
    
  if (_modulaser) ClearFlagModulaser();

  (*cur) = 0L;
  stampa_prospetto(pr);

  return TRUE;
}

void TQuadroG1::stampa_prospetto(TPrinter& pr)
{
  TPrint_section& head = section('H', 1);
  const word rr = head.height()-1;
  TPrintrow& head_row = head.row(rr-1);                    

// Setta il cod.fis. del dichiarante se necessario
  if (tipo_ditta() == estinto)
  {
    TForm_item& cfd = head.find_field(H_COFI_DIC);
    cfd.set(_cofi_dic);
  }  

  TCursor* cur = cursor();
// Prospetto
  TRectype& r = cur->curr();
  TToken_string p12(r.get("P12"));
  TToken_string p13(r.get("P13"));
  TToken_string p14(r.get("P14"));    
  TToken_string p15(r.get("P15"));    
  TToken_string p16(r.get("P16"));        
  TToken_string p17(r.get("P17"));          
  
  const int START_PROSP  = 56;
  const int RIGHE_COL356 = 12;
  const int RIGHE_COL27  = 5;
  const int COL_PROSP = 5;
  
// Colonne 2 e 7
  for (int i = 0; i < RIGHE_COL27; i++)
  {
    const int fc2 = START_PROSP + i;
    TForm_item& c2 = head.find_field(fc2);
    c2.set(p12.get(i));
    
    const int fc7 = fc2 + RIGHE_COL27 + 1;     
    TForm_item& c7 = head.find_field(fc7);    
    c7.set(p17.get(i));    
  }

  const int START_COL3 = 68;
// Colonne 3 5 e 6
  for (i = 0; i < RIGHE_COL356; i++)
  {
    const int fc3 = START_COL3 + i;
    TForm_item& c3 = head.find_field(fc3);
    c3.set(p13.get(i));
    
    const int fc5 = fc3 + RIGHE_COL356 + 1;     
    TForm_item& c5 = head.find_field(fc5);    
    c5.set(p15.get(i));    

    const int fc6 = fc5 + RIGHE_COL356 + 1;     
    TForm_item& c6 = head.find_field(fc6);    
    c6.set(p16.get(i));    
  }

// Righe da saltare nelle prime pag. dei moduli successivi al primo (che' son
// senza le righe del posizionamento...)
  int HEADER_PRIMA_NOPOS = 3;
  head.update();  
  for (word j = 0; j <= rr; j++)
  {
    if (j==0)
    {        
      if (_modulaser)
      {
        TPrintrow& r = head.row(j);
        if (!_GiaMessoStartDoc)
          put_modulaser(r, STARTDOC);     
        put_modulaser(r, STARTDITTA);
        put_modulaser(r, STARTPAGE, 1);
        pr.print(r);
        _RigaCorr++;
        r.reset();
        HEADER_PRIMA_NOPOS--;
      }
      if (!PaginaPosizionamento())
        fill_page(pr, HEADER_PRIMA_NOPOS);
    }             
    else
    {
      pr.print(head.row(j));
      _RigaCorr++;
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//                                         STAMPA QUADRO G-1
//
/////////////////////////////////////////////////////////////////////////////////////////////
class TStampaQuadroG1 : public TStampaQuadroD
{
  private:
    TQuadroG1* _form;
    TRelation* _rel;
    TCursor*   _cur;
    
  protected:    
    virtual bool user_create();
    virtual bool user_destroy();

    virtual TDicForm* get_form() const   { return _form; }
    virtual TCursor*  get_cursor() const { return _cur; }
    virtual bool conta_tipi_per() const  { return FALSE; }

  public:
    TStampaQuadroG1(char livel)  : TStampaQuadroD("G1", livel) {}
};

bool TStampaQuadroG1::user_create()
{
  _form = new TQuadroG1("77QG1", quadro());

  _rel = new TRelation(LF_QUAG1);
  _rel->add(LF_NDITTE,  "CODDITTA=CODDITTA");
  _rel->add(LF_ANAG,    "TIPOA=TIPOA|CODANAGR=CODANAGR",  1, LF_NDITTE,  116);
  _rel->add(LF_ANAGFIS, "CODANAGR=CODANAGR",              1, LF_ANAG,    118);    
  _rel->add(LF_COMUNI,  "COM=COMNASC",                    1, LF_ANAGFIS, 113); 
  _rel->add(LF_COMUNI,  "COM=COMRF(COMRES)",              1, LF_ANAG,    213); 
  _cur = new TCursor(_rel);

  return TRUE;
}

bool TStampaQuadroG1::user_destroy()
{
  delete _cur;       
  delete _rel;
  delete _form;

  return TRUE;
}

/*
// _ditte e' fatto di righe siffatte:
// codditta, flag 2 dichiarante, 1 normale, 0 estinto, num_fis, num_nofis, ultima_con_fis, ultima_con_nofis
bool TStampaQuadroG1::print_quadro(TString& quadro, const int OffsetDitta)
{
  int start=0, last=0;                

// Setta formlen prima di printer.open per avere la lunghezza giusta nel caso di 
// stampa a video
  printer().formlen(QG_FORMLEN);               
  bool ok = printer().open();
  bool modulaser = _m->get_bool(F_MODULASER);

  _form->set_cursor(_rel, _cur);

  _form->set_modulaser(modulaser);

// Dice se deve eseguire il posizionamento del foglio.
// Se stampa piu' ditte va eseguito solo sulla prima
// Occhio a non spostarlo nel ciclo.
  _form->set_posiziona(TRUE);
    
  if (OffsetDitta >= 0)
  {
    start = OffsetDitta;
    last = OffsetDitta;  
  }
  else
    last = _ditte.items() - 1;
    
  for (int i = start; i <= last; i++)
  {
    TString CoFiDic(20);
    TToken_string riga(_ditte[i]);
    riga.separator('|');
    const long codditta = atol(riga.get(0));
    const TipoDitta  tipo = (TipoDitta)riga.get_int(1);

// I gruppi dich-estinti hanno totali comuni  
// Si presume che nell'array vengano messi nell'ordine dich-estinti
    if (tipo == normale || tipo == dichiarante)
      _form->azzera_totali();

    if (tipo == estinto)
      CoFiDic = riga.get(6);
      
// Dice al form che tipo di ditta si stampa
    _form->set_tipo_ditta(tipo);

// Numera i fogli a partire da 1 per ogni ditta normale e da 1 e di seguito negli estinti
// per i sogg. dichiaranti
    if (tipo == normale || tipo == dichiarante)
      _form->set_num_foglio(1);
      
// Se la ditta e' estinta dice al form il cod.fis. del dichiarante
    if (tipo == estinto)
      _form->set_cofi_dic(CoFiDic);

// Dice al form che e' l'ultima ditta
    if (i == last)
      _form->set_last_ditta(TRUE);

    _form->print(codditta);
  }                       
  printer().close();
  return ok;
}
*/
/*
void TStampaQuadroG1::fill_estinti(const long CodDic)
{ 
  int NumFisiche=0, NumNoFisiche=0;
  TString CodFiDic(20);
    
// Salva il cod.fis. del dichiarante
  CodFiDic = cod_fis(CodDic);
        
  _ditte.add(CodDic, dichiarante);
  const int index_dich = _ditte.curr_index();
  int index = index_dich;

// Leggo gli estinti
  TLocalisamfile base(LF_BASE);
  base.setkey(2);
  base.zero();   
  base.put(BSE_CODDIC, (long)CodDic);
  TRectype dep(base.curr()); 

  for (base.read(); !base.eof(); base.next())
  {
    if (base.curr() > dep)
      break;

// Scarta il record del quadro I "globale" del dichiarante            
    const char tipoqua = base.get(BSE_TIPOQUA)[0];
    if (tipoqua == COD_QUA_I_DIC)
      continue;

    const long DittaEstinta = base.get_long(BSE_CODDITTA);

    _ditte.add(DittaEstinta, estinto, 0L, 0L, FALSE, FALSE, CodFiDic);

    index++;
  }
}
*/
/*
void TStampaQuadroG1::print()
{
  int NumFisiche=0, NumNoFisiche=0;

  _ditte.destroy();  // Pulisce l'array delle ditte
  
  if (_singola_ditta)           
  {
    if (sogg_estinto(_codditta))
    {
      warning_box("La ditta %ld e' un soggetto estinto", _codditta);
      return;
    }

// Se e' un dichiarante va a prendere tutti i suoi estinti.
    bool dich = sogg_dic(_codditta);
    if (dich)             
      fill_estinti(_codditta);    
    else
      _ditte.add(_codditta, normale);      
  }
  else    // stampa ditte selezionate
  {     
// Costruisco un'array delle ditte da stampare. 
// Tolgo i sogg. estinti, e dopo un dichiarante metto tutti i suoi estinti.
    long codditta_prec = get_firm_770();
    long codditta = 0L;
    int i=0;
    while ((codditta = _cnf->get_long(DITTE_SEL, _section, i++)) != 0L) 
    {  
      if (sogg_estinto(codditta))
        continue;

// Se e' un dichiarante va a prendere tutti i suoi estinti.
      bool dich = sogg_dic(codditta);
      if (dich)             
        fill_estinti(codditta);
      else
        _ditte.add(codditta, normale);      
        
    }  
    set_firm_770(codditta_prec);
  }
  print_quadro(_quadro, -1);
}
*/


///////////////////////////////////////////////////////////////////////////////////////////
//
// Quadro F
//
///////////////////////////////////////////////////////////////////////////////////////////

HIDDEN const int QF_FORMLEN = 72;
HIDDEN const int QF_PAGINE  = 2;
HIDDEN const int HEADER_SECONDA_F = 7;

class TQuadroF : public TDicForm
{
  private:  
    real    pa3t, pa4t, pa5t, pa6t, pa7t;   // totali prosp. A
    real    pb3t, pb4t, pc3t, pc4t, pd3t, pd4t; // totali prosp, B, C e D
    int     _ptrA, _ptrB, _ptrC, _ptrD;       // puntatori alle righe dei prospetti
    long      _items;
    int       stampa_prospetto_A(TPrinter& pr);
    int       stampa_prospetto_B(TPrinter& pr);
    int       stampa_prospetto_C(TPrinter& pr);
    int       stampa_prospetto_D(TPrinter& pr);    
    TRecord_array*  _prosp_a, *_prosp_b, *_prosp_c, *_prosp_d;
    void      azzera_contatori();
    void      aggiorna_totali(char tipoprosp, TRectype& r);
    void      stampa_totali(char tipoprosp, TPrinter& pr);
    virtual bool ultima_pagina() const { return _PaginaCorrente==SECONDA; }
    
  public:                 
    virtual bool  print(const long codditta, const long numfis=0L, const long numnofis=0L);
    virtual void  inc_curr_page();
    virtual void  next_page(TPrinter& pr);

    TQuadroF(const char* form, const char* quadro)  : TDicForm(form, quadro) {}
    virtual ~TQuadroF() {} 
};      

void TQuadroF::azzera_contatori()
{
  pa3t = pa4t = pa5t = pa6t = pa7t = ZERO;
  pb3t=pb4t=pc3t=pc4t=pd3t=pd4t = ZERO; // totali prosp, B, C e D
  _ptrA = _ptrB = _ptrC = _ptrD = 1;
}


void TQuadroF::stampa_totali(char tipoprosp, TPrinter& pr)
{
  const int PA3_TOT = 104; 
  const int PB3_TOT = 54;  
  TPrint_section& sez = tipoprosp == 'A' ? section('H', 1) : section('B', 1);
  const int rr        = sez.height()-1;
  int i = PA3_TOT, riga_tot=0;  
  
  switch (tipoprosp)
  {
    case 'A':     
    {    
      riga_tot = 46;
      TForm_item& c = sez.find_field(i++);
      TString c3(pa3t.string());
      c.set(c3);
      c = sez.find_field(i++);  
      TString c4(pa4t.string());      
      c.set(c4);
      c = sez.find_field(i++);        
      TString c5(pa5t.string());            
      c.set(c5);
      c = sez.find_field(i++);
      TString c6(pa6t.string());
      c.set(c6);
      c = sez.find_field(i++);  
      TString c7(pa7t.string());      
      c.set(c7);
      break;
    }
    case 'B':     
    {      
      i = PB3_TOT;  
      riga_tot = 14;
      TForm_item& c = sez.find_field(i++);
      TString c3(pb3t.string());      
      c.set(c3);
      c = sez.find_field(i);    
      TString c4(pb4t.string());      
      c.set(c4);
      break;
    }
    case 'C':     
    {
      i = PB3_TOT+2;
      riga_tot = 20;      
      TForm_item& c = sez.find_field(i++);
      TString c3(pc3t.string());            
      c.set(c3);
      c = sez.find_field(i);          
      TString c4(pc4t.string());            
      c.set(c4);
      break;
    }
    case 'D':
    {
      i = PB3_TOT+4;
      riga_tot = 26;      
      TForm_item& c = sez.find_field(i++);
      TString d3(pd3t.string());            
      c.set(d3);
      c = sez.find_field(i);          
      TString d4(pd4t.string());            
      c.set(d4);
      break;      
    }
    default:
      break;
  }

  sez.update();
  pr.print(sez.row(riga_tot));
  _RigaCorr++;
  
  if (usa_progind())
    progind()->addstatus(1);         
  fill_page(pr, -1);   // formfeed "adattato"  
  inc_curr_page();
}

void TQuadroF::aggiorna_totali(char tipoprosp, TRectype& r)
{
  real sogg,rope,acc,ecc,sal;
  
  switch (tipoprosp)
  {
    case 'A':
      sogg = r.get_real(QUF_SOGRIT);
      rope = r.get_real(QUF_ROPE);
      acc  = r.get_real(QUF_ACCONTI);
      ecc  = r.get_real(QUF_VERSECC);
      sal  = r.get_real(QUF_VERSALDO);
      pa3t += sogg;
      pa4t += rope;
      pa5t += acc;
      pa6t += ecc;
      pa7t += sal;      
      break;
    case 'B':
      sogg = r.get_real(QUF_SOGRIT);
      rope = r.get_real(QUF_ROPE);
      pb3t += sogg;
      pb4t += rope;
      break;
    case 'C':
      sogg = r.get_real(QUF_SOGRIT);
      rope = r.get_real(QUF_ROPE);
      pc3t += sogg;
      pc4t += rope;
      break;
    case 'D':
      sogg = r.get_real(QUF_SOGRIT);
      rope = r.get_real(QUF_ROPE);
      pd3t += sogg;
      pd4t += rope;
      break;
    default:
      break;
  }
}

void TQuadroF::next_page(TPrinter& pr)
{
  PaginaQuadro PagCorr = curr_page();
//  if (PagCorr = SECONDA) stampa_totali(pr);
  fill_page(pr, -1);   // formfeed "adattato"  
  inc_curr_page();
}

void TQuadroF::inc_curr_page()
{
  if (_PaginaCorrente == PRIMA)
    _PaginaCorrente = SECONDA;
  else
    if (_PaginaCorrente == SECONDA)
      _PaginaCorrente = PRIMA;
}


bool TQuadroF::print(const long codditta, const long numfis, const long numnofis)
{  
  bool EndPrint=FALSE, End_A=FALSE, End_B=FALSE, End_C=FALSE, End_D=FALSE;
  int residui_A=0, residui_B=0, residui_C=0, residui_D=0;
  TCursor* cur = cursor();
  TPrinter& pr = printer();
  
  if (!InitPrint(codditta))
    return FALSE;                   
    
  azzera_contatori();    

  TLocalisamfile& rf = cur->file(LF_RIGHEF);
  TRectype dep(rf.curr());
  dep.zero();                
  dep.put("CODDITTA", _codditta);
  dep.put("TIPOPRO", "A");
  _prosp_a = new TRecord_array(dep, "NPROG");
  dep.put("TIPOPRO", "B");
  _prosp_b = new TRecord_array(dep, "NPROG");
  dep.put("TIPOPRO", "C");
  _prosp_c = new TRecord_array(dep, "NPROG");
  dep.put("TIPOPRO", "D");
  _prosp_d = new TRecord_array(dep, "NPROG");

  pr.formlen(QG1_FORMLEN);             

  while (!EndPrint)
  {    
    for (int pagina=1; pagina <= QF_PAGINE; pagina++, next_page(pr))
    {
      if (_PaginaCorrente == PRIMA)
      {                      
        if (_modulaser) ClearFlagModulaser();

        if (End_A)
          break;

        (*cur) = 0L;

        residui_A = stampa_prospetto_A(pr);

        End_A =  (residui_A == 0);
        if (End_A) stampa_totali('A', pr);
        _EndPrintDitta=EndPrint = End_A && End_B && End_C && End_D;
      }

      if (_PaginaCorrente == SECONDA)
      {
// Reset del flag di pagina con posiz.      
        if (_posiziona && _PaginaPosizionamento) _PaginaPosizionamento = FALSE;

        if (End_B && End_C && End_D)
          break;

        fill_page(pr, HEADER_SECONDA_F);

        residui_B = stampa_prospetto_B(pr);          
        End_B =  (residui_B == 0);        
        if (End_B) stampa_totali('B', pr);

        residui_C = stampa_prospetto_C(pr);          
        End_C =  (residui_C == 0);        
        if (End_C) stampa_totali('C', pr);

        residui_D = stampa_prospetto_D(pr);          
        End_D =  (residui_D == 0);        
        if (End_D) stampa_totali('D', pr);

        _EndPrintDitta=EndPrint = End_A && End_B && End_C && End_D;
      }
    }  // for pagina..
  } // EndPrint()
  close_print();
  return TRUE;
}

const int F_DESC_CAUS = 50;
const int RIGHE_PROSP = 3;

int TQuadroF::stampa_prospetto_C(TPrinter& pr)
{
  TPrint_section& sez = section('B', 1);
  const int rr        = sez.height()-1;

  const int START_C = 16;
  const int last_c = _prosp_c->last_row();
  for (int i=0; i < RIGHE_PROSP; _ptrC++, i++)
  {         
    if (_ptrC > last_c)
      break;
      
    TRectype& r = _prosp_c->row(_ptrC, TRUE);
    aggiorna_totali('C', r);        
    TString16 codcau(r.get(QUF_CODCAUS));
    TString   descr_cau(get_desc_cau(codcau));        
    TString16 aliq  (r.get(QUF_ALIQUOTA));   
    TString   sogg  (r.get(QUF_SOGRIT));
    TString   rope  (r.get(QUF_ROPE));

    const int fc0 = START_C + _ptrC - 1;
    TString16 nord; nord << _ptrC;
    TForm_item& c0 = sez.find_field(fc0);
    c0.set(nord);
    
    const int fc1 = fc0 + RIGHE_PROSP;     
    TForm_item& c1 = sez.find_field(fc1);    
    c1.set(descr_cau);    

    const int fc2 = fc1 + RIGHE_PROSP;     
    TForm_item& c2 = sez.find_field(fc2);    
    c2.set(aliq);    

    const int fc3 = fc2 + RIGHE_PROSP;     
    TForm_item& c3 = sez.find_field(fc3);    
    c3.set(sogg);    

    const int fc4 = fc3 + RIGHE_PROSP;     
    TForm_item& c4 = sez.find_field(fc4);    
    c4.set(rope);    
  }  
  const int res_C = last_c - _ptrC;    
  return res_C < 0 ? 0 : res_C;
}

int TQuadroF::stampa_prospetto_D(TPrinter& pr)
{
  TPrint_section& sez = section('B', 1);
  const int rr        = sez.height()-1;

  const int START_D = 31;
  const int last_d = _prosp_d->last_row();
  for (int i=0; i < RIGHE_PROSP; _ptrD++, i++)
  {                                      
    if (_ptrD > last_d)
      break;
      
    TRectype& r = _prosp_d->row(_ptrD, TRUE);
    aggiorna_totali('D', r); 
    TString16 codcau(r.get(QUF_CODCAUS));
    TString   descr_cau(get_desc_cau(codcau));        
    TString16 aliq  (r.get(QUF_ALIQUOTA));   
    TString   sogg  (r.get(QUF_SOGRIT));
    TString   rope  (r.get(QUF_ROPE));

    const int fc0 = START_D + _ptrD - 1;
    TString16 nord; nord << _ptrD;
    TForm_item& c0 = sez.find_field(fc0);
    c0.set(nord);
    
    const int fc1 = fc0 + RIGHE_PROSP;     
    TForm_item& c1 = sez.find_field(fc1);    
    c1.set(descr_cau);    

    const int fc2 = fc1 + RIGHE_PROSP;     
    TForm_item& c2 = sez.find_field(fc2);    
    c2.set(aliq);    

    const int fc3 = fc2 + RIGHE_PROSP;     
    TForm_item& c3 = sez.find_field(fc3);    
    c3.set(sogg);    

    const int fc4 = fc3 + RIGHE_PROSP;     
    TForm_item& c4 = sez.find_field(fc4);    
    c4.set(rope);    
  }

  sez.update();
  for (i=0; i < rr; i++)
  {
    pr.print(sez.row(i));
    _RigaCorr++;
  }

  if (usa_progind())
    progind()->addstatus(1);         

  const int res_D = last_d - _ptrD;      
  return res_D < 0 ? 0 : res_D;
}

int TQuadroF::stampa_prospetto_B(TPrinter& pr)
{
  TPrint_section& sez = section('B', 1);
  const int rr        = sez.height()-1;

  const int START_B = 1;     
  
  const int last_b = _prosp_b->last_row();
  for (int i=0; i < RIGHE_PROSP; _ptrB++, i++)
  {                                           
    if (_ptrB > last_b)
      break;
      
    TRectype& r = _prosp_b->row(_ptrB, TRUE);
    aggiorna_totali('B', r);
    TString dep(50);
    dep = r.get(QUF_CODCAUS);                 
    TString   descr_cau(get_desc_cau(dep));        
    TString16 aliq (r.get(QUF_ALIQUOTA));
    TString   sogg (r.get(QUF_SOGRIT));
    TString   rope (r.get(QUF_ROPE));

    const int fc0 = START_B + _ptrB - 1;
    TString16 nord; nord << _ptrB;
    TForm_item& c0 = sez.find_field(fc0);
    c0.set(nord);
    
    const int fc1 = fc0 + RIGHE_PROSP;     
    TForm_item& c1 = sez.find_field(fc1);    
    c1.set(descr_cau);    

    const int fc2 = fc1 + RIGHE_PROSP;     
    TForm_item& c2 = sez.find_field(fc2);    
    c2.set(aliq);    

    const int fc3 = fc2 + RIGHE_PROSP;     
    TForm_item& c3 = sez.find_field(fc3);    
    c3.set(sogg);    

    const int fc4 = fc3 + RIGHE_PROSP;     
    TForm_item& c4 = sez.find_field(fc4);    
    c4.set(rope);    
  }

// TBI setta totali e descr.causale F
  TString16 fcau(cursor()->curr(LF_QUAF).get(QUF_FCAUS));
  TString   descr_cau(get_desc_cau(fcau));          
  TForm_item& fd = sez.find_field(F_DESC_CAUS);      
  fd.set(descr_cau);
    
  const int res_B = last_b - _ptrB;    
  return res_B < 0 ? 0 : res_B;
}

int TQuadroF::stampa_prospetto_A(TPrinter& pr)
{
  TPrint_section& head = section('H', 1);
  const word rr = head.height()-1;
  TPrintrow& head_row = head.row(rr-1);                    

// Setta il cod.fis. del dichiarante se necessario
  if (tipo_ditta() == estinto)
  {
    TForm_item& cfd = head.find_field(H_COFI_DIC);
    cfd.set(_cofi_dic);
  }  

  TCursor* cur = cursor();
  
  const int START_PROSP  = 56;
  const int RIGHE_PROSP  = 6;
  const int COL_PROSP    = 8;                 
  const int last_a = _prosp_a->last_row();  

  for (int i=0; i < RIGHE_PROSP ; _ptrA++, i++)
  {         
    if (_ptrA > last_a)
      break;
    TRectype& r = _prosp_a->row(_ptrA, TRUE);  
    aggiorna_totali('A', r);
    TString16 codcau(r.get(QUF_CODCAUS));
    TString   descr_cau(get_desc_cau(codcau));
    TString16 aliq  (r.get(QUF_ALIQUOTA));   
    TString   sogg  (r.get(QUF_SOGRIT));
    TString   rope  (r.get(QUF_ROPE));
    TString   acc(r.get(QUF_ACCONTI));
    TString   ecc(r.get(QUF_VERSECC));
    TString   sal(r.get(QUF_VERSALDO));

    const int fc0 = START_PROSP + _ptrA - 1;
    TString16 nord; nord << _ptrA;
    TForm_item& c0 = head.find_field(fc0);
    c0.set(nord);
    
    const int fc1 = fc0 + RIGHE_PROSP;     
    TForm_item& c1 = head.find_field(fc1);    
    c1.set(descr_cau);    

    const int fc2 = fc1 + RIGHE_PROSP;     
    TForm_item& c2 = head.find_field(fc2);    
    c2.set(aliq);    

    const int fc3 = fc2 + RIGHE_PROSP;     
    TForm_item& c3 = head.find_field(fc3);    
    c3.set(sogg);    

    const int fc4 = fc3 + RIGHE_PROSP;     
    TForm_item& c4 = head.find_field(fc4);    
    c4.set(rope);    

    const int fc5 = fc4 + RIGHE_PROSP;     
    TForm_item& c5 = head.find_field(fc5);    
    c5.set(acc);    

    const int fc6 = fc5 + RIGHE_PROSP;     
    TForm_item& c6 = head.find_field(fc6);    
    c6.set(ecc);    

    const int fc7 = fc6 + RIGHE_PROSP;     
    TForm_item& c7 = head.find_field(fc7);    
    c7.set(sal);    
  }  
  
// Righe da saltare nelle prime pag. dei moduli successivi al primo (che' son
// senza le righe del posizionamento...)
  int HEADER_PRIMA_NOPOS = 3;
  head.update();  
  for (word j = 0; j <= rr; j++)
  {
    if (j==0)
    {        
      if (_modulaser)
      {
        TPrintrow& r = head.row(j);
        if (!_GiaMessoStartDoc)
          put_modulaser(r, STARTDOC);     
        put_modulaser(r, STARTDITTA);
        put_modulaser(r, STARTPAGE, 1);
        pr.print(r);
        _RigaCorr++;
        r.reset();
        HEADER_PRIMA_NOPOS--;
      }
      if (!PaginaPosizionamento())
        fill_page(pr, HEADER_PRIMA_NOPOS);
    }             
    else
    {
    pr.print(head.row(j));
    _RigaCorr++;
    }
  }
  const int res = last_a - _ptrA;
  return res < 0 ? 0 : res;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//                                         STAMPA QUADRO F
//
/////////////////////////////////////////////////////////////////////////////////////////////

class TStampaQuadroF : public TStampaQuadro
{
  private:
    TQuadroF*   _form;
    TRelation*  _rel;
    TCursor*    _cur;
    
  protected:    
    virtual bool conta_tipi_per()    const { return FALSE; }
    virtual TDicForm* get_form()     const { return _form; }

    virtual TCursor*  get_cursor()   const { return _cur; }
    
    virtual bool user_create();
    virtual bool user_destroy();

  public:
    TStampaQuadroF(char livel) : TStampaQuadro("F", livel) { }
};

bool TStampaQuadroF::user_create()
{
  _form = new TQuadroF("77QF", quadro());

  _rel = new TRelation(LF_QUAF);          
  _rel->add(LF_RIGHEF,  "CODDITTA=CODDITTA");
  _rel->add(LF_NDITTE,  "CODDITTA=CODDITTA",              1, LF_QUAF);
  _rel->add(LF_ANAG,    "TIPOA=TIPOA|CODANAGR=CODANAGR",  1, LF_NDITTE, 116);
  _rel->add(LF_ANAGFIS, "CODANAGR=CODANAGR",              1, LF_ANAG, 118);    
  _rel->add(LF_COMUNI,  "COM=COMNASC",                    1, LF_ANAGFIS, 113); 
  _rel->add(LF_COMUNI,  "COM=COMRF(COMRES)",              1, LF_ANAG, 213); 
  _cur = new TCursor(_rel);

  return TRUE;
}

bool TStampaQuadroF::user_destroy()
{
  delete _cur;       
  delete _rel;
  delete _form;
  return TRUE;
}          

/////////////////////////////////////////////////////////////////////////////////
// Busta
/////////////////////////////////////////////////////////////////////////////////

class TBusta : public TDicForm
{
protected:  
  virtual bool print(const long codditta, const long, const long);
  virtual int   prima_riga(PaginaQuadro p) const;  
public:
  TBusta(const char* form, const char* quadro) : TDicForm(form, quadro) { }
  virtual ~TBusta() { } 
};      

bool get_alleg_730(const long codditta)
{
  TLocalisamfile base(LF_BASE);
  base.zero();
  base.put("CODDITTA",(long)codditta);
  if (base.read()==NOERR)
  {
    const long allegA=base.get_long("N730ALLA");
    const long allegA2=base.get_long("N730ALLA2");
    return allegA || allegA2;
  }
  else
    return FALSE;
}

HIDDEN const int BUSTA_CON_POSIZ = 53;
HIDDEN const int BUSTA_SENZA_POSIZ = 56;

int TBusta::prima_riga(PaginaQuadro p) const
{
  return HEADER_PRIMA_NOPOS-1;
} 

bool TBusta::print(const long codditta, const long, const long)
{     
  const bool ok = InitPrint(codditta);
  if (ok)
  {   
    // Calcola identificatore del quadretto corrispondente al quadro L
    TForm_item& dietor = find_field('B', odd_page, 740);
    const int anno = anno_770();
    const bool elle = esiste_record_L(codditta, anno);
    dietor.set(elle ? "X" : "");
    TForm_item& all730 = find_field('B', odd_page, 20);
    const bool bAlleg730 = get_alleg_730(codditta); 
    all730.set(bAlleg730 ? "X" : "");    
                                         
    TPrinter& pr=printer();                                         
    TPrint_section& body = section('B', odd_page);
    const int body_righe = body.height();
    TCursor* cur=cursor();
    bool finito=FALSE;    
    (*cur)=0L; 
    pr.formlen(BUSTA_CON_POSIZ);
    if (!_PaginaPosizionamento)
      jump_to_line(pr,prima_riga(PRIMA));    
    while (!finito)   
    {
      body.reset();
      body.update();       
      for (int i=0; i < body_righe; i++)
      {
        pr.print(body.row(i));
        _RigaCorr++;
      }
      if (usa_progind())
        progind()->addstatus(1);
      ++(*cur);               
      finito= cur->pos() >= cur->items()-1;  
      pr.formlen(BUSTA_SENZA_POSIZ);
      _PaginaPosizionamento=FALSE;      
    }
  }  
  return ok;  
}

class TStampaBusta : public TStampaQuadro
{ 
  TDicForm* _form;

protected:  // TStampaQuadro  
  virtual bool user_create();
  virtual bool user_destroy();
  virtual bool conta_tipi_per() const { return FALSE; }  
  virtual TDicForm* get_form() const { return _form; }
  virtual TCursor* get_cursor() const { return _form->TForm::cursor(); }
  virtual bool print_quadro(const int OffsetDitta, const bool modulaser);

public:
  TStampaBusta(const char* quadro, char livel);
  virtual ~TStampaBusta() { }
};

TStampaBusta::TStampaBusta(const char* quadro, char livel) 
            : TStampaQuadro(quadro, livel), _form(NULL)
{ 
  set_taitol("Stampa buste"); 
}

bool TStampaBusta::user_create()
{
  _form = new TBusta("77Busta", quadro());
  return TRUE;
}

bool TStampaBusta::user_destroy()
{
  delete _form;
  _form = NULL;
  return TRUE;
}

bool TStampaBusta::print_quadro(const int OffsetDitta, const bool modulaser)
{
  TDicForm* ff = get_form();
  ff->set_cursor(get_cursor());

// Setta formlen prima di printer.open per avere la lunghezza giusta nel caso di stampa a video     
  printer().formlen(ff->height());               
  bool ok = printer().open();

  ff->set_modulaser(modulaser);
  
  ff->set_arrange(FALSE);
  ff->set_posiziona(TRUE);
    
  int start = 0, last = 0;
  if (OffsetDitta >= 0)
  {
    start = OffsetDitta;
    last = OffsetDitta;  
  }
  else
    last = ditte().items() - 1;
    
  for (int i = start; i <= last; i++)
  {
    TToken_string& riga  = ditte()[i];
    const long codditta  = riga.get_long(0);
    const TipoDitta tipo = (TipoDitta)riga.get_int();
    if (tipo != estinto)
      ff->print(codditta, 0, 0);
  }                       
  
  printer().close();
  return ok;
}

///////////////////////////////////////////////////////////////////////////////////////////
//
// BASE
//
///////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////
//
//  MAIN
//
//  Uso:
//         772mod -4 [QUADRO] [ LIVELLO {S|D} ]
//
/////////////////////////////////////////////////////////////////////////////////
int stampa_quadro(int argc, char* argv[])
{
  if (argc >= 4)
  {
    const TFixed_string quadro(argv[2]);
    const char livello = *argv[3];
    
    TStampaQuadro* app = NULL;

    if ( quadro == "C" )
    {
      app = new TStampaQuadroC(quadro, livello);
    }
    else if ( quadro == "D" )
    {
      app = new TStampaQuadroD(quadro, livello);
    }    
    else if (quadro == "D1")
    {
      app = new TStampaQuadroD1(quadro, livello);
    }
    else if (quadro[0] == 'A')
    {                        
      switch (quadro[1] - '0')
      {
      case  1: app = new TStampaQuadroA1(quadro, livello); break; 
      case  2: app = new TStampaQuadroA2(quadro, livello); break; 
      case  3: app = new TStampaQuadroA3(quadro, livello); break;
      default: app = new TStampaQuadroA(quadro, livello);  break;
      }  
    }                      
    else if (quadro[0] == 'B' && quadro[1] != 'a')
    { 
      switch (toupper(quadro[1]))
      {
      case 'U': app = new TStampaBusta(quadro, livello); break;
      default : app = new TStampaQuadroB(quadro, livello); break;
      }
    }
    else if (quadro == "F")
    {
      app = new TStampaQuadroF(livello);    
    }
    else if (quadro == "G")
    {
      app = new TStampaQuadroG(livello);    
    }
    else if (quadro == "G1")
    {
      app = new TStampaQuadroG1(livello);    
    }
    else if (quadro == "J")
    {
      app = new TStampaQuadroGAgg("G aggiuntivo", livello);    
    }
    else if (quadro == "Base")      
    {
      app = new TStampaBase(livello);
    }
    else if (quadro == "H")
    {
      app = new TStampaQuadroH(quadro, livello);    
    }
    else if (quadro == "L")
    {
      app = new TStampaQuadroAggL(quadro, livello);    
    }
    else if (quadro == "N")
    {
      app = new TStampaQuadroAggN(quadro, livello);    
    }
    else if (quadro == "S")
    {
      app = new TStampaAlleSoci("Allegato Soci", livello);    
    }

    if (app != NULL)
    {
      app->run(argc, argv, app->taitol());
      delete app;
    }  
  }
  
  return 0;
}
