#include <applicat.h>
#include <config.h>
#include <currency.h>
#include <form.h>
#include <msksheet.h>
#include <printer.h>
#include <progind.h>
#include <recarray.h>
#include <tabutil.h>
#include <urldefid.h>
                                    
#include "../sc/scselect.h"
#include "../ve/velib.h"

#include <doc.h>

#include "sv1.h"
#include "sv1100a.h"

class TSchede_mask : public TSelection_mask
{       
  void init_sheet(short id);
  void ini2sheet(short id);
  void sheet2ini(short id);

protected:                                        
  static bool date_handler(TMask_field& f, KEY k);
  static bool num_handler(TMask_field& f, KEY k);
  static bool save_handler(TMask_field& f, KEY k);
  static bool sheet_notify(TSheet_field& s, int row, KEY k);
  static bool fieldname_handler(TMask_field& f, KEY k);
  static bool valuta_handler(TMask_field& f, KEY k);
  static bool realfield_handler(TMask_field& f, KEY k);
  static bool cambio_handler(TMask_field& f, KEY k);

public:
  void mask2ini();
  void ini2mask();

  TSchede_mask();
  virtual ~TSchede_mask() { }
};

bool TSchede_mask::date_handler(TMask_field& f, KEY k)
{         
  bool ok = true;
  if (f.to_check(k))
  {
    TMask& m = f.mask();
    const TDate fd(m.get(F_FROMDATE));
    const TDate td(m.get(F_TODATE));
    if (td.ok() && td < fd)
      ok = f.error_box(TR("La data finale deve seguire quella iniziale"));
  }
  return ok;
}

bool TSchede_mask::num_handler(TMask_field& f, KEY k)
{         
  bool ok = true;
  if (f.to_check(k))
  {
    TMask& m = f.mask();
    const TString& fn = m.get(F_FROMNUM);
    const TString& tn = m.get(F_TONUM);
    if (tn.not_empty() && tn < fn)
      ok = f.error_box(TR("La numerazione finale deve seguire quella iniziale"));
  }
  return ok;
}

bool TSchede_mask::valuta_handler(TMask_field& f, KEY key)
{
  if (key == K_TAB && f.to_check(key, true))
  {           
    TMask& m = f.mask();
    const TString& val = f.get();
    const bool full = val.not_empty() && val != TCurrency::get_firm_val();
    if (full)
    {   
      TEdit_field& dc = m.efield(F_DATACAMBIO);
      if (dc.empty())      // Inizializza data cambio se assente
      {
        const TDate oggi(TODAY);
        dc.set(oggi.string());
      }  

      if (f.focusdirty())
      {
        dc.set_dirty(); 
        dc.check(RUNNING_CHECK); // Forza ricerca cambio
        if (m.get(F_CAMBIO).empty())
        {      
          TCursor& cur = *dc.browse()->cursor();
          if (cur.items() == 0)  // Uso cambio standard
          {  
            const TRectype& rec = cache().get("%VAL", val);
            dc.set(rec.get("D0"));     
            m.set(F_CAMBIO, rec.get("S4"));
            m.set(F_CONTROEURO, rec.get("B1"));
          }
        }   
      }  
    }
    else
    {
      m.reset(F_DATACAMBIO); 
      m.reset(F_CAMBIO); 
      m.reset(F_CONTROEURO);
    }  
  }
  return true;
}

bool TSchede_mask::save_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {
    TSchede_mask& m = (TSchede_mask&)f.mask();
    m.mask2ini();
  }
  return true;
}

bool TSchede_mask::fieldname_handler(TMask_field& f, KEY k)
{
  if (f.to_check(k))
  {
    TSchede_mask& m = (TSchede_mask&)f.mask();
    TEdit_field& head = m.efield(S_HEAD);
    if (head.empty())
    {
      TParagraph_string para(m.get(S_DESCR), head.size());
      head.set(para.get(0));
    }
  }
  return true;
}

bool TSchede_mask::realfield_handler(TMask_field& f, KEY k)
{
  if (k == K_F9)
  {               
    TMask& m = f.mask();
    const TSheet_field& s = *m.get_sheet();
    TRelation rel(s.dlg() == F_SINTETICA ? LF_DOC : LF_RIGHEDOC);
    TRelation_description rd(rel);
    if (rd.choose_field(f.get()))
    {
      f.set(rd.field_name());
      TEdit_field& head = m.efield(S_HEAD);
      TParagraph_string para(rd.field_desc(), head.size());
      head.set(para.get(0));
      m.set(S_DESCR, rd.field_desc());
      if (rd.field_type() == _realfld)
      {
        const int decimals = rel.curr().ndec(rd.field_name());
        const int length   = rel.curr().length(rd.field_name());
        m.set(S_IMPORTO, (decimals <= 3 && length >= 6)? "X" : "");
      }
      else
        return f.error_box(TR("E' necessario selezionare un campo numerico."));
    }
  }
  return true;
}


bool TSchede_mask::sheet_notify(TSheet_field& s, int row, KEY k)
{           
  bool ok = true;
  switch(k)
  {       
  case K_INS:
    ok = s.items() < 8; // Posso aggiungere al massimo otto colonne di stampa
    break;
  case K_CTRL+K_INS:
    s.row(row) = "F";  // Proponi una formula
    break;
  default:
    break;
  }
  return ok;
}

void TSchede_mask::sheet2ini(short id)
{
  TSheet_field& sheet = sfield(id);
  TString_array& arr = sheet.rows_array();
  
  const char* field = id == F_SINTETICA ? "SynField" : "DetField";
  const char* head = id == F_SINTETICA ? "SynHead" : "DetHead";
  
  TConfig ini(CONFIG_STUDIO, "sv1100");
  for (int r = arr.last(); r >= 0; r--)
  {                       
    TToken_string& row = arr.row(r);
    ini.set(field, row.get(1), NULL, true, r);
    ini.set(head, row.get(), NULL, true, r);
  }
  ini.remove(field, arr.items());
  ini.remove(head, arr.items());
}

void TSchede_mask::ini2sheet(short id)
{
  TSheet_field& sheet = sfield(id);

  const char* field = id == F_SINTETICA ? "SynField" : "DetField";
  const char* head = id == F_SINTETICA ? "SynHead" : "DetHead";
  
  TRelation rel(id == F_SINTETICA ? LF_DOC : LF_RIGHEDOC);
  const TRectype& rec = rel.curr();
  TRelation_description rd(rel);
  
  TConfig ini(CONFIG_STUDIO, "sv1100");
  for (int r = 0; ; r++)
  {                       
    TString16 str = ini.get(field, NULL, r);
    if (str.not_empty())
    {                                   
      TToken_string& row = sheet.row(r);
      row = rec.exist(str) ? "C" : "F";
      row.add(str);
      row.add(ini.get(head, NULL, r));
      if (row[0] == 'C')
      {
        row.add(rd.get_field_description(str));
        if (rec.type(str) == _realfld)
          row.add(rec.ndec(str) <= 3 ? "X" : "");
      }
      else  
        sheet.check_row(r);
    }
    else
      break;
  }
}

void TSchede_mask::mask2ini()
{
  sheet2ini(F_SINTETICA);
  sheet2ini(F_DETTAGLIATA);
}

void TSchede_mask::ini2mask()
{
  ini2sheet(F_SINTETICA);
  ini2sheet(F_DETTAGLIATA);
}

void TSchede_mask::init_sheet(short id)
{
  TSheet_field& sheet = sfield(id);
  sheet.set_notify(sheet_notify);
  TMask& sm = sheet.sheet_mask();
  sm.set_handler(S_FIELD, fieldname_handler);
  sm.set_handler(S_REALFIELD, realfield_handler);
}

TSchede_mask::TSchede_mask()
            : TSelection_mask("sv1100a")
{ 
  set_handler(F_TODATE, date_handler);
  set_handler(F_TONUM, num_handler);
  set_handler(F_VALUTA, valuta_handler);
  set_handler(DLG_SAVEREC, save_handler);

  init_sheet(F_SINTETICA);
  init_sheet(F_DETTAGLIATA);
  
  ini2mask();
}

///////////////////////////////////////////////////////////
// TSchede_form
///////////////////////////////////////////////////////////

class TSchede_form : public TForm
{       
public:
  void init(const TSheet_field& sheet);
  void init_pictures(const TMask& msk);

  TSchede_form(const char* n);
  virtual ~TSchede_form() { }
};

TSchede_form::TSchede_form(const char* n)
            : TForm(n)
{
}

void TSchede_form::init(const TSheet_field& sheet)
{  
  TPrint_section& body = section('B', odd_page);
               
  TString_array& arr = sheet.rows_array();
  
  TString80 str;
  bool on = true;
  for (word r = 3; r < body.fields(); r++)
  {        
    const int riga = r-3;
    if (on)
    {
      if (riga < arr.items())
      {
        str = arr.row(riga).get(1);
        on = str.not_empty();
      }
      else
        on = false;  
    }
    TForm_item& item = body.field(r);
    if (!item.is_section())
    {
      item.show(on);
      if (on)
      {           
        str = arr.row(riga).get(2);
        if (str.blank())
          str = arr.row(riga).get(1);
        item.set_col_head(str);
      }
    }  
  }

  const TPrint_section& head = section('H', odd_page);
  const TPrint_section& foot = section('F', odd_page);
  
  const int hh = head.height();
  const int fh = foot.height();
  const int fl = printer().formlen();
  
  int rows[4];         // Righe orizzontali
  rows[0] = hh-2;      // Terzultima riga della testata
  rows[1] = hh;        // Ultima riga della testata
  rows[2] = fl-fh+1;   // Prima riga del footer
  rows[3] = 0;

  genera_fincatura(odd_page, rows[0], rows[2], rows);
  TForm::genera_intestazioni(odd_page, hh-1);
}

void TSchede_form::init_pictures(const TMask& msk)
{

  const TPrint_section& head = section('H', odd_page);
  const int hh = head.height();
  TForm::genera_intestazioni(odd_page, hh-1);
  
  const char tipo_stampa = msk.get(F_TIPO)[0];
  TSheet_field& sheet = msk.sfield(tipo_stampa == 'D' ? F_DETTAGLIATA : F_SINTETICA);
  const int imppos = sheet.cid2index(S_IMPORTO);
  const int rfpos  = sheet.cid2index(S_REALFIELD);
  const int ftpos  = sheet.cid2index(S_FIELDTYPE);
  
  TPrint_section& body = section('B', odd_page);
  const int campi = sheet.items()+2;
  
  const TCurrency valuta(ZERO, msk.get(F_VALUTA));
  
  TRectype rec(tipo_stampa == 'D' ? LF_RIGHEDOC : LF_DOC);

  TString16 pic;
  for (int c = 0; c < campi; c++)
  {
    TForm_item& fi = body.find_field(FF_FIRSTCOLUMN+c);
    bool importo = true;
    if (c > 1)
      importo = sheet.row(c-2).get_char(imppos) > ' ';      

    if (importo)
    {
      pic.format(".%d", valuta.decimals());
      fi.set_picture(pic);
    }  
    else
    { 
      if (c > 1 && sheet.row(c-2).get_char(ftpos) == 'C')
      {
        pic.format(".%d",rec.ndec(sheet.row(c-2).get(rfpos)));
        fi.set_picture(pic);
      }
    }
  }
}
 
///////////////////////////////////////////////////////////
// Main app
///////////////////////////////////////////////////////////

class TStampa_schede : public TSkeleton_application
{
  char _clifo;              // <C>lienti o <F>ornitori
  char _tipo;               // <D>ettagliata o <S>intetica
  char _sort;               // <F>attura o <A>rticolo
  char _prov;               // <P>rovvisori o <D>efinitivi
  bool _peragenti;          // Stampa per agenti
  bool _perageart;          // Stampa per agenti ma ordinata per Articolo, Cliente, documento
  bool _provvart;           // Stampa solo righe articolo con provvigione
  TString _curagente;       // Codice e descrizione agente corrente
  TDate _fromdate, _todate; // Date limite
  TString _fromnum, _tonum; // Numerazioni limite 
  TString _tipodoc;         // Tipo documento limite
  
  TArray _totali;           // Totali complessivi
  TArray _totriga;          // Totali di riga
  TArray _totage;           // Totali per agente
  long _progressivo;        // Numero progressivo di record per file di stampa  
  TString _lastkey;         // Ultima chiave del file di stampa temporaneo
  
  TSchede_mask* _mask;      // Mask di stampa
  TSchede_form* _form;      // Form di stampa
  
protected:
  virtual void main_loop();
  virtual bool create(); 
  virtual bool destroy();
  
protected:  
  void put_real(TRectype& tab, int index, real val, bool importo, const TExchange& fc, const TExchange& tc);
  void fill_key(TRectype& tab, const TDocumento& doc, const bool ageart = false);
  void fill_key(TRectype& tab, const TRiga_documento& rdoc, const bool ageart = false);
  static bool filtra_doc_per_stat(const TRelation* rel);

public:  
  // stampa un documento (stampa sintetica)
  bool fill_doc(TRectype& tab, const TDocumento& doc);
  // stampa una riga documento (stampa dettagliata)
  bool fill_rdoc(TRectype& tab, const TRiga_documento& rdoc, const bool ageart = false);
  void update_totriga(const TRectype& tab);
  void update_totage(const TRectype& tab);
  void fill_totriga(TRectype& tab);
  void fill_tot(TRectype& tab);
  void fill_totage(TRectype& tab);
  bool fill_codart(TRectype& tab);
  bool fill_codcli(TRectype& tab);
  bool write_tab(TLocalisamfile& tab) const;
  bool write_totali_per_articolo(TLocalisamfile& tab);
  bool write_artcli_descrizioni(TLocalisamfile& tab);
  
  bool stampa_clienti() const { return _clifo == 'C'; }
  bool stampa_fornitori() const { return _clifo == 'F'; }
  bool stampa_sintetica() const { return _tipo == 'S'; }
  bool stampa_dettagliata() const { return _tipo == 'D'; }
  bool stampa_per_articolo() const { return _sort == 'A'; }
  bool stampa_per_documento() const { return _sort == 'D'; }
  bool stampa_per_agente() const { return _peragenti; }
  bool stampa_per_ageart() const { return _perageart; }

  long clifo2index(TCursor_sheet& clifosheet, long codcf);
  bool raggruppa_articoli(TCursor& cur, TProgind* pi, bool last_clifo);
  bool stampa_clifo(TCursor& cur, const TString& ragsoc, bool last_clifo);
  bool stampa_selezione(TCursor& clifocur, const TSheet& clifosheet, const TString& filter);
};

void TStampa_schede::put_real(TRectype& tab, int index, real val, bool importo, 
                              const TExchange& fc, const TExchange& tc)
{
  char erre[4]; sprintf(erre, "R%d", index);
  if (importo)
  {
    TCurrency cur(val, fc);
    cur.change_value(tc);
    val = cur.get_num();
  }  
  tab.put(erre, val);
  
  // Se non � un importo, non va totalizzato (ad esempio le quantita...)
  if (importo)
  {
    real* r = (real*)_totali.objptr(index);
    if (r == NULL)
      _totali.add(val, index);
    else  
      *r += val;
  }    
}

void TStampa_schede::fill_key(TRectype& tab, const TDocumento& doc, const bool ageart)
{
  tab.zero();
  tab.put("COD", "PRN");
  
  const TCli_for& clifo = doc.clifor();
  tab.put("S8", clifo.tipo());
  tab.put("I8", clifo.codice());

  if (ageart)
    tab.put("S4", doc.get("CODAG"));
  
  TString16 str;
  TString80 key;
  
  if (ageart)
    key.format("%c%7ld", clifo.tipo(), clifo.codice());

  key << doc.data().string(ANSI);
  
  str = doc.numerazione(); str.left_just(4);
  key << str;
  
  str.format("%4d", doc.numero());
  key << str;
  
  tab.put("S0", key);       
  tab.put("CODTAB", ++_progressivo);
}

void TStampa_schede::fill_key(TRectype& tab, const TRiga_documento& rdoc, const bool ageart)
{ 
  fill_key(tab, rdoc.doc(), ageart);
  
  _lastkey = tab.get("S0");
  
  _lastkey.left_just(20);
  if (stampa_per_articolo() || ageart)
  {
    TString80 str = rdoc.get(RDOC_CODART);
    str.left_just(20);
    _lastkey.insert(str, 0);
  }  
  
  TString16 numero;
  numero.format("%4d", rdoc.numero());
  
  _lastkey << numero;
  tab.put("S0", _lastkey);
}

bool TStampa_schede::fill_doc(TRectype& tab, const TDocumento& doc)
{   
  if (stampa_dettagliata())
    return false;
  const TTipo_documento& tipo = doc.tipo();
  if (!tipo.statistiche()) // documento non abilitato per le statistiche
    return false;
  
  // Codice valuta del documento
  const TExchange fc(doc.head());
  
  // Codice valuta di stampa
  const TString& codval = _mask->get(F_VALUTA);
  const real cambio = _mask->get(F_CAMBIO);
  const exchange_type tipocambio = _mask->get_bool(F_CONTROEURO) ? _exchange_contro : _exchange_base;
  const TExchange tc(codval, cambio, tipocambio);

  fill_key(tab, doc);
  
  TString descr(80);
  
  const TCodice_numerazione& num = doc.codice_numerazione();
  
  descr << tipo.descrizione() << ' ';
  descr << num.prefisso();
  descr << doc.numero();
  descr << num.postfisso();
  descr << " del " << doc.data();
  tab.put("S1", descr);

  const bool is_nota_credito = doc.tipo().nota_credito();
  real bs = doc.basesconto();
  real td = doc.totale_doc();

  if (is_nota_credito)
  {
    bs = -bs;
    td = -td;
  }
  
  put_real(tab, 0, bs, true, fc, tc);
  put_real(tab, 1, td, true, fc, tc);
  
  TSheet_field& sheet = _mask->sfield(F_SINTETICA);
  const int fldpos = sheet.cid2index(S_FIELD);
  const int imppos = sheet.cid2index(S_IMPORTO);

  TString_array& arr = sheet.rows_array();
  TString16 src;
  for (int r = 0; r < arr.items(); r++)
  {
    TToken_string& row = arr.row(r);
    src = row.get(fldpos);
    if (src.blank())
      break;
    const bool importo = row.get_char(imppos) > ' ';
    real val = doc.get(src);

    if (is_nota_credito)
      val = -val;

    put_real(tab, r+2, val, importo, fc, tc);
  }
  return true;
}

bool TStampa_schede::fill_rdoc(TRectype& tab, const TRiga_documento& rdoc, const bool ageart)
{   
  if (stampa_sintetica())
    return false;
    
  switch(rdoc.tipo().tipo())
  {
    case RIGA_MERCE      : break;
    case RIGA_OMAGGI     : break;
    case RIGA_PRESTAZIONI: break;
    default              : return false;
  }
  
  const TDocumento& doc = rdoc.doc();
  const TTipo_documento& tipo = doc.tipo();
  if (!tipo.statistiche()) // documento non abilitato per le statistiche
    return false;
  
  // Codice valuta del documento
  const TExchange fc(doc.head());
  
  // Codice valuta di stampa
  const TString& codval = _mask->get(F_VALUTA);
  const real cambio = _mask->get(F_CAMBIO);
  const exchange_type tipocambio = _mask->get_bool(F_CONTROEURO) ? _exchange_contro : _exchange_base;
  const TExchange tc(codval, cambio, tipocambio);
  
  fill_key(tab, rdoc, ageart);
                     
  TString descr(80);
  
  if (ageart)
  {
    descr << TR("*** Doc.") << doc.numerazione();
    descr << '/' << doc.numero();
    descr << TR(" del ") << doc.data();
  }
  else
  {
    if (stampa_per_articolo())
    {
      descr << doc.numerazione();
      descr << ' ' << doc.numero();
      descr  << "," << doc.data();
      descr << ':' << rdoc.get(RDOC_DESCR);
    } else {
      descr << rdoc.get(RDOC_CODART) << ' ';
      descr << rdoc.get(RDOC_DESCR);
    }
  }
  descr.cut(50);
  tab.put("S1", descr);                       

  const bool is_nota_credito = doc.tipo().nota_credito();
  real  ins =  rdoc.importo(true, false);
  real  ils =  rdoc.importo(true, true);

  if (is_nota_credito)
  {
    ins = -ins;
    ils = -ils;
  }
  
  put_real(tab, 0, ins, true, fc, tc); // importo netto scontato
  put_real(tab, 1, ils, true, fc, tc); // importo lordo scontato
  
  TSheet_field& sheet = _mask->sfield(F_DETTAGLIATA);
  TString_array& arr = sheet.rows_array();
  const int fldpos = sheet.cid2index(S_FIELD);
  const int imppos = sheet.cid2index(S_IMPORTO);
    
  TString16 src;
  for (int r = 0; r < arr.items(); r++)
  {
    TToken_string& row = arr.row(r);
    src = row.get(fldpos);
    if (src.blank())
      break;
  
    const bool importo = row.get_char(imppos) > ' ';
    real val = rdoc.get(src);
    if (is_nota_credito)
      val = -val;

    put_real(tab, r+2, val, importo, fc, tc);
  }
  
  return true;
}

void TStampa_schede::update_totriga(const TRectype& tab)
{           
  char erre[4];
  for (int r = _totali.last(); r >= 0; r--)
  {
    sprintf(erre, "R%d", r);
    const real val(tab.get(erre));
  
    real* tot = (real*)_totriga.objptr(r);
    if (tot == NULL)
      _totriga.add(val, r);
    else  
      *tot += val;
  }
}

void TStampa_schede::fill_totriga(TRectype& tab)
{
  TString80 descr;
  tab.zero();
  tab.put("COD", "PRN");
  tab.put("CODTAB", ++_progressivo);
  
  _lastkey.overwrite("9999", _lastkey.len()-4);
  tab.put("S0", _lastkey);       
  if (stampa_per_articolo())
  {
    descr= "Totale articolo " ;
    descr << _lastkey.left(20);
  } else {
    TDate ddoc;
    ddoc.set_year(atoi(_lastkey.left(4)));
    ddoc.set_month(atoi(_lastkey.mid(4,2)));
    ddoc.set_day(atoi(_lastkey.mid(6,2)));
    descr << TR("Totale documento ") << _lastkey.mid(8,4) ;
    descr << ' ' << atoi(_lastkey.mid(12,4));
    descr  << TR(" del ") << ddoc;
  }
  tab.put("S1", descr);
  tab.put("B8", true);          // Riga totale

  TSheet_field& sheet = _mask->sfield(stampa_dettagliata() ? F_DETTAGLIATA : F_SINTETICA);
  TString_array& arr = sheet.rows_array();
  const int imppos = sheet.cid2index(S_IMPORTO);
  
  for (int r = _totriga.last(); r >= 0; r--)
  { 
    const bool importo = r > 1 ? arr.row(r-2).get_char(imppos) > ' ' : true;

    char erre[4]; sprintf(erre, "R%d", r);
    tab.put(erre, importo ? (real&)_totriga[r] : ZERO);
  }
}

bool TStampa_schede::fill_codart(TRectype& tab)
{
  const TString codart = _lastkey.left(20);
  if (codart == "zzzzzzzz")
    return false;
  
  const TString codag = tab.get("S4");
  tab.zero();
  tab.put("COD", "PRN");
  tab.put("CODTAB", ++_progressivo);
  tab.put("S0", codart);
  
  TString s;
  s << "@B" << codart;
  s.trim();
  s << ' ' << cache().get(LF_ANAMAG, codart, "DESCR");
  tab.put("S1", s);
  tab.put("S4", codag); // Riporta il codice agente

  return true;
}

bool TStampa_schede::fill_codcli(TRectype& tab)
{
  TString s = _lastkey.left(28); // CODART + TIPOCF + CODCF
  const long c = atol(s.right(7));
  if (c <= 0)
    return false;

  const char t = s[20];

  TLocalisamfile& clifo = _form->relation()->lfile(LF_CLIFO);
  
  const TString codag = tab.get("S4");
  tab.zero();
  tab.put("COD", "PRN");
  tab.put("CODTAB", ++_progressivo);
  tab.put("S0", s);
  
  clifo.put("TIPOCF", t); clifo.put("CODCF", c);
  s = t=='C' ? TR("Cliente ") : TR("Fornitore ") ;

  s << c << " ";
  if (clifo.read() == NOERR)
    s << clifo.get("RAGSOC");
  s.strip_double_spaces();
  tab.put("S1", s);
  tab.put("S4", codag); // Riporta il codice agente

  return true;
}

void TStampa_schede::fill_tot(TRectype& tab)
{
  tab.zero();
  tab.put("COD", "PRN");
  tab.put("CODTAB", ++_progressivo);
  tab.put("S0", "yyyyyyyy");    // Si assicura che sia l'ultima prima dell'agente   
  tab.put("S1", TR("Totale"));                       
  tab.put("B8", true);          // Riga totale


  for (int r = _totali.last(); r >= 0; r--)
  { 
    const real* t = (const real*)_totali.objptr(r);
    char erre[4]; sprintf(erre, "R%d", r);
    tab.put(erre, t == NULL ? ZERO : *t);
  }
}

bool TStampa_schede::write_tab(TLocalisamfile& tab) const
{
  int err = tab.write();
  if (err != NOERR)
    error_box(FR("Errore %d durante la scrittura sul file temporaneo"), err);
  return err == NOERR;
}

bool TStampa_schede::write_totali_per_articolo(TLocalisamfile& tab)
{           
  bool ok = true;         
  TRectype& curtab = tab.curr();
  const TRecfield key(curtab, "S0");
  
  _lastkey.cut(0);
  _totriga.destroy();
  
  for (int err = tab.first(); err == NOERR && ok; err = tab.next())
  {
    if (_lastkey.not_empty() && _lastkey.compare((const char*)key, 20) != 0)
    {                             
      const TRecnotype pos = tab.recno();
      fill_totriga(curtab);        
      ok = write_tab(tab);
      tab.readat(pos);
      _totriga.destroy();
    }    
    _lastkey = (const char*)key;
    update_totriga(curtab);
  }
  
  if (ok && _lastkey.not_empty())
  {
    fill_totriga(curtab);
    ok = write_tab(tab);
  } 
  
  return ok; 
}

bool TStampa_schede::write_artcli_descrizioni(TLocalisamfile& tab)
{
  bool ok = true;         
  TRectype& curtab = tab.curr();
  const TRecfield key(curtab, "S0");
  const TRecfield art(curtab, "S0", 0, 19);
  TString last_art;
  
  _lastkey = "";

  for (int err = tab.first(); err == NOERR && ok; err = tab.next())
  {
    if (_lastkey.not_empty())
      if (_lastkey.compare((const char*)key, 28) != 0)  // Cambio articolo o cliente
      {
        const TRecnotype pos = tab.recno();
        if (last_art != (const char*)art)
        {
          if (fill_codart(curtab))
            ok = write_tab(tab);
        }
        // � per forza un cambio codcf
        if (fill_codcli(curtab))
          ok = write_tab(tab);
        tab.put("S0", _lastkey);
        if (tab.read() == NOERR)
        {
          tab.put("B8", true); 
          tab.rewrite();
        }
        tab.readat(pos);
      }
    _lastkey = (const char*)key;
    last_art = (const char*)art;
  }
  
  if (ok && _lastkey.not_empty())
  {
    tab.put("B8",true); tab.rewrite();
    if (fill_codart(curtab))
      ok = write_tab(tab);
    if (fill_codcli(curtab))
      ok = write_tab(tab);
  } 

  return ok;
}

void TStampa_schede::update_totage(const TRectype& tab)
{           
  char erre[4];
  for (int r = _totali.last(); r >= 0; r--)
  {
    sprintf(erre, "R%d", r);
    const real val(tab.get(erre));
  
    real* tot = (real*)_totage.objptr(r);
    if (tot == NULL)
      _totage.add(val, r);
    else  
      *tot += val;
  }
}

void TStampa_schede::fill_totage(TRectype& tab)
{
  tab.zero();
  tab.put("COD", "PRN");
  tab.put("CODTAB", ++_progressivo);
  
  TString80 descr;
  descr << TR("Totale Agente ") << _curagente;
  descr.cut(50);
  
  tab.put("S0", "zzzzzzzz");    // Mi assicuro che sia l'ultima riga   
  tab.put("S1", descr);
  tab.put("S4", _curagente.left(5));
  tab.put("B8", true);          // Riga totale

  TSheet_field& sheet = _mask->sfield(stampa_dettagliata() || stampa_per_ageart() ? F_DETTAGLIATA : F_SINTETICA);
  TString_array& arr = sheet.rows_array();
  const int imppos = sheet.cid2index(S_IMPORTO);

  for (int r = _totage.last(); r >= 0; r--)
  { 
    const bool importo = r > 1 ? arr.row(r-2).get_char(imppos) > ' ' : true;

    char erre[4]; sprintf(erre, "R%d", r);
    tab.put(erre, importo ? (real&)_totage[r] : ZERO);
  }
}

bool TStampa_schede::raggruppa_articoli(TCursor& cur, TProgind* pi, bool last_clifo)
{ 
  const long items = cur.items();
  
  cur.file().set_curr(new TDocumento);
  TDocumento& doc = (TDocumento&)cur.file().curr();
  
  TLocalisamfile& tab = _form->relation()->lfile();
  TRectype& curtab = tab.curr();

  bool can_print = true;
  bool has_money = false;
  
  // Scorre i documenti del cliente corrente
  for (cur = 0; cur.pos() < items && can_print; ++cur)
  {
    if (pi->iscancelled())
    {
      can_print = false;
      break;
    }  
    // Scorre le righe del documento corrente
    for (int r = doc.physical_rows(); r > 0 && can_print; r--)
    { 
      const TRiga_documento& rdoc = doc[r];
      if (rdoc.is_articolo())
      {                    
        bool fill = true;
        if (_provvart)
          fill = !rdoc.provvigione().is_zero();
        if (fill && fill_rdoc(curtab, rdoc, true))
        {
          can_print = write_tab(tab);
          if (can_print)
          {
            update_totage(curtab);
            has_money = true;
          }
        }    
      }
    }
  }

  if (can_print && last_clifo)
  {
    // Totale agente
    fill_totage(curtab);
    can_print = write_tab(tab);

    // Scrive le righe che mancano
    write_artcli_descrizioni(tab);
  }

  return can_print;
}

bool TStampa_schede::stampa_clifo(TCursor& cur, const TString& ragsoc, bool last_clifo)
{ 
  const long items = cur.items();
  
  TProgind* pi = NULL;
  if (items > 4)
  {
    TString header(160);
    header = TR("Preparazione file temporaneo di stampa ...");
    if (ragsoc.not_empty())
      header << '\n' << ragsoc;
    pi = new TProgind(items, header, true, true);
  }
    
  cur.file().set_curr(new TDocumento);
  TDocumento& doc = (TDocumento&)cur.file().curr();
    
  TIsamtempfile* tab = new TIsamtempfile(LF_TAB, "svschede", true,true);
  tab->setkey(2);
  _form->relation()->replace(tab);
  TRectype& curtab = tab->curr();
  
  _totali.destroy();
  _progressivo = 0;
    
  bool can_print = true;
  
  TForm_item& tit = _form->find_field('H',odd_page,FF_TITOLO);
  tit.set(stampa_clienti() ? TR("clienti") : TR("fornitori"));
  
  TForm_item& age = _form->find_field('H',odd_page,FF_AGENTE);
  if (stampa_per_agente())
  {
    age.show();
    age.set(_curagente);
  }
  else
    age.hide();
  
  for (cur = 0; cur.pos() < items && can_print; ++cur)
  {
    if (pi != NULL)
    {
      pi->addstatus(1);
      if (pi->iscancelled())
      {
        can_print = false;
        break;
      }  
    }
    
    if (stampa_sintetica())
    {
      if (fill_doc(curtab, doc))
      {
        can_print = write_tab(*tab);
        if (can_print && stampa_per_agente())
          update_totage(curtab);
      }
    }
    else
    {
      _totriga.destroy();
      for (int r = doc.physical_rows(); r > 0 && can_print; r--)
      { 
        const TRiga_documento& rdoc = doc[r];
        if (fill_rdoc(curtab, rdoc))
        {
          can_print = write_tab(*tab);
          if (can_print)
          {
            if (stampa_per_documento())
              update_totriga(curtab);
            if (stampa_per_agente())
              update_totage(curtab);
          }
        }  
      }
      
      if (can_print && _totriga.items() > 0)
      {
        fill_totriga(curtab);
        can_print = write_tab(*tab);   
      }  
    }  
  }
  
  if (can_print && tab->items() > 0)
  {  
    if (can_print && stampa_per_articolo())
      can_print = write_totali_per_articolo(*tab);
      
    if (can_print)
    {
      fill_tot(curtab);
      can_print = write_tab(*tab);
    }
    
    if (can_print && stampa_per_agente() && last_clifo)
    {
      fill_totage(curtab);
      can_print = write_tab(*tab);
    }
  }
  
  if (pi != NULL)
    delete pi;
  
  if (can_print && tab->items() > 0)
  {  
    TForm_item& col1 = _form->find_field('B',odd_page,FF_FIRSTCOLUMN);
    TForm_item& col2 = _form->find_field('B',odd_page,FF_SECONDCOLUMN);
    if (stampa_sintetica())
    {
      col1.set_col_head(TR("Base sconto"));
      col2.set_col_head(TR("Totale"));
    }
    else
    {
      col1.set_col_head(TR("Netto scontato"));
      col2.set_col_head(TR("Lordo scontato"));
    }
    
    _form->init_pictures(*_mask);
    _form->print();
  }

  _form->relation()->replace(new TLocalisamfile(LF_TAB));
  
  return can_print;
}    

bool TStampa_schede::filtra_doc_per_stat(const TRelation* rel)
{
  const TString16 tipodoc = rel->curr().get(DOC_TIPODOC);
  const TRectype& tipo = cache().get("%TIP", tipodoc);
  const bool stat = tipo.get_bool("B2");
  return stat;
}

bool TStampa_schede::stampa_selezione(TCursor& clifocur, const TSheet& clifosheet, 
                                      const TString& filter)
{
  const long clifos = clifosheet.items();
  long toprint = clifosheet.checked();
  if (toprint == 0) toprint = clifos;
  const bool all = toprint == clifos;
  const TRecnotype items = clifocur.items();
 
  TString ragsoc;
 
  TRelation rel(LF_DOC);
  TRectype rec(LF_DOC);
  
  bool cancel = false;
  TProgind *pi = NULL;
  
  // Inizializzazione solo per stampa agenti/articoli/clienti/documenti
  if (stampa_per_ageart())
  {
    TForm_item& tit = _form->find_field('H',odd_page,FF_TITOLO);
    tit.set(TR("agenti"));

    TString header;
    header = TR("Preparazione file temporaneo di stampa per l'agente: ");
    header << _curagente;
      
    pi = new TProgind(items, header, true, true);
    
    // Sostituisce il file principale  
    TIsamtempfile* tab = new TIsamtempfile(LF_TAB, "svschede", true,true);
    tab->setkey(2);
    _form->relation()->replace(tab);
    _progressivo = 0;
  }

//  printer().open(); // Spostata altrove
  for (clifocur = 0; clifocur.pos() < clifos && toprint > 0 && !cancel; ++clifocur)
  {  
    if (all || clifosheet.checked(clifocur.pos()))
    {
      const char tipocf = clifocur.curr().get_char(CLI_TIPOCF);
      const long codcf = clifocur.curr().get_long(CLI_CODCF);
      ragsoc = tipocf == 'C' ? TR("Cliente") : TR("Fornitore");
      ragsoc << ' ' << codcf << " - " << clifocur.file().get(CLI_RAGSOC);
          
      if (pi)
      {
        pi->addstatus(1L);
        if (pi->iscancelled())
        {
          cancel = true;
          break;
        }
      }
          
      rec.put(DOC_TIPOCF, tipocf);
      rec.put(DOC_CODCF, codcf);
      rec.put(DOC_PROVV, _prov);
      // Uso la chiave 2: TIPOCF+CODCF+PROVV+ANNO+DATADOC+CODNUM+NDOC
      TCursor cur(&rel, filter, 2, &rec, &rec);
      cur.set_filterfunction(filtra_doc_per_stat);
      const TRecnotype tot = cur.items();
      if (tot > 0)
      {            
        cur.freeze();
        if (stampa_per_ageart())
          cancel = !raggruppa_articoli(cur, pi, toprint == 1); 
        else
          cancel = !stampa_clifo(cur, ragsoc, toprint == 1);
        cur.freeze(false);
      }  
      toprint--;
    }  
  }

  
  // Stampa scheda agenti suddivisa per articoli/cliente/documento
  if (!cancel && stampa_per_ageart())
  {
    pi->setstatus(items);
    _form->init_pictures(*_mask);
    if (_form->cursor()->items() > 0)
      _form->print();
     // Necessario fare il replace per la stampa del prossimo agente  
     // In modo che venga automaticamente cancellato il precedente file temporaneo
    _form->relation()->replace(new TLocalisamfile(LF_TAB));
  }
//  printer().close(); Spostata altrove
  
  if (pi)
    delete pi;
  
  return !cancel;
}

long TStampa_schede::clifo2index(TCursor_sheet& clifosheet, long codcf) 
{          
  long i = -1;
  const int codpos = _mask->get_int(SC_SORTCF); // Posizione del codice clifo nello sheet
  if (codpos == 1)
  {                                           
    long a = 0;
    long b = clifosheet.items()-1;
    while (a <= b)
    {    
      i = (a+b)/2;
      const long clifo = clifosheet.row(i).get_long(codpos);
      if (clifo == codcf)
        break;
      if (clifo > codcf)  
        b = i-1;
      else
        a = i+1;  
    }
  }
  else
  {
    for (i = clifosheet.items()-1; i >= 0; i--)
    {
      TToken_string& row = clifosheet.row(i);
      long clifo = row.get_long(codpos);
      if (clifo == codcf)
        break;
    }
  }
  return i;
}

void TStampa_schede::main_loop()
{        
  TSchede_mask& m = *_mask;
  while (m.run() != K_QUIT)
  {                                        
    _clifo     = m.get(SC_CLIFO)[0];
    _tipo      = m.get(F_TIPO)[0];
    _sort      = m.get(F_ORDINE)[0];
    _prov      = m.get(F_PROVVIS)[0];
    _peragenti = m.get_bool(F_SORTAGENTI);
    _perageart = m.get_bool(F_SORTAGEART);
    _provvart  = m.get_bool(F_PROVVART);
    _fromdate  = m.get_date(F_FROMDATE);
    _todate    = m.get_date(F_TODATE);  
    _fromnum   = m.get(F_FROMNUM);
    _tonum     = m.get(F_TONUM);
    _tipodoc   = m.get(F_TIPODOC);

    _form = new TSchede_form(_perageart ? "sv1100b" : "sv1100a");
    
    _form->init(m.sfield(stampa_dettagliata() ? F_DETTAGLIATA : F_SINTETICA));
    
    TString filter(80); 
    if (_fromdate.ok())
    {
      if (filter.not_empty()) filter << "&&";
      filter << "(ANSI(" << DOC_DATADOC << ")>=\"" << _fromdate.string(ANSI) << "\")";
    }  
    if (_todate.ok() && _todate >= _fromdate)
    {
      if (filter.not_empty()) filter << "&&";
      filter << "(ANSI(" << DOC_DATADOC << ")<=\"" << _todate.string(ANSI) << "\")";
    }  
    if (_fromnum.not_empty() && _fromnum == _tonum)
    {
      if (filter.not_empty()) filter << "&&";
      filter << '(' << DOC_CODNUM << "==\"" << _fromnum << "\")";
    }
    else
    {
      if (_fromnum.not_empty())
      {
        if (filter.not_empty()) filter << "&&";
        filter << '(' << DOC_CODNUM << ">=\"" << _fromnum << "\")";
      }
      if (_tonum.not_empty() && _tonum >= _fromnum)
      {
        if (filter.not_empty()) filter << "&&";
        filter << '(' << DOC_CODNUM << "<=\"" << _tonum << "\")";
      }
    }
    if (_tipodoc.not_empty())
    {
      if (filter.not_empty()) filter << "&&";
      filter << '(' << DOC_TIPODOC << "==\"" << _tipodoc << "\")";
    }
    
    TCursor_sheet& clifosheet = m.cur_sheet();
    TCursor& clifocur = *clifosheet.cursor();

    const long clifos = clifocur.items();      
    long toprint = clifosheet.checked();
    const bool all = toprint == 0 || toprint == clifos;
    bool cancel = false;

    printer().open(); // Spostata da stampa_selezione
    if (stampa_per_agente())
    {   
      TRelation relagenti(LF_AGENTI);
      TRectype fromage(LF_AGENTI), toage(LF_AGENTI);
      if (m.get(F_DAAGENTE).not_empty())
        fromage.put(AGE_CODAGE, m.get(F_DAAGENTE));
      if (m.get(F_ADAGENTE).not_empty())
        toage.put(AGE_CODAGE, m.get(F_ADAGENTE));

      TCursor curagenti(&relagenti, "", 1, &fromage, &toage);
      const long ages = curagenti.items();
      curagenti.freeze();
      const TRectype& recagenti = curagenti.curr();
      
      // Crea la lista degli agenti da stampare
      TAssoc_array cia;

      TRectype darec(LF_DOC), arec(LF_DOC);

      int key = 0;
      TString filterage = filter;
      if (filterage.not_empty()) 
        filterage << "&&";
      filterage << '(' << DOC_CODAG << "!=\"\")";
      if (!m.field(F_DAAGENTE).empty())
        filterage << "&&(" << DOC_CODAG << ">=\"" << m.get(F_DAAGENTE) << "\")";
      if (!m.field(F_ADAGENTE).empty())
        filterage << "&&(" << DOC_CODAG << "<=\"" << m.get(F_ADAGENTE) << "\")";
  
      if (_fromdate.ok() || _todate.ok())
      {
        key = 3;
        filterage << "&&(" << DOC_TIPOCF << "=\"" << m.get_who() << "\")";
        if (_fromdate.ok())
          darec.put(DOC_DATADOC, _fromdate);
        if (_todate.ok())
          arec.put(DOC_DATADOC, _todate);
      }
      else
      {
        key = 2;
        darec.put(DOC_TIPOCF, m.get_who());
        arec.put(DOC_TIPOCF, m.get_who());
      }
      
      TRelation rel(LF_DOC);
      TCursor cur(&rel, filterage, key, &darec, &arec);
      cur.set_filterfunction(filtra_doc_per_stat);
      const TRectype& curdoc = cur.curr();

      const TRecnotype doc_items = cur.items();
      if (doc_items > 0)
      {
        TProgind pi(doc_items, TR("Selezione documenti"), TRUE, TRUE);

        cur.freeze();
        for (cur = 0L; cur.pos() < doc_items; ++cur)
        {
          pi.addstatus(1);
          if (pi.iscancelled())
          {
            cancel = true;
            break;
          }

          const TString& age = curdoc.get(DOC_CODAG);
          CHECK(age.not_empty(), "Agente nullo");
          TAssoc_array* sel = (TAssoc_array*)cia.objptr(age);
          if (sel == NULL)
          {
            sel = new TAssoc_array;
            cia.add(age, sel);
          }
          const TString& clifo = curdoc.get(DOC_CODCF);
          sel->add(clifo, clifo);
        }
      }
     
      for (curagenti = 0L; curagenti.pos() < ages && !cancel; ++curagenti)
      {  
        _curagente = recagenti.get(AGE_CODAGE);
        TAssoc_array* sel = (TAssoc_array*)cia.objptr(_curagente);
        if (sel != NULL)
        {
          _totage.destroy();  // Azzera totali agente

          clifosheet.uncheck(-1);
          FOR_EACH_ASSOC_STRING((*sel), h, k, s)
          {
            const long i = clifo2index(clifosheet, atol(k));
            if (i >= 0)
              clifosheet.check(i);
          }

          filterage = filter;
          if (filterage.not_empty())
            filterage << "&&";
          filterage << '(' << DOC_CODAG << "==\"" <<  _curagente << "\")";

          _curagente << ' ' << recagenti.get(AGE_RAGSOC);
          cancel = !stampa_selezione(clifocur, clifosheet, filterage);
        }
      }
    }
    else
    {
      _curagente.cut(0);
      if (all)
      {                        
        TString msg;
        msg.format(FR("Attenzione: e' stata selezionata la stampa di tutti i %s!\n"
                   "Si desidera continuare ugualmente?"), 
                   m.get_who() == 'C' ? TR("clienti") : TR("fornitori"));
        cancel = !yesno_box(msg);
      }
      
      if (!cancel)
        stampa_selezione(clifocur, clifosheet, filter);
    }
    printer().close(); // Spostata da stampa_selezione
    
    delete _form;
    _form = NULL;
  }        
}

bool TStampa_schede::create()
{                
  open_files(LF_DOC, LF_RIGHEDOC, LF_CONDV, LF_RCONDV, LF_ANAMAG, LF_SCONTI, LF_UMART, 
      LF_TAB, LF_TABCOM, LF_CLIFO,LF_CFVEN, LF_INDSP, LF_OCCAS, LF_MOVMAG, LF_RMOVMAG,LF_PROVV, 0);
  open_files(LF_SVRIEP,LF_SVSTAT,0);
  
  _mask = new TSchede_mask;
  
  return TSkeleton_application::create();
}

bool TStampa_schede::destroy()
{                  
  delete _mask;
  return true;
}

int sv1100(int argc, char* argv[])
{
  TStampa_schede app;
  app.run(argc, argv, TR("Stampa schede"));
  return 0;
}