//
//Lista fatture:
//  CG3 -6 C ==> Lista fatture per tipo costo/ricavo
//  CG3 -6 I ==> Lista fatture con iva indetrabile
//  CG3 -6 N ==> Lista fatture intracomunitarie
//
#include "cg3.h"
#include "cg3700a.h"
#include "cglib03.h"

#include <defmask.h>
#include <printapp.h>
#include <recarray.h>
#include <sheet.h>

#include <nditte.h>
#include <causali.h>
#include <clifo.h>
#include <mov.h>
#include <rmoviva.h>

class _Iva_item : public TObject
{ 
  real _impv,_ivav,_impa,_ivaa;

public:
  real& impv() { return _impv; } // Imponibile ven.
  real& ivav() { return _ivav; } // Iva ven.
  real& impa() { return _impa; } // Imponibile acq.
  real& ivaa() { return _ivaa; } // Iva acq.
  void zero()  { _impv = _ivav = _impa = _ivaa = ZERO; }
  virtual TObject* dup() const { return new _Iva_item(*this); }
  _Iva_item() { zero(); }  
  ~_Iva_item() { }
};

// Tipo di stampa
enum tipo_st
{ 
  indetraibile,
  costo_ricavo,
  intra
};

class TLista_fatture : public TPrintapp
{
  TRelation*    _rel;        // Relazione principale
  int           _cur1,
                _cur2,
                _cur3;       // Cursori della TPrintapp
  int           _tipodetprec,
                _tipocrprec; // Variabili per sapere quando stampare i totali parz.              
  long          _numregprec; // Per la stampa di piu' righe di uno stesso documento             
  tipo_st       _tipo;       // Tipo di stampa
  TArray_sheet* _ditte;      // Sheet di selezione ditte
  long          _unica_ditta;

  TAssoc_array  _intra_items;// Array ordinato (per codice IVA)  dei totali per fatture INTRA
  long          _from_cf,    // Estremi selezione clienti/fornitori
                _to_cf;
  TString4      _from_reg,   // Estremi selezione registri
                _to_reg,
                _from_cau,   // Estremi selezione causali
                _to_cau;
  TPrintrow     _pr;
  TString       _ragsoc;
  TDate         _date_from,
                _date_to;    // Estremi data
  real          _tot_doc,  //Non ha senso tenere il totale documenti visto che la stampa rappresenta le righe: 
                           //infatti uno stesso documento puo' comparire per piu' tipi indetraibilita' o tipi costo/ricavo diversi
                _tot_imp,
                _tot_iva,    // Totali complessivi della stampa
                _tp_doc,
                _tp_imp,
                _tp_iva;     // Totali parziali della stampa
  bool          _one_printed,
                _print_all;  // Flags per il controllo della stampa totali/parziali e righe multiple
                
  TString _tmp;
                
  static bool filter_func1(const TRelation *);   // Funzione di filtro per cursore 1
  static bool filter_func2(const TRelation *);   // Funzione di filtro per cursore 3
                
protected:
  long   select_firm_range(long from, long to);
  int    tiporeg(const TString& );
  static bool mix_handler(TMask_field&, KEY);
  static bool date_handler(TMask_field&, KEY);
  static bool to_ditt_handler(TMask_field&, KEY);
  static bool fr_ditt_handler(TMask_field&, KEY);
  static bool select_button(TMask_field&, KEY);
  static bool reset_button(TMask_field&, KEY);
  
  void reset_choices(TMask&);
  void set_choice_limits(TMask&);
  void build_ditte_sheet();
  virtual bool preprocess_page(int,int);
  virtual bool preprocess_print(int,int) { repeat_print();  return TRUE;} // Per stampare tutte le ditte in un unico botto
  virtual print_action postprocess_page(int,int)  {return NEXT_PAGE;}
  virtual print_action postprocess_print(int,int);
  void    set_the_header();
  virtual void set_page(int,int);
  virtual bool set_print(int);
  
  const char* real2string(const real& r, const char* pic = NULL)
  { real2currency(_tmp, r, pic); return _tmp; }

public:
  virtual bool user_create();
  virtual bool user_destroy();
  TArray_sheet* get_ditte_sheet() { return _ditte; }

  TLista_fatture() : _ditte(NULL) {}
  virtual ~TLista_fatture() {}
};

inline TLista_fatture& app() { return (TLista_fatture&) main_app(); }

int TLista_fatture::tiporeg(const TString& reg)
{
  TString8 s; s.format("%4d%-3s",_date_from.year(),(const char*)reg);
  return atoi(cache().get("REG", s, "I0"));
}

bool TLista_fatture::filter_func1(const TRelation *r) 
{
  TLista_fatture& a = app();
  const TRectype& mov = r->curr(LF_MOV);
  
  const TDate data = mov.get_date(MOV_DATAREG);
  if (data < a._date_from || data > a._date_to)
    return false;

  const TString& rg = mov.get(MOV_REG);  
  if (rg < a._from_reg || rg > a._to_reg)
    return false;
  
  const TRectype& riv = r->curr();
  if (a._tipo == indetraibile)
  {
    real percind;
    const int tipodet = get_tipodet_from_rmi(riv, mov, percind);
    if (tipodet == 0 || percind.is_zero())
      return false;
  
    const int tiporeg = a.tiporeg(rg);
    if (tiporeg != 2)
      return false;
  }
  else // Tipo costo/ricavo
  {
    if (riv.get_int(RMI_TIPOCR) == 0)
      return false;
  }  

  const long cod = mov.get_long(MOV_CODCF);
  const bool ok = cod >= a._from_cf && cod <= a._to_cf;
  return ok;
}

bool TLista_fatture::filter_func2(const TRelation *r) 
{
  const TLista_fatture& a = app();
  const TRectype& mov = r->curr(LF_MOV);
  
  const TDate data = mov.get_date(MOV_DATAREG);
  if (data < a._date_from || data > a._date_to)
    return false;
  
  const TString& cau = mov.get(MOV_CODCAUS);
  if (cau >= a._from_cau && cau <= a._to_cau)
  {
    const bool is_intra = r->lfile().get_bool(RMI_INTRA);
    return is_intra;
  }
  return false;
}

bool TLista_fatture::date_handler(TMask_field& f, KEY key)
{ 
  if ((key == K_TAB && f.focusdirty()) || key == K_ENTER)
  {
    TMask& m = f.mask();
    const TDate da(m.get_date(FLD_DATE_FROM));
    const TDate a(m.get_date(FLD_DATE_TO));

    if (da.ok())
      m.set(FLD_ANNO, da.year()); else
    if (a.ok())
      m.set(FLD_ANNO, a.year());

    if (a.ok() && da.ok()) // Solo se sono entrambi compilati
    {
      if (da > a)
        return f.error_box(TR("La data di fine deve essere maggiore della data di inizio."));
      if (da.year() != a.year())
        return f.error_box(TR("Le date devono appartenere allo stesso anno."));
    }
  }
  return TRUE;
}

bool TLista_fatture::mix_handler(TMask_field& f, KEY key)
{
  if (f.to_check(key))
  {
    TMask& m = f.mask();
    short dlg1 = f.dlg();
    short dlg2;
    
    if (dlg1 == FLD_TO_FOR) 
      dlg2 = FLD_FROM_FOR;
    else
      if (dlg1 == FLD_TO_REG)
        dlg2 = FLD_FROM_REG;
      else
        dlg2 = FLD_FROM_CAU;
    
    if (dlg1 == FLD_TO_FOR)
    {
      const long l1 = m.get_long(dlg1);
      const long l2 = m.get_long(dlg2);
      if (l1 != 0L && l2 != 0L && l1 < l2)
        return f.error_box(TR("Intervallo clienti/fornitori errato."));
      return TRUE;
    }
    
    const TString msg(dlg1 == FLD_TO_REG ? TR("Intervallo registri errato.") : TR("Intervallo causali errato."));
    const TString s1(m.get(dlg1));
    const TString s2(m.get(dlg2));
    if (s1.not_empty() && s2.not_empty() && s1 < s2)
      return f.error_box(msg);
    return TRUE;
  }
  return TRUE;
}

bool TLista_fatture::to_ditt_handler(TMask_field& f, KEY key)
{
  TMask& m = f.mask();
  if (key == K_F9)
  {
    TArray_sheet* sh = app().get_ditte_sheet();
    TMask& m = f.mask();
    
    sh->disable_check();
    sh->disable(DLG_USER);
    if (sh->run() == K_ENTER)
    {
      app().select_firm_range(m.get_long(FLD_DFR),sh->row(sh->selected()).get_long(1));
      app().set_choice_limits(m);
    }
    sh->enable(DLG_USER);
  }
  if (key == K_TAB && f.focusdirty())
  {
    app().select_firm_range(m.get_long(FLD_DFR), m.get_long(FLD_DTO));
    app().set_choice_limits(m);
  }
  return TRUE;
}

bool TLista_fatture::fr_ditt_handler(TMask_field& f, KEY key)
{                          
  TMask& m = f.mask();
  if (key == K_F9)
  {
    TMask& m = f.mask();
    TArray_sheet* sh = app().get_ditte_sheet();

    sh->disable_check();    
    sh->disable(DLG_USER);
    if (sh->run() == K_ENTER)
    {
      app().select_firm_range(sh->row(sh->selected()).get_long(1), m.get_long(FLD_DTO));
      app().set_choice_limits(m);
    }
    sh->enable(DLG_USER);
 }
  else if (key == K_TAB && f.focusdirty())
  {
    app().select_firm_range(m.get_long(FLD_DFR), m.get_long(FLD_DTO));
    app().set_choice_limits(m);
  }
  return TRUE;
}

long TLista_fatture::select_firm_range(long from, long to)
{
  if (to == 0l) to = 99999L;                              
  
  for (int i = 0; i < _ditte->items(); i++)
  {
    if (_ditte->row_disabled(i))
      continue;

    TToken_string& d = _ditte->row(i);

    const long cod = d.get_long(1);
    if (cod >= from && cod <= to)
      _ditte->check(i);
    else 
      _ditte->uncheck(i);
  } 
  
  return _ditte->checked();
}

bool TLista_fatture::select_button(TMask_field& f, KEY key)
{
  if (key == K_SPACE)
  {
    app()._ditte->enable_check();
    if (app()._ditte->run() == K_ENTER)
      app().set_choice_limits(f.mask());
  }
  return TRUE;
}

bool TLista_fatture::reset_button(TMask_field& f, KEY key)
{
  if (key == K_SPACE)
    app().reset_choices(f.mask());
  return TRUE;
}

void TLista_fatture::reset_choices(TMask& m)
{
  m.reset(FLD_SELECTED);
  m.reset(FLD_DFR);
  m.reset(FLD_DTO);
  m.disable(DLG_PRINT);
  _ditte->check(-1, false);
}

void TLista_fatture::set_choice_limits(TMask& m)
{     
  long first = -1l, last = -1l;
  const long items = _ditte->items();
  for (int i = 0; i < items; i++)
  {
    if (_ditte->checked(i))
    {
      const long dit = _ditte->row(i).get_long(1);
      if (first == -1l) first = dit;
      if (last < dit)   last  = dit;
    }
  }
  if (first != -1) 
    m.set(FLD_DFR, first);
  if (last  != -1)
    m.set(FLD_DTO, last);
  const long checked = _ditte->checked();
  m.enable(DLG_PRINT,checked > 0);
  m.set(FLD_SELECTED, checked);
}

void TLista_fatture::build_ditte_sheet()
{
  _ditte->destroy();

  long first_enabled = 0;
  long firms_enabled = 0;
  
  TLocalisamfile nditte(LF_NDITTE);
  for (int err = nditte.first(); err == NOERR; err = nditte.next())
  {
    TToken_string* d = new TToken_string(64);
    d->add(" ");
    const long n = nditte.get_long(NDT_CODDITTA);
    d->add(n);
    d->add(nditte.get(NDT_RAGSOC));
    
    const bool unselectable = !prefix().exist(n);
    
    const long pos = _ditte->add(d);     
    if (unselectable)
      _ditte->disable_row(pos);
    else
    {
      _ditte->enable_row(pos);
      if (firms_enabled++ == 0)
        first_enabled = pos;
    }
  }
  
  _unica_ditta = (firms_enabled == 1) ? first_enabled : -1; 
}

bool TLista_fatture::preprocess_page(int file, int counter)
{
  TCursor*  curs = current_cursor();
  const TRectype& rec  = curs->curr();
  const TRectype& mov = curs->curr(LF_MOV);
  _ragsoc = curs->curr(LF_CLIFO).get(CLI_RAGSOC);
  _ragsoc.strip_double_spaces();
  real percind;
  const int tipodet = get_tipodet_from_rmi(rec, mov, percind);
  if (_tipo == indetraibile && percind < CENTO)
  {
    const int dec = TCurrency::get_firm_dec();
    real imponibile = rec.get_real(RMI_IMPONIBILE) * percind / CENTO; imponibile.round(dec);
    real imposta    = rec.get_real(RMI_IMPOSTA) * percind / CENTO; imposta.round(dec);
    ((TRectype&)rec).put(RMI_IMPONIBILE, imponibile);
    ((TRectype&)rec).put(RMI_IMPOSTA, imposta);
  }

  const int tipocr  = rec.get_int(RMI_TIPOCR);
  const long numreg = rec.get_long(RMI_NUMREG);
  
  if (_tipodetprec == -1)  _tipodetprec = tipodet;
  if (_tipocrprec  == -1)  _tipocrprec  = tipocr;
  
  const bool new_det = (_tipo == indetraibile && tipodet != _tipodetprec);
  const bool new_cr  = (_tipo == costo_ricavo && tipocr != _tipocrprec);
  if (new_det || new_cr) // Stampa totali parziali
  {
    const bool is_cr = _tipo == costo_ricavo;
    TString256 s(TR("TOTALE TIPO "));
    _pr.reset();
    _pr.set_style(boldstyle);
    s << (is_cr ? TR("COSTO/RICAVO ") : TR("INDETRAIBILITA' "));
    s << (is_cr ? _tipocrprec : _tipodetprec);
    _pr.put(s,42);
    if (_tp_doc != 0.0)
      _pr.put(real2string(_tp_doc),73);
    if (_tp_imp != 0.0)
      _pr.put(real2string(_tp_imp),89);
    if (_tp_iva != 0.0)
      _pr.put(real2string(_tp_iva),112);
    printer().print(_pr);
    _pr.reset();
    printer().print(_pr);
    _tipodetprec = tipodet;
    _tipocrprec  = tipocr;
    _tp_doc = 0.0; _tp_imp = 0.0; _tp_iva = 0.0;
  }
  
  real doc = mov.get_real(MOV_TOTDOC);
  real imp = rec.get_real(RMI_IMPONIBILE);
  real iva = rec.get_real(RMI_IMPOSTA);
  if (_tipo == intra)
  {
    TString4 codiva  = rec.get(RMI_CODIVA);
    const int tipomov = tiporeg(mov.get(MOV_REG));
    if (tipomov == 2 && tipodet == 9)
      codiva = "~A19"; // Speciale per acquisti indeducibili art. 19
    const bool is_key = _intra_items.is_key(codiva); // Esiste l'elemento ?
    // Se si' allora prendi quello, altrimenti prendine uno nuovo
    _Iva_item newiva;
    _Iva_item& xiva = (is_key ? (_Iva_item&) _intra_items[codiva] : newiva);
    // Somma imponibile/imposta per vendite/acquisti
    if (tipomov == 1) //vendite
    {
      xiva.impv() += imp;
      xiva.ivav() += iva;
    }
    else // acquisti
    {
      xiva.impa() += imp;
      xiva.ivaa() += iva;
    }
    _intra_items.add(codiva,xiva,is_key); 
  }
  else
  {
    _tot_imp += imp;
    _tot_iva += iva;
    _tp_imp  += imp;
    _tp_iva  += iva;
  }

  const bool same_reg = numreg == _numregprec;
  if (same_reg && !new_det && !new_cr) // Se sta stampando un'altra riga di uno stesso documento,
  {                                    // cambia il formato di stampa delle righe
    _print_all = false;
    reset_print();
    set_page(0,0);    // Ignore parameters passed
  }
  else
  {
    if (_tipo != intra)
    {
      _tot_doc += doc;
      _tp_doc  += doc;
    }
    _print_all = TRUE;
    reset_print();
    set_page(0,0);    // Ignore parameters passed
  }
  _numregprec = numreg;
  
  if (!_one_printed) 
    _one_printed = TRUE;
  return TRUE;
}

print_action TLista_fatture::postprocess_print(int file, int counter)
{
  TPrinter& p = printer();
  if (_one_printed)
    if (_tipo != intra)
    {
      const bool is_cr = _tipo == costo_ricavo;
      TString256 s(TR("TOTALE TIPO "));
      _pr.reset();
      _pr.set_style(boldstyle);
      s << (is_cr ? TR("COSTO/RICAVO ") : TR("INDETRAIBILITA' "));
      s << (is_cr ? _tipocrprec : _tipodetprec);
      _pr.put(s,42);
      if (_tp_doc != 0.0)
        _pr.put(real2string(_tp_doc),73);
      if (_tp_imp != 0.0)
        _pr.put(real2string(_tp_imp),89);
      if (_tp_iva != 0.0)
        _pr.put(real2string(_tp_iva),112);
      p.print(_pr);
      _pr.reset();
      p.print(_pr);

      if (!is_cr)
      {
        p.print(_pr);
        _pr.set_style(boldstyle);
        _pr.put(TR("TOTALE GENERALE             :"),42);
        if (_tot_doc != 0.0)
          _pr.put(real2string(_tot_doc),73);
        if (_tot_imp != 0.0)
          _pr.put(real2string(_tot_imp),89);
        if (_tot_iva != 0.0)
          _pr.put(real2string(_tot_iva),112);
        p.print(_pr);
      }
    }
    else
    {
      // Stampa gli elementi di _intra_items
      real tot1,tot2,tot3,tot4;
      TString16 cod;
      TString80 des;
      _Iva_item * xiva; // Scorre gli elementi memorizzati

      _pr.reset();
      for (int i=0; i<3; i++)
        p.print(_pr);
      _pr.put(FR("Cod.@57gVENDITE@92gACQUISTI"),1);
      p.print(_pr);
      _pr.reset();
      _pr.put(FR("IVA  Descrizione@45gImponibile@66gImposta@82gImponibile@101gImposta"),1);
      p.print(_pr);
      _pr.reset();
      p.print(_pr);
      
      for (xiva = (_Iva_item *) _intra_items.first_item(); xiva != NULL; xiva = (_Iva_item*)_intra_items.succ_item())
      {
        real& r1 = xiva->impv();
        real& r2 = xiva->ivav();
        real& r3 = xiva->impa();
        real& r4 = xiva->ivaa();
        cod = _intra_items.get_hashobj()->key();
        if (cod == "~A19")
        {
          p.print(_pr);
          _pr.put(TR("Totale "),1);
          if (tot1 != 0.0)
            _pr.put(real2string(tot1),40);
          if (tot2 != 0.0)
            _pr.put(real2string(tot2),58);
          if (tot3 != 0.0)
            _pr.put(real2string(tot3),77);
          if (tot4 != 0.0)
            _pr.put(real2string(tot4),93);
          p.print(_pr);
          _pr.reset();
          p.print(_pr);
          des = TR("Totale acquisti indeducibili per ART.19");
          _pr.put(des,1);
        }
        else
        {
          des = cache().get("%IVA", cod).get("S0");
          _pr.put(cod,1);  
          _pr.put(des,6);
        }
        if (r1 != 0.0)
          _pr.put(real2string(r1),40);
        if (r2 != 0.0)
          _pr.put(real2string(r2),58);
        if (r3 != 0.0)
          _pr.put(real2string(r3),77);
        if (r4 != 0.0)
          _pr.put(real2string(r4),93);
        tot1 += r1;
        tot2 += r2;
        tot3 += r3;
        tot4 += r4;
        p.print(_pr);
        _pr.reset();
      }
      p.print(_pr);
      _pr.put(TR("Totale Generale IVA"),1);
      if (tot1 != 0.0)
        _pr.put(real2string(tot1),40);
      if (tot2 != 0.0)
        _pr.put(real2string(tot2),58);
      if (tot3 != 0.0)
        _pr.put(real2string(tot3),77);
      if (tot4 != 0.0)
        _pr.put(real2string(tot4),93);
      p.print(_pr);
    }
  return NEXT_PAGE;
}

void TLista_fatture::set_the_header()
{ 
  int soh = 1;    
  const long firm = get_firm();

  reset_header ();
	const TRectype & nditte = cache().get(LF_NDITTE, firm);

  TDate today(TODAY);
  TString s(132), rw(132);
  TString16 s1,s2;
  s = nditte.get(NDT_RAGSOC);    
  s1 = _date_from.string();
  s2 = _date_to.string();
  char c[2]={'N','D'};

  set_header (soh++, FR("Ditta : %ld %s@100gData@106g%s  @123gPag. @#"),
             firm,  (const char *)s,  (const char *)today);
 
  s.format(FR("Dalla data %s  Alla data %s"),(const char*)s1,(const char*)s2);
  if (_tipo == indetraibile || _tipo == costo_ricavo)
  {
    s << FR("@45g Dal fornitore ");
    if (_from_cf == 0L && _to_cf == 999999L)
      s << TR(" Al fornitore");
    else
    {
      s << _from_cf;
      s << TR("  Al fornitore ");
      s << _to_cf;
    }
    s << FR("@94g Dal registro ");
    if (_from_reg.empty() && _to_reg == "~~~")
      s << TR(" Al registro");
    else
    {
      s << _from_reg;
      s << TR("  Al registro ");
      s << _to_reg;
    }
    if (_tipo == costo_ricavo)
    {
      set_header(soh++,FR("@50gLISTA FATTURE PER TIPO COSTO/RICAVO"));
      c[0] = 'C'; c[1] = 'R';
    }
    else
      set_header(soh++,FR("@50gLISTA FATTURE CON IVA INDETRAIBILE"));
  }
  else
  {
    set_header(soh++,FR("@50gLISTA FATTURE INTRACOMUNITARIE"));
    s << FR("@45g Dal c. causale ");
    if (_from_cau.empty() && _to_cau == "~~~")
      s << TR("  Al c. causale");
    else
    {
      s << _from_cau;
      s << TR("  Al codice causale ");
      s << _to_cau;
    }
  }
  
  set_header(soh++,s);    
  
  rw.fill('-');
  set_header(soh++, (const char *) rw);
  set_header(soh++, FR("@12gNum@21gDocumento@63gCod.@68gM@70gTipo@106gCod@110g%c@128gNum."),c[0]);
  set_header(soh++, FR("Data reg.@12gprot.@18gData@30gNumero@37gCodice@44gRagione sociale@63gReg.@68gL@70gDoc."
                       "@75gTot.documento@94gImponibile@106gIva@110g%c@118gImposta@128gReg."),c[1]);
  set_header(soh++, (const char *) rw);
    
  set_header(soh,"");
}

void TLista_fatture::set_page(int file, int counter)
{ 
  int nriga=1;
  set_the_header();

  if (_print_all)
  {
    set_row(nriga,"@ld@12g@5,rs@18g@ld@29g@7,rs",FLD(LF_MOV,MOV_DATAREG),FLD(LF_MOV,MOV_PROTIVA),
                                               FLD(LF_MOV,MOV_DATADOC),FLD(LF_MOV,MOV_NUMDOC));
    set_row(nriga,"@37g@6,rn@44g#-18.18t@63g@3s@67g@2,rn",FLD(LF_MOV,MOV_CODCF),&_ragsoc,FLD(LF_MOV,MOV_REG), FLD(LF_MOV,MOV_MESELIQ));
    set_row(nriga,"@70g@2s@73g@15n",FLD(LF_MOV,MOV_TIPODOC),FLD(LF_MOV,MOV_TOTDOC));
    set_row(nriga,"@125g@7,rn",FLD(LF_MOV,MOV_NUMREG));
  }
  set_row(nriga,"@89g@15n@105g@4,rs",FLD(LF_RMOVIVA,RMI_IMPONIBILE),FLD(LF_RMOVIVA,RMI_CODIVA));
  
  const bool cr = _tipo == costo_ricavo;
  if (cr)
    set_row(nriga,"@110g@1s",FLD(LF_RMOVIVA, RMI_TIPOCR));
  else
  {
    real percind;
    const int tipodet = get_tipodet_from_rmi(current_cursor()->curr(), current_cursor()->curr(LF_MOV), percind);
    set_row(nriga,"@110g%d", tipodet);
  }
  set_row(nriga,"@112g@15n",FLD(LF_RMOVIVA,RMI_IMPOSTA));
}

bool TLista_fatture::set_print(int m)
{
  TMask msk("cg3700a");
  msk.set_handler(FLD_DATE_FROM, date_handler);
  msk.set_handler(FLD_DATE_TO,   date_handler);
  msk.set_handler(FLD_FROM_FOR, mix_handler);
  msk.set_handler(FLD_TO_FOR, mix_handler);
  msk.set_handler(FLD_FROM_REG, mix_handler);
  msk.set_handler(FLD_TO_REG, mix_handler);
  msk.set_handler(FLD_FROM_CAU, mix_handler);
  msk.set_handler(FLD_TO_CAU, mix_handler);
  msk.set_handler(FLD_DTO,  to_ditt_handler);
  msk.set_handler(FLD_DFR,  fr_ditt_handler);
  msk.set_handler(BUT_SEL,  select_button);
  msk.set_handler(BUT_ANN,  reset_button);

  add_file(LF_RMOVIVA);
  set_real_picture("###.###.###.###");
  set_magic_currency(TRUE);

  if (_unica_ditta >= 0)
  {
    _ditte->check(_unica_ditta);
    set_choice_limits(msk);
  }
  
  switch (_tipo)
  {
    case costo_ricavo: 
      msk.set_caption(TR("Lista fatture per costo/ricavo"));
      msk.field(FLD_FROM_FOR).set_prompt(TR("Da cli./for. "));
      msk.field(FLD_TO_FOR).set_prompt(TR("A cli./for.  "));
      break;
    case intra: 
      msk.set_caption(TR("Lista fatture intracomunitarie"));
      msk.hide(-1);
      msk.show(-2);
      break;
    default:
      break;
  }
  while (msk.run() == K_ENTER)
  {
    _from_cf = msk.get_long(FLD_FROM_FOR);
    _to_cf   = msk.get_long(FLD_TO_FOR);
    if (_to_cf == 0L) 
      _to_cf = 999999L;
    _from_reg = msk.get(FLD_FROM_REG);
    _to_reg   = msk.get(FLD_TO_REG);
    if (_to_reg.empty())
      _to_reg = "~~~";
    _from_cau = msk.get(FLD_FROM_CAU);
    _to_cau   = msk.get(FLD_TO_CAU);
    if (_to_cau.empty())
      _to_cau = "~~~";
    _date_from = msk.get_date(FLD_DATE_FROM);
    _date_to   = msk.get_date(FLD_DATE_TO);

    int cur; // Seleziona il cursore corrente
    switch (_tipo)
    {
      case costo_ricavo:
        cur = _cur2;
        break;
      case intra:
        cur = _cur3;
        break;
      default:
        cur = _cur1;
        break;
    }  
    
    // Cosi' filtra il cursore ad ogni inizio stampa
    get_cursor(_cur1)->set_filterfunction(filter_func1,TRUE); // Cursore 1
    get_cursor(_cur2)->set_filterfunction(filter_func1,TRUE); // Cursore 2
    get_cursor(_cur3)->set_filterfunction(filter_func2,TRUE); // Cursore 3

    select_cursor(cur);
    
    // Salva la ditta corrente
    TPrefix& pref = prefix();
    const long save_firm = pref.get_codditta();
    
    // Ciclo sulle ditte slezionate
    const long items = _ditte->items();
    printer().open();
    for (int i = 0; i < items; i++)
    {  
      if (_ditte->checked(i))
      {
        _tipocrprec  = -1;
        _tipodetprec = -1;
        _numregprec  = -1L;
        _tot_doc = 0.0; 
        _tot_imp = 0.0; _tot_iva = 0.0;
        _tp_doc  = 0.0; _tp_imp  = 0.0; _tp_iva  = 0.0;
        _one_printed = false; _print_all = TRUE;
        pref.set_codditta(_ditte->row(i).get_long(1));
        if (get_cursor(cur)->items() > 0)
        {
          if (_tipo == intra)
            _intra_items.destroy(); // Azzera l'array dei totali per fatture intra
          print();
        }
      }
    }
    if (printer().isopen())
      printer().close();
      
    // Ripristina la ditta
    pref.set_codditta(save_firm);
    msk.reset();
  }
  return false;
}

bool TLista_fatture::user_create()
{
  _tipo = indetraibile;
  const int argc = TApplication::argc();
  if (argc > 2)
  {
    const char c = argv(2)[0];
    switch (c)
    {
      case 'C': _tipo = costo_ricavo;
        break;
      case 'N': _tipo = intra;
        break;
      default:
        break;
    }
  }
  _ditte  = new TArray_sheet(-1, -1, -4, -4, TR("Selezione Ditte"),
                             HR("@1|Cod.@5R|Ragione Sociale@50"));
  open_files(LF_NDITTE, LF_TAB, LF_TABCOM, 0);

  _rel = new TRelation(LF_RMOVIVA);
  _rel->add(LF_MOV,"NUMREG==NUMREG");
  _rel->add(LF_CAUSALI,"CODCAUS==CODCAUS",1,LF_MOV); // Relazione
  _rel->add(LF_CLIFO,"TIPOCF==TIPO|CODCF==CODCF",1,LF_MOV);
                         
  _cur1 = add_cursor(new TSorted_cursor(_rel,"TIPODET|23->DATAREG|NUMREG")); // Cursore valido per lista fatture con iva indetraibile
  _cur2 = add_cursor(new TSorted_cursor(_rel,"TIPOCR|23->DATAREG|NUMREG"));  // Cursore valido per lista fatture per tipo costo/ricavo
  _cur3 = add_cursor(new TCursor(_rel));                                     // Cursore valido per lista fatture intracomunitarie
  
  build_ditte_sheet();

  return TRUE;
}

bool TLista_fatture::user_destroy()
{
  if (_ditte)  delete _ditte;
  if (_rel)    delete _rel;
  return TRUE;
}

///////////////////////////////////////////////////////////
// Main
///////////////////////////////////////////////////////////

int cg3700(int argc, char* argv[])
{          
  TLista_fatture lf;
  lf.run(argc, argv, TR("Lista fatture"));
  return 0;
}