// ba3200       Stampa tabelle
//
// legge un file con estensione .rpt che descrive la stampa.
// Vedi file leggimi.txt per il formato del file
//

#include <mask.h>
#include <printapp.h>
#include <utility.h>

#include <nditte.h>

#include "ba3.h"
#include "ba3200.h"

#define FOOTER_LEN 4  // se non ridefinito nel .rpt

class BA3200_application : public TPrintapp
{
  TString       _tabname;
  TFilename     _rptname;
  TRelation*    _rel;
  TCursor      *_cur;
  TMask*        _msk;
  TString       _maskname;
  int           _logicnum;
  TArray        _string_roman; 
  TArray        _field_roman; 
  bool          _stampa_registri;
  bool          _stampa_ca7; //tabella causali 770
  bool          _tabella_comune;
  
public:

  virtual bool user_create() ;
  virtual bool user_destroy() ;
  virtual bool set_print(int) ;

  virtual void set_page(int, int);
  virtual bool preprocess_page (int, int);
  virtual bool preprocess_print(int file, int counter);

  void set_headers();
  void set_rows();
  void set_footers();
  void set_translations();
  void set_relations();
  BA3200_application() {}
  virtual ~BA3200_application() {}
};


bool BA3200_application::set_print(int)
{
  TRectype from(_rel->lfile().curr()); from.zero();
  TRectype to  (from);
  
  if (_msk->run() == K_ENTER)
  {
    const int campi_maschera = _msk->fields(); 
    for (int i = 0; i < campi_maschera; i++)
    {
      const TMask_field& campo_maschera = _msk->fld(i);
      const char* val = campo_maschera.get();
      if (*val)
      {
        const TFieldref* campo_ref = campo_maschera.field();  

        if (campo_ref != NULL && campo_ref->ok())
        {                                                   
          TDate d;    
          const bool is_date_field = campo_maschera.class_id() == CLASS_DATE_FIELD;
          if (is_date_field) 
            d=val;
          if (campo_maschera.in_group(1)) campo_ref->write(is_date_field ? d.string(ANSI) : val, from);
          else
            if (campo_maschera.in_group(2)) campo_ref->write(is_date_field ? d.string(ANSI) : val, to);
        }  
      }
    }

    _cur->setregion (from, to);

    set_headers();
    return TRUE;
  }
  return FALSE;  
}

void BA3200_application::set_page (int , int )
{
  _string_roman.destroy();
  _field_roman.destroy();
  set_rows();
}

bool BA3200_application::preprocess_page(int , int)
{
  const int items = _field_roman.items();

  if (items > 0)
  {
    for (int i = 0; i < items; i++)
    {
      TString& fn  = (TString &) _field_roman[i];
      TFieldref fld(fn, 0);
      TString& s = (TString &) _string_roman[i];
      
      const int n = atoi(fld.read(_rel));
      s = itor(n);
    }
  }
  // Stampa tabella registri. Calcolo: pagine residue = pagine - stampate
  if (_stampa_registri)
  {
    const int pagine   = _cur->file().get_int("I2");
    const int stampate = _cur->file().get_int("I1");
    const int residue  = pagine - stampate;
    if (residue > 0)
      set_row(1, "@126g%4d", residue);
    else
      set_row(1, "@126g%4s", "    ");
  }
  return TRUE;
}

void BA3200_application::set_headers()
{
  TString        NomeTabella, sep, formato_intesta, testo_intesta;
  int            LungRiga, riga_intesta=0, last_riga=1;
  TToken_string  line;
  TString256     riga;
  
  reset_header ();

  TScanner rpt(_rptname);
  rpt.paragraph("Headers");

  // Leggo la lunghezza della riga (usata per centrare l'intestazione)
  line = rpt.line();
  LungRiga    = line.get_int();

  riga.spaces(LungRiga);
  // Senno' nella stampa a 80 non ci sta ditta e data

  // Leggo il nome della tabella
  line = rpt.line();
  NomeTabella = line.get();

  // Sulla prima riga di intestazione metto la ditta, la data e la pagina
  if (!_tabella_comune)
  {
    const long     codditta = get_firm();
    TString80      ragsoc;
    TLocalisamfile nditte(LF_NDITTE);

    nditte.zero();
    nditte.put(NDT_CODDITTA, codditta);
    if (nditte.read() == NOERR)
    {
      ragsoc = nditte.get(NDT_RAGSOC);
      if (LungRiga < 100) ragsoc.cut(40);
    }
    riga.overwrite(format("Ditta %4ld %s", codditta,(const char *)ragsoc));
  }
  
  if (_stampa_ca7) 
  {
    TDate d (_msk->get(F_DATASTAMPA));
    printer().setdate(d);
  }
  
  riga.overwrite ("Data @< Pag. @#", riga.len()-22);

  set_header (last_riga++, "%s", (const char *)riga);
  
  // Centro il nome della tabella
  // Per la stampa registri non va centrato. 
  // Lo lascio anche per le altre stampe 
  //  if (_stampa_registri)
  NomeTabella.left_just (LungRiga);
  /*  else
      NomeTabella.center_just (LungRiga); */
  if (_stampa_ca7) 
    NomeTabella.center_just (LungRiga); 

  set_header (last_riga++, "@b%s", (const char *)NomeTabella);

  // Aggiungo una riga vuota per separare prima intestazione
  //sep.fill ('-', LungRiga);
  //set_header (last_riga, "%s", (const char *)sep);

  line = rpt.line();
  while ( (line != "") && (line[0] != '[') )
  {
    riga_intesta    = atoi (line.get());        
    formato_intesta = line.get();
    testo_intesta   = (const char *) line.get();
    if (riga_intesta)
      set_header (last_riga+riga_intesta, (const char *)formato_intesta, 
                  (const char *)testo_intesta);
    line = rpt.line();
  }

  if (riga_intesta) last_riga += riga_intesta;
  last_riga++;
  
  //set_header (last_riga, (const char *)sep);
  sep.fill(' ');
  set_header (last_riga, (const char *)sep); 
  set_background(format("W2l{1,3,%d,3}l{1,%d,%d,%d}", LungRiga, last_riga, LungRiga, last_riga));
}

void BA3200_application::set_rows()
{
  TToken_string  line;
  TFieldref     campo;
  int           from, to, riga_record;
  TString       formato_campo, picture;
  const char *          name;

  TScanner rpt(_rptname);
  rpt.paragraph("Rows");

  line = rpt.line();
  while ( (line != "") && (line[0] != '[') )
  {
    riga_record = line.get_int();

    TString s(line.get());

    campo = s;
    from = campo.from();
    to = campo.to();
    name = campo.name();
    int logicnum = campo.file() == 0 ? _logicnum : campo.file();

    formato_campo = line.get();
    formato_campo.trim();
    formato_campo.lower();
    const int p = formato_campo.find("@m");
    
    if (p != -1)
    {
      formato_campo.cut(p);
      formato_campo << "#t";
      _string_roman.add(new TString);
      _field_roman.add(s);
      const int last = _string_roman.items() - 1;

      set_row (riga_record, formato_campo, _string_roman.objptr(last));
    }
    else
    {
      if (formato_campo.find("@pn"))
        picture = line.get();
      else
        picture = "";
      
      if (to == -1)
        if (picture != "")
          set_row (riga_record, formato_campo, FLD(logicnum,name,picture) );
        else
          set_row (riga_record, formato_campo, FLD(logicnum,name) );
      else
        set_row (riga_record, formato_campo, FLD(logicnum,name,from,to) );
    }

    line = (const char *) rpt.line();
  }
}

void BA3200_application::set_footers()
{
  TToken_string line;
  int     footer_len, riga;
  TString formato, testo;

  reset_footer();

  TScanner rpt(_rptname);
  rpt.paragraph("Footers");

  line = rpt.line();
  footer_len = line.get_int(); 
  if (footer_len != 0) 
  {
    printer().footerlen(footer_len);
    line = rpt.line();
  }  
  while ( (line != "") && (line[0] != '[') )
  {
    riga = line.get_int();
    formato = line.get();
    testo   = line.get();
    set_footer (riga, (const char *)formato, (const char*)testo);
    line = rpt.line();
  }
}

void BA3200_application::set_translations()
{
  TString campo, from, to;
  TToken_string line;
  int   logicnum;

  TScanner rpt(_rptname);
  rpt.paragraph("Translations");

  line = rpt.line();
  while ( (line != "") && (line[0] != '[') )
  {
    logicnum = line.get_int();
    campo    = line.get();
    from     = line.get();
    to       = line.get();
    set_translation (logicnum, (char*)(const char *)campo, (char*)(const char *)from, (char*)(const char *)to);
    line = rpt.line();
  }
}

void BA3200_application::set_relations()
{
  TToken_string line("", ';');
  TString tab(16), expr(40);
  int key, linkto, alias, logicnum;

  TScanner rpt(_rptname);
  rpt.paragraph("Relations");

  line = rpt.line();
  while ( (line != "") && (line[0] != '[') )
  {
    tab = line.get();
    logicnum = atoi(tab);
    expr = line.get();
    key = line.get_int();
    if (key == 0) key = 1;
    linkto = line.get_int();
    alias = line.get_int();
    if (logicnum > 0)
      _rel->add(logicnum, expr, key, linkto, alias);
    else
      _rel->add(tab, expr, key, linkto, alias);
    
    line = rpt.line();
  }
}
bool BA3200_application::user_create()
{
  _tabname = argv(2);

  TString16 t(_tabname);

  _tabella_comune = (t[0] == '%');
  if (_tabella_comune)
    t.ltrim(1);
  
  _rptname  << "batb" << t << ".rpt" ;
  if (!fexist(_rptname)) 
    return error_box("Impossibile aprire il file '%s'", (const char*)_rptname);

  // Flag per la stampa tabella registri
  _tabname.upper();
  _stampa_registri = (_tabname == "REG");
  _stampa_ca7 = (_tabname == "%CA7");
  
  _rel = new TRelation (_tabname);
  _cur = new TCursor (_rel);

  _maskname << "bast" << t;
  _msk = new TMask (_maskname) ;

  add_cursor (_cur);
  add_file (_tabname);

  _logicnum = _cur->file().num();

  reset_print ();

  printer().footerlen (FOOTER_LEN);
  for (int i=1; i <= FOOTER_LEN; i++) set_footer(i, "%s", "  ");

#ifdef DBG1
  set_fillchar ('.');
#endif
  set_relations();
  return TRUE;
}

bool BA3200_application::preprocess_print(int file, int counter)
{
  set_headers();
  set_footers();
  set_translations();
  return TRUE;
}                            

bool BA3200_application::user_destroy() 
{
  delete _msk;
  delete _cur;
  delete _rel;
  return TRUE;
}

int ba3200(int argc, char* argv[])
{
  BA3200_application a;
  a.run(argc, argv, "Stampa tabella");
  return 0;
}
