// ------------------------------------------------------------
// Calcolo liquidazioni
// Part 1: interfaccia
// fv 21-1-94
// ------------------------------------------------------------
                               
#include "cg4300.h"
#include "cg4300a.h"

#include <defmask.h> 
#include <recarray.h>                 
#include <mailbox.h>
#include <progind.h>
#include <sheet.h>

#include <mov.h>

// Methods of _Iva11Array
bool _Iva11Array::add(const real& val, const char* fld_name, int num_file)
{
  const bool is_key = TAssoc_array::is_key(fld_name);
  if (!is_key)
    TAssoc_array::add(fld_name,(_Iva11Item*)new _Iva11Item,is_key);
  _Iva11Item& bi = (_Iva11Item&)find(fld_name);
  bi.value() += val;
  if (num_file != LF_TAB1100A) 
    bi.file() = num_file;
  
  return true;
}

bool _Iva11Array::sub(const real& val, const char* fld_name, int num_file)
{
  const real v1 = val * (-1.0);
  return add(v1,fld_name, num_file);
}


void _Iva11Array::zero(const char* fld_name)
{
  const bool is_key = TAssoc_array::is_key(fld_name);
  if (!is_key)
    TAssoc_array::add(fld_name,(_Iva11Item*) new _Iva11Item,is_key);
  _Iva11Item& bi = (_Iva11Item&)find(fld_name);
  bi.value() = ZERO;
}

// Methods of _ProrataItem

// Calcola prorata con percentuale identificata dall'anno passato
// se la % prorata relativa all'anno indicato non esiste, ritorna 0
real _ProrataItem::calc_prorata(const real& acq, const char * year)
{
  real perc = _percentuali.objptr(year) ? (real&) *_percentuali.objptr(year) : ZERO;
  real prorata = (acq * perc) / CENTO;
  prorata.round(TCurrency::get_firm_dec());
  return prorata;
}

// Ritorna la % prorata relativa all'anno indicato. Se non esiste internamente
// viene ritornato INVALID_PRORATA
real _ProrataItem::percentuale(const char * year)
{
  real perc = _percentuali.objptr(year) ? (real&) *_percentuali.objptr(year) : INVALID_PRORATA;
  if (perc == ZERO) //Se la % prorata vale 0 la percentuale non e' valida
    perc = INVALID_PRORATA;
  return perc;
}

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

TLiquidazione_app::TLiquidazione_app(int m) :
_ditte(NULL), _selected(10000),
_year(4), _nomiditte(100), _menu(m), _firm_bookmark(-1)
{ 
  _isprint = _is_interactive = _canprint = true; 
  _isplafond = _printonly = _is_visliq = false; 
  _isvent = _isagricolo = _isbenzinaro = _isviaggio = _isdiff = false; 
  _row = 1;  _what = all; _comp_acconto = false; 
  _isriepilogo = FALSE; _calcall = false;
  _recalc_only = _recalc_regis = _isfinal = _isregis = false;     
  _stampa_vers = _stampa_acc = false;
  _recalc = needed;
}

bool TLiquidazione_app::user_create()
{                 
  // vediamo se c'e' il messaggio per calcolare in batch
  TMailbox mail;
  TProgind* pnd = NULL;
  TMessage* msg = mail.next_s("RCL");
  TToken_string subj(36);
  _is_interactive = msg == NULL;
  bool is_header = TRUE;
  int  bodylen;
  TDate   printdate;            
  TString filename;         
  long    ditta;
  bool    nocalc = FALSE;                             
  
  _prind = NULL;

  if (msg != NULL) subj = msg->body();  
  
  if (_is_interactive) 
    pnd = new TProgind (3,TR("Preparazione archivi\nPrego attendere"), 
                        FALSE, TRUE); 
  else begin_wait();

  _nditte = new TRelation(LF_NDITTE);
  _nditte->add(LF_ATTIV,"CODDITTA=CODDITTA");
  _nditte_r   = &(_nditte->curr());
  _att_r      = &(_nditte->curr(LF_ATTIV));

  _ditte  = new TArray_sheet(-1, -1, -4, -4, TR("Selezione Ditte"),
                             HR("@1|Cod.@5R|Ragione Sociale@50|Vers.|Agr.Min"));
  _n_ditte = 0l;    
  
  // Caro tab11, ricordati che un giorno sarai un file unico!
  _tab11 = new TRelation(LF_TAB1100A);
  _tab11->add(LF_TAB1100B,"TADITT=TADITT|TACATT=TACATT");
  _tab11->write_enable(LF_TAB1100B); // Senno' col fischio che scrive i records
  
  // prevediamo la data che usera'; se calcola la liq. di un altro anno
  // si fottera' la frequenza versamenti                      
  
  if (_is_interactive)
  {
    TDate oggi(TODAY);                    
    _year.format("%d",oggi.year());
    _month = oggi.month();
    TConfig conf(CONFIG_STUDIO);
    _sind11 = conf.get_bool("Sind11");
  }
  else // parse messaggio
  {
    _year       = subj.get(0);
    _month      = subj.get_int(1);
    ditta       = subj.get_long(2);  
    char rcl    = *(subj.get(3));
    _recalc_only  = rcl == 'C';
    _recalc_regis = rcl == 'R' && atoi(_year) > 1997;
    _is_visliq    = rcl == 'V';   
    // S/s =  stampa senza ricalcolo (minuscolo = definitivo)
    // L/l =  stampa con ricalcolo se necessario (minuscolo = definitivo)
    // C   =  solo ricalcolo
    // R   =  solo ricalcolo per registri: aggiorna solo progressivi PRM e PRP. Non fa niente altro ne write_liq() ne pim, ne stampe...
    // V   =  stampa ed ev. ricalcolo per visualizzazione
    // s o l minuscoli = registro bollato
    _isregis    = (rcl == 'l' || rcl == 'L' || 
                   rcl == 'S' || rcl == 's'); // stampa per registri    
    _isfinal    = rcl == 'l' || rcl == 's';   // se l minuscolo, definitivo 
    nocalc      = rcl == 'S' || rcl == 's';
    printdate   = subj.get(4);
    filename    = subj.get(5);
    char rliq   = *(subj.get(6)); 
    _riepilogo  = rliq == 'X';    
    bodylen     = subj.get_int(7);
    is_header   = subj.items() == 8;
    printer().formlen(bodylen); 
  }
  
  if(pnd) pnd->addstatus(1);
  
  _rel = new TRelation(LF_MOV);
  _rel->add(LF_RMOVIVA,"NUMREG=NUMREG");
  _rel->add(LF_PCON,"GRUPPO=GRUPPO|CONTO=CONTO",1,LF_RMOVIVA,AGR_PCON1);
  _rel->add(LF_PCON,"GRUPPO=GRUPPO|CONTO=CONTO|SOTTOCONTO=SOTTOCONTO",1,LF_RMOVIVA,AGR_PCON2);
  _rel->add(LF_CAUSALI,"CODCAUS=CODCAUS");

//  _cur = new TCursor(_rel, "", 2);
  _cur = new TCursor(_rel, "", 4);

  _ver        = new TInteressi_IVA_table();
  _pim        = new TTable("PIM");
  _pis        = new TTable("PIS");
  _prm        = new TTable("PRM");
  _prp        = new TTable("PRP");
  _pum        = new TTable("PUM"); 
  _pam        = new TTable("PAM"); 
  _pom        = new TTable("POM"); 
  _ppa        = new TTable("PPA"); 
  _plm        = new TTable("PLM"); 
  _pia        = new TTable("PIA"); 
  _lim        = new TTable("LIM");
  _lam        = new TTable("LAM");
  _pla        = new TTable("%PLA");  
  _reg        = new TTable("REG"); 
  _iva        = new TTable("%IVA");
  _del        = new TTable("%DEL");
  _lia        = new TTable("%LIA");
  
  _mov        = &_cur->file(LF_MOV); 
  _rmoviva    = &_cur->file(LF_RMOVIVA); 
  _pcon_1     = &_cur->file(-AGR_PCON1);
  _pcon_2     = &_cur->file(-AGR_PCON2);

  _pim_r      = &(_pim->curr());
  _pis_r      = &(_pis->curr());
  _prm_r      = &(_prm->curr());
  _prp_r      = &(_prp->curr());
  _plm_r      = &(_plm->curr());
  _pia_r      = &(_pia->curr());
  _pum_r      = &(_pum->curr());
  _pam_r      = &(_pam->curr());
  _pom_r      = &(_pom->curr());
  _iva_r      = &(_iva->curr());
  _del_r      = &(_del->curr());
  _lim_r      = &(_lim->curr());
  _lam_r      = &(_lam->curr());
  _pla_r      = &(_pla->curr());
  _ppa_r      = &(_ppa->curr());
  _reg_r      = &(_reg->curr());
  _mov_r      = &(_mov->curr());
  _rmoviva_r  = &(_cur->curr(LF_RMOVIVA));
  _pcon_1_r   = &(_cur->curr(-AGR_PCON1));
  _pcon_2_r   = &(_cur->curr(-AGR_PCON2));
  
  // ACHTUNG: tutti i _codatt (codici attivita') sono
  // in realta' composti dal codice attivita' piu' il
  // tipo attivita' (1 o 2)
  // sarebbe piu' saggio fare 2 campi ma ci vuole 1 vita

  _pim_anno    = new TRecfield(*_pim_r,"CODTAB",0,3);
  _pim_codatt  = new TRecfield(*_pim_r,"CODTAB",4,9);
  _pim_codreg  = new TRecfield(*_pim_r,"CODTAB",10,12);  
  _pim_mese    = new TRecfield(*_pim_r,"CODTAB",13,14);
  _pim_tipocr  = new TRecfield(*_pim_r,"CODTAB",15,15);
  _pim_codiva  = new TRecfield(*_pim_r,"CODTAB",16,19);  
  _pim_tipodet = new TRecfield(*_pim_r,"CODTAB",20,20);  
  _pis_anno    = new TRecfield(*_pis_r,"CODTAB",0,3);
  _pis_codatt  = new TRecfield(*_pis_r,"CODTAB",4,9);
  _pis_codreg  = new TRecfield(*_pis_r,"CODTAB",10,12);  
  _pis_mese    = new TRecfield(*_pis_r,"CODTAB",13,14);
  _pis_tipocr  = new TRecfield(*_pis_r,"CODTAB",15,15);
  _pis_codiva  = new TRecfield(*_pis_r,"CODTAB",16,19);  
  _pis_tipodet = new TRecfield(*_pis_r,"CODTAB",20,20);  
  _prm_anno    = new TRecfield(*_prm_r,"CODTAB",0,3);
  _prm_codatt  = new TRecfield(*_prm_r,"CODTAB",4,9);
  _prm_codreg  = new TRecfield(*_prm_r,"CODTAB",10,12);  
  _prm_mese    = new TRecfield(*_prm_r,"CODTAB",13,14);
  _prm_tipocr  = new TRecfield(*_prm_r,"CODTAB",15,15);
  _prm_codiva  = new TRecfield(*_prm_r,"CODTAB",16,19);  
  _prm_tipodet = new TRecfield(*_prm_r,"CODTAB",20,20);  
  _prp_anno    = new TRecfield(*_prp_r,"CODTAB",0,3);
  _prp_codatt  = new TRecfield(*_prp_r,"CODTAB",4,9);
  _prp_codreg  = new TRecfield(*_prp_r,"CODTAB",10,12);  
  _prp_mese    = new TRecfield(*_prp_r,"CODTAB",13,14);
  _prp_tipocr  = new TRecfield(*_prp_r,"CODTAB",15,15);
  _prp_codiva  = new TRecfield(*_prp_r,"CODTAB",16,19);  
  _prp_tipodet = new TRecfield(*_prp_r,"CODTAB",20,20);  
  _pum_anno    = new TRecfield(*_pum_r,"CODTAB",0,3);
  _pum_codatt  = new TRecfield(*_pum_r,"CODTAB",4,9);
  _pum_mese    = new TRecfield(*_pum_r,"CODTAB",10,11);
  _pam_anno    = new TRecfield(*_pam_r,"CODTAB",0,3);
  _pam_codatt  = new TRecfield(*_pam_r,"CODTAB",4,9);
  _pam_mese    = new TRecfield(*_pam_r,"CODTAB",10,11);
  _pom_anno    = new TRecfield(*_pom_r,"CODTAB",0,3);
  _pom_codatt  = new TRecfield(*_pom_r,"CODTAB",4,9);
  _pom_mese    = new TRecfield(*_pom_r,"CODTAB",10,11);
  _ppa_year    = new TRecfield(*_ppa_r,"CODTAB",0,3);
  _ppa_codatt  = new TRecfield(*_ppa_r,"CODTAB",4,9);
  _ppa_month   = new TRecfield(*_ppa_r,"CODTAB",10,11);
  _ppa_kind    = new TRecfield(*_ppa_r,"CODTAB",12,12); 

  _plm_anno    = new TRecfield(*_plm_r,"CODTAB",0,3);
  _plm_codatt  = new TRecfield(*_plm_r,"CODTAB",4,9);
  _plm_mese    = new TRecfield(*_plm_r,"CODTAB",10,11);

  _pia_anno    = new TRecfield(*_pia_r,"CODTAB",0,3);
  _pia_codatt  = new TRecfield(*_pia_r,"CODTAB",4,9);
  _pia_mese    = new TRecfield(*_pia_r,"CODTAB",10,11);
  _pia_codord  = new TRecfield(*_pia_r,"CODTAB",12,15);
  _pia_codcom  = new TRecfield(*_pia_r,"CODTAB",16,19);

  _pla_ditta   = new TRecfield(*_pla_r,"CODTAB",0,4);
  _pla_anno    = new TRecfield(*_pla_r,"CODTAB",5,8);
  _pla_codatt  = new TRecfield(*_pla_r,"CODTAB",9,14);

  _del_ditta   = new TRecfield(*_del_r,"CODTAB",0,4);
  _del_anno    = new TRecfield(*_del_r,"CODTAB",5,8);
  _del_mese    = new TRecfield(*_del_r,"CODTAB",9,10);
  _del_tipo    = new TRecfield(*_del_r,"CODTAB",11,11);

  _lim_anno    = new TRecfield(*_lim_r,"CODTAB",0,3);
  _lim_mese    = new TRecfield(*_lim_r,"CODTAB",4,6);
  
  _lam_anno    = new TRecfield(*_lam_r,"CODTAB",0,3);
  _lam_mese    = new TRecfield(*_lam_r,"CODTAB",4,6);
  
  __firm = TApplication::get_firm();

  if (pnd) pnd->addstatus(1);
  
  if (_is_interactive)
  { 
    build_nomiditte(pnd);            
    build_ditte_sheet(all);
  }

  if (pnd) pnd->addstatus(1);

  TApplication::set_firm(__firm);
  set_real_picture(REAL_PICTURE);
  set_magic_currency(TRUE);
  
  if (!_is_interactive)
  {            
    TTemp_window w(TASK_WIN);
    if (_recalc_only) 
      _isprint = FALSE;
    //else printer().set_export_file(filename, is_header, headerlen);
    else printer().set_export_file(filename, is_header);
    
    // calcola liquidazione 
    printer().setdate(printdate);
    _recalc = nocalc ? never : needed;
    TApplication::set_firm(ditta);
    
    if (!look_lia()) 
    { end_wait();  return FALSE; }
    
    TIva_round ir; // Imposta arrotondamento iva
    ir.set_default_iva_mode(atoi(_year), _month > 12, ditta);
 
    _nditte->zero(); 
    _nditte_r->put("CODDITTA", ditta); 
    _nditte->read();
    _freqviva = _lia->get("S7");

    TRectype& mov = _cur->curr();
    TRectype  from(_cur->curr()); from.zero();
    TRectype  to(from);
    TDate f(1, 1, atoi(_year));
    TDate t(1, _month == 13 ? 12 : _month, atoi(_year));

// qui se liquidazione diff. su ditta si parte da year-4 e filtro su anno o data liquid diff sul movim  nel periodo
    t.set_end_month();
    from.put(MOV_DATAREG, f);
    to.put(MOV_DATAREG, t);
    _cur->setregion(from, to);
    _canprint = is_month_ok_strict(_month) || _month == 13;
    _isannual = _isriepilogo = _month == 13;
      
    //modifica del 03/05/1995 
    int need_refresh = FALSE;
		int m;

    for (m = 1; m < _month; m++)
      if (is_month_ok_strict(m) && (!look_lim(m) || !_lim->get_bool("B0")))
      {
        need_refresh = TRUE; 
        break;
      }

    if (need_refresh) _recalc = ever;

    // determina attivita' prevalente e istanzia cazzuole
    // per vedere che Kazzo di liquidazione calcolare
    const TString8 attprev = _nditte->curr().get("CODATTPREV");
		TString16 key;

		key.format("%ld|%s", ditta, (const char *) attprev);
	  
		const TRectype & atts = cache().get(LF_ATTIV, key);

    // istanzia benzinaro
    _isbenzinaro = atts.get_bool("ART74_4");
      
    // riaggiusta relazione
    _nditte->read();               
    
    for (int mese = 1; mese < _month; mese++)   
      if ((is_month_plain(mese) && !(_freqviva == "T" && _recalc_regis)) || _recalc == ever)
        update_firm(mese);
    
    if (is_month_plain(_month) || _month == 13) 
      update_firm(_month);
    
    if (_isprint && _descr_arr.items() > 0)
      print();            
                 
    if (!nocalc)
    {
      // se ci sono altri mesi dopo l'ultimo calcolato, invalida il 
      // flag 'calcolato' del primo, per causare il ricalcolo dei
      // successivi (evitando problemi per credito precedente)
      for (m = _month+1; m <= 13; m++)
        if (look_lim(m))
        { 
          _lim->put("B0","");
          _lim->rewrite();
          break; 
        }
    }    
            
    TApplication::set_firm(__firm);      
    end_wait();
    user_destroy();
  }                    
  else 
    delete pnd; 
  
  return _is_interactive;
}

bool TLiquidazione_app::user_destroy()
{
  delete _ditte;

  delete _pim_anno;
  delete _pim_codreg;
  delete _pim_mese;
  delete _pim_tipocr;
  delete _pim_codiva;
  delete _pim_codatt;
  delete _pim_tipodet;
  delete _pis_anno;
  delete _pis_codreg;
  delete _pis_mese;
  delete _pis_tipocr;
  delete _pis_codiva;
  delete _pis_codatt;
  delete _pis_tipodet;
  delete _prm_anno;
  delete _prm_codreg;
  delete _prm_mese;
  delete _prm_tipocr;
  delete _prm_codiva;
  delete _prm_codatt;
  delete _prm_tipodet;
  delete _prp_anno;
  delete _prp_codreg;
  delete _prp_mese;
  delete _prp_tipocr;
  delete _prp_codiva;
  delete _prp_codatt;
  delete _prp_tipodet;
  delete _ppa_year;
  delete _ppa_codatt;
  delete _ppa_month;
  delete _ppa_kind;
  delete _plm_anno;
  delete _plm_codatt;
  delete _plm_mese;
  delete _pia_anno;
  delete _pia_codatt;
  delete _pia_mese;
  delete _pia_codord;
  delete _pia_codcom;
  delete _pum_anno;
  delete _pum_codatt;
  delete _pum_mese;
  delete _pam_codatt;
  delete _pam_anno;
  delete _pam_mese;
  delete _pom_codatt;
  delete _pom_anno;
  delete _pom_mese;
  delete _lim_anno;
  delete _lim_mese;
  delete _lam_anno;
  delete _lam_mese;
  delete _pla_anno;
  delete _pla_codatt;
  delete _del_ditta;
  delete _del_anno;
  delete _del_mese;
  delete _del_tipo;

  delete _ver;
  delete _pim;
  delete _pis;
  delete _prm;
  delete _prp;
  delete _pum;
  delete _pam;
  delete _pom;
  delete _ppa;
  delete _plm;
  delete _pia;
  delete _lim;
  delete _lam;
  delete _pla;
  delete _del;

  delete _tab11;
  delete _nditte;
  delete _rel;
  delete _cur;   
  
  return TRUE;
}

bool TLiquidazione_app::set_print(int)
{
  _descr_arr.destroy();
  _errors.destroy(); 
  _reg_arr.destroy();
  _codiva_arr.destroy();
  
  switch(_menu)
  {
  case 1: // liquidazione
    _isprint = TRUE;
    while (set_liquidazione()) 
    {
      if (_selected.ones() > 0l)
        return recalc_all() && _isprint;
      else warning_box(TR("Nessuna ditta selezionata!"));
    }
    break;
  case 2: // estrazione deleghe
    _isprint = FALSE;
    _selected.reset();
    _ditte->check(-1, FALSE);
    build_ditte_sheet(all);
    while (set_deleghe()) 
    { 
      if (_calcall || _selected.ones() > 0l)
      {
        extract_deleghe(); 
        return _isprint;
      } 
      else warning_box(TR("Nessuna ditta selezionata!"));
    }
    break;
  case 3: // calcolo acconto
    _isprint = TRUE;
    _month = 12; 
    _selected.reset();
    _ditte->check(-1, FALSE);
    build_ditte_sheet(all);
    real inf; real ina;  // cotale obbrobrio non fu da me cercato, ne' mai condiviso
    while (set_acconto(inf, ina)) 
    { 
      if (_calcall || _selected.ones() > 0l)
      {
        recalc_acconti(inf, ina); 
        return _isprint; 
      } 
      else warning_box(TR("Nessuna ditta selezionata!"));
    }
    break;
  }
  return FALSE;
}

long TLiquidazione_app::select_firm_range(long from, long to, wht freq)
{
  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 char vers = d.get_char(3);
    if (vers == '?' || (freq == mnt && vers == 'T') || (freq == trimestre && vers == 'M'))
      continue;

    const long cod = d.get_long(1);
    if (cod >= from && cod <= to)
    {
      _selected.set(i); 
      _ditte->check(i);
    }
    else 
    {
      _selected.set(i,FALSE);
      _ditte->uncheck(i);
    }
  } 
  
  return _selected.ones();
}

// ----------------------------------------------- handlers

bool TLiquidazione_app::ch_year_handler(TMask_field& f, KEY key)
{                                                    
  if (key == K_TAB && f.focusdirty())
  {                         
    
	TWait_cursor hourglass;
    app().reset_choices(f.mask());
    app().set_year(f.get());
    app().build_nomiditte();
    app().build_ditte_sheet(f.mask().source_file() == "cg4300a.msk" ?
                            (wht)atoi(f.mask().get(CG43_RDB_VERS))  :
                            all);
  }
  return TRUE;
} 

void TLiquidazione_app::build_nomiditte(TProgind* pnd)
{                 
  _nomiditte.destroy();
  // ricostruire _nomiditte e rifare build_ditte_sheet
  TLocalisamfile& dt = _nditte->lfile();
  
  for (dt.first(); !dt.eof(); dt.next())
  {     
    // check no archivi
    bool good = prefix().exist(dt.get_long("CODDITTA"));                        
    
    if (good) 
    {   
      // check no parametri liquidazione                                               
      if (!look_lia(dt.get_long("CODDITTA")))
        good = FALSE; 
    }
    else continue;
    
    TToken_string* d = new TToken_string(64);
    
    // add record 
    d->add(dt.get("CODDITTA"));
    d->add(dt.get("RAGSOC"));
    if (good)
    {
      d->add(_lia->get("S7"));
      d->add(_lia->get("B2"));
    }
    else      
    {
      d->add("??"); 
      d->add("??"); 
    }
    _nomiditte.add(d);  
  }
  if (pnd) pnd->addstatus(1);
}

bool TLiquidazione_app::to_ditt_handler(TMask_field& f, KEY key)
{
  TMask& m = f.mask();
  if (key == K_F9)
  {
    TArray_sheet* sh = app().get_ditte_sheet();
    
    sh->disable_check();
    sh->disable(DLG_USER);
    if (sh->run() == K_ENTER)
    {
      app().select_firm_range(m.get_long(CG43_FLD_DFR),sh->row(sh->selected()).get_long(1), 
                              (wht)m.get_int(CG43_RDB_VERS));
      app().set_choice_limits(m);
    }
    sh->enable(DLG_USER);
  }
  if (key == K_TAB && f.focusdirty())
  {
    const long l = app().select_firm_range(m.get_long(CG43_FLD_DFR),
                                           m.get_long(CG43_FLD_DTO), 
                                           (wht)m.get_int(CG43_RDB_VERS));
    app().set_choice_limits(m);
    m.set(CG43_FLD_SELECTED, l);
  }
  return TRUE;
}

bool TLiquidazione_app::fr_ditt_handler(TMask_field& f, KEY key)
{                          
  TMask& m = f.mask();
  if (key == K_F9)
  {
    TArray_sheet* sh = ((TLiquidazione_app&)main_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(CG43_FLD_DTO), 
                              (wht)m.get_int(CG43_RDB_VERS));
      app().set_choice_limits(m);
    }
    sh->enable(DLG_USER);
  }
  else if (key == K_TAB && f.focusdirty())
  {
    const long l = app().select_firm_range(m.get_long(CG43_FLD_DFR),
                                           m.get_long(CG43_FLD_DTO), 
                                           (wht)m.get_int(CG43_RDB_VERS));

    app().set_choice_limits(m);
    m.set(CG43_FLD_SELECTED, l);
  }
  return TRUE;
}

bool TLiquidazione_app::what_freq_handler(TMask_field& f, KEY key)
{    
  if (key == K_SPACE)
  {  
    int month = f.mask().get_int(CG43_LST_MESE);
    if (f.get()[0] == '3')       // trimestre intelligente
    {
      if  (month > 3) 
        while (!is_trim(month)) month--;  
      else month = 3; 
      
      f.mask().set(CG43_LST_TRIM,month); 
    }
    app().set_month(month);
    app().reset_choices(f.mask());                            
    app().build_ditte_sheet((wht)atoi(f.get()));
  } 
  return TRUE;
}

bool TLiquidazione_app::lst_tm_handler(TMask_field& f, KEY key)
{
  if (f.to_check(key))
  {
    const int m   = atoi(f.get());
    TMask&    msk = f.mask();

    if (m == 13)
    {
      msk.field(CG43_LST_CALC).set("2");
      msk.field(CG43_LST_CALC).disable();
    }
    else
     // Abilita il ricalcolo solo se non e' richiesta esplicitamente la sola stampa
      if (!msk.get_bool(CG43_CHK_FINAL))
        msk.field(CG43_LST_CALC).enable();

    const bool change = (app()._month != 13 && m == 13) || (app()._month == 13 && m != 13);
    if (change)
    {
      TWait_cursor hourglass;
      app().reset_choices(f.mask());
      app().set_month(m);
      app().build_ditte_sheet(f.mask().source_file() == "cg4300a.msk" ?
                              (wht)atoi(f.mask().get(CG43_RDB_VERS))  :
                              all);
    }
  }
  return TRUE;
}

bool TLiquidazione_app::select_button(TMask_field& f, KEY key)
{
  if (key == K_SPACE)
  {
    app()._ditte->enable_check();
    // seleziona e aggiungi alle gia' selezionate 
    if (app()._ditte->run() == K_ENTER)
    {
      const long itms = app()._ditte->items();
      for (long j = 0l; j < itms; j++)
        app()._selected.set(j, app()._ditte->checked(j));
      app().set_choice_limits(f.mask());
    }
  }
  return TRUE;
}

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

bool TLiquidazione_app::chk_final_handler(TMask_field& f, KEY key)
{
  if (key == K_SPACE)
  {
    TMask& m = f.mask();
    // Abilita solo se il mese di ricalcolo e' != 13 (annuale) e non e' checkkato il campo
    const int vers = m.get_int(CG43_RDB_VERS);
    const int mese = vers == 3 ? m.get_int(CG43_LST_TRIM) : m.get_int(CG43_LST_MESE);
    const bool abilita = !m.get_bool(CG43_CHK_FINAL) && mese != 13;
    m.enable(CG43_LST_CALC, abilita);
  }
  return TRUE;
}

void TLiquidazione_app::reset_choices(TMask& m)
{
  _selected.reset();  
  if (m.source_file() == "cg4300a.msk")
  {
    m.reset(CG43_FLD_SELECTED);
    m.reset(CG43_FLD_DFR);
    m.reset(CG43_FLD_DTO);
  } 
  _ditte->check(-1, FALSE);
}

void TLiquidazione_app::set_choice_limits(TMask& m)
{     
  long first = -1l, last = -1l;
  for (int i = 0; i < _ditte->items(); i++)
  {
    if (_selected[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(CG43_FLD_DFR, first);                        
  if (last  != -1) m.set(CG43_FLD_DTO, last);                        
  m.set(CG43_FLD_SELECTED, _selected.ones());
}

void TLiquidazione_app::build_ditte_sheet(wht what)
{
  // build sheet
  const int items = _nomiditte.items();
  _ditte->destroy();
  _what = what;
  for (int i = 0; i < items; i++)
  {
    TToken_string* d = new TToken_string(64);
    *d = (TToken_string&)_nomiditte[i];
    const char vers = d->get_char(2);
    const bool agr  = d->get_char(3) == 'X';
    
    bool unselectable = vers == '?' || (_year > "1997" && _month < 13 && agr);
    if ((what == mnt && vers == 'T') || (what == trimestre && vers == 'M'))
      continue;
    
    d->insert(" |", 0);        
    
    const long pos = _ditte->add(d);     
    if (unselectable)
      _ditte->disable_row(pos);
    else
    {
      _ditte->enable_row(pos);
      if (_selected[i])
       _ditte->check(pos);
    }
  }     
}


// ----------------------------------------------------

bool TLiquidazione_app::set_liquidazione()
{
  TMask m("cg4300a");
  
  m.set_handler(CG43_FLD_DTO,  to_ditt_handler);
  m.set_handler(CG43_FLD_DFR,  fr_ditt_handler);
  m.set_handler(CG43_RDB_VERS, what_freq_handler);
  m.set_handler(CG43_FLD_ANNO, ch_year_handler);
  m.set_handler(CG43_LST_MESE, lst_tm_handler);
  m.set_handler(CG43_LST_TRIM, lst_tm_handler);
  m.set_handler(CG43_BUT_SEL,  select_button);
  m.set_handler(CG43_BUT_ANN,  reset_button);
  m.set_handler(CG43_CHK_FINAL, chk_final_handler);
  
  m.set(CG43_FLD_SELECTED, _selected.ones());
  m.set(CG43_FLD_ANNO, _year);
  set_choice_limits(m);
  
  // stampa abilitata per default
  m.set(CG43_CHK_STAMPA,"X");  
  
  _month = m.get_int(CG43_LST_MESE);
  
  m.set(CG43_RDB_VERS, _what);
  
  const KEY k = m.run();
  if (k == K_ENTER) 
  {                   
    // handlers have set everything
    _month   = _what == trimestre ? m.get_int(CG43_LST_TRIM) : 
    m.get_int(CG43_LST_MESE);
    
    _year      = m.get(CG43_FLD_ANNO);
    _date      = m.get(CG43_FLD_DATA);
    _isprint   = m.get_bool(CG43_CHK_STAMPA);
    _recalc    = (recalc)m.get_long(CG43_LST_CALC);
    _printonly = m.get_bool(CG43_CHK_FINAL);

    if (_isprint) printer().setdate(_date);
    if (_printonly) _recalc = never;
  }
  return k == K_ENTER;
}

int cg4300(int argc, char* argv[])
{
  TApplication::check_parameters(argc, argv);
  
  const char* title = TR("Liquidazione IVA");
  int menu = 1;
  
  if (argc > 2)
  {
    const char mode = argv[2][1];
    switch (mode)
    {
    case 'A':
      title = TR("Calcolo acconti");
      menu = 3;
      break;
    case 'C':
      title = TR("Ricalcolo progressivi IVA");
      break;
    case 'D': 
      title = TR("Estrazione versamenti");
      menu = 2;
      break;
    case 'S':
      title = TR("Stampa liquidazione"); 
      break;  
    default:
      break;  
    }  
  }

  TLiquidazione_app* main_app = new TLiquidazione_app(menu);
  main_app->run(argc, argv, title);
  delete main_app;
  return TRUE;
}