#include <browfile.h>
#include <currency.h>
#include <prefix.h>
#include <execp.h>
#include <msksheet.h>
#include <mailbox.h>
#include <prefix.h>
#include <progind.h>
#include <relation.h>
#include <recarray.h>
#include <sheet.h>
#include <viswin.h> 

#include "cglib03.h"
#include "cg5500.h"
#include "cg5500a.h"

static void round_imposta(real& d)
{
  TIva_round ir;
  ir.round(d);
}

const char* Visliq_app::itoname(int m)
{                    
  const char* mn;     
  if (m == 13) 
    return TR("Annuale");
  
  if (_freqviva == "M")
    return itom(m);

  switch(m)
  {
  case 3:
    mn = TR("1 Trimestre");
    break;
  case 6:
    mn = TR("2 Trimestre");
    break;
  case 9:
    mn = TR("3 Trimestre");
    break;
  case 12:
    mn = TR("4 Trimestre");
    break;
  }
  
  return mn;
}                             

void Visliq_app::set_freqviva()
{
  if (look_lia())
    _freqviva = _lia->get("S7");
  else
  {
		TString key;

		key.format("%ld", get_firm());

    const TRectype & ditta = cache().get(LF_NDITTE, key);

    _freqviva = ditta.get("FREQVIVA");
  }
}

bool Visliq_app::create()
{ 
  _firm = get_firm();
  TDate oggi(TODAY);                    
  _year = oggi.year();
	open_files(LF_TABCOM, LF_TAB, LF_NDITTE, 0);

  _nditte = new TRelation(LF_NDITTE);
  _ditte  = new TArray_sheet(-1, -1, -4, -4, TR("Selezione Ditte"),
                             HR("Cod.@5|Ragione Sociale@50|Vers."));  
  _from_one = FALSE;
  _del        = new TTable("%DEL");
  _lia        = new TTable("%LIA");
  _lim        = new TTable("LIM");
  _lam        = new TTable("LAM");
  _del_r      = &(_del->curr());
  _lim_r      = &(_lim->curr());
  _lam_r      = &(_lam->curr());
  _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);

  begin_wait();
  build_nomiditte();
  build_ditte_sheet();
  end_wait();
  
  return TSkeleton_application::create();  
}

bool Visliq_app::destroy()
{                                  
  delete _lim_mese;
  delete _lim_anno;
  delete _lam_mese;
  delete _lam_anno;
  delete _del_tipo;
  delete _del_mese;
  delete _del_ditta;
  delete _lim;
  delete _lam;
  delete _del;
  delete _ditte;
  delete _nditte;
  
  return TApplication::destroy();
}

bool Visliq_app::ch_year_handler(TMask_field& f, KEY key)
{                                                    
  if (key == K_TAB && f.focusdirty())
  {                         
    TWait_cursor hourglass;
    app().set_year(f.get());
    app().build_nomiditte();
    app().build_ditte_sheet();  
    app().reset_fields();  
  }
  return TRUE;
} 


void Visliq_app::build_ditte_sheet()
{
  // build sheet
  _ditte->destroy();
  long prima = -1;
  
  for (int i = 0; i < _nomiditte.items(); i++)
  {
    TToken_string* d = new TToken_string(_nomiditte.row(i));
    const long pos = _ditte->add(d);     
    const char vers = d->get_char(2);
    const bool selectable = vers != '?';
    _ditte->enable_row(pos, selectable);
    if (selectable && prima < 0)
      _ditte->select(prima = pos);
  }     
}

void Visliq_app::reset_fields()
{
  _mask->field(F_CODDITTA).set("");
  _mask->field(F_RAGSOC).set("");
}

bool Visliq_app::select_butt(TMask& m)
{     
  if (_ditte->run() == K_ENTER)
  {
    TToken_string& row = _ditte->row(_ditte->selected()); 
    m.field(F_CODDITTA).set(row.get(0));
    m.field(F_RAGSOC).set(row.get(1));
    set_freqviva(row.get(2)); 
    set_mask_freq(m);
    return TRUE;        
  }
  return FALSE;
}

void Visliq_app::build_nomiditte()
{                 
  _nomiditte.destroy();
  // ricostruire _nomiditte e rifare build_ditte_sheet
	TRectype & ditta = _nditte->lfile().curr();
	TCursor cur(_nditte);
	const TRecnotype items = cur.items();

	cur.freeze();
  for (cur = 0L; cur.pos() < items; ++cur)
  {     
    // check no archivi
    bool good = prefix().exist(ditta.get_long("CODDITTA"));                        
    
    if (good) 
    {   
      // check no parametri liquidazione
      TString16 cod; 
      
			cod.format("%05ld%d", ditta.get_long("CODDITTA"), _year);
      
			const TRectype & lia = cache().get("%LIA", cod);
			TToken_string* d = new TToken_string(64);
    
			// add record 
	    d->add(ditta.get("CODDITTA"));
		  d->add(ditta.get("RAGSOC"));

			const TString & fr = lia.get("S7");

			d->add(fr.empty() ? "??" : fr);
	    _nomiditte.add(d);  
    }

  }
}

void Visliq_app::set_mask_freq(TMask& m)
{
  if (_freqviva == "M")
  {
    m.show(F_MONTHS);
    m.hide(F_TRIMS);
  }
  else
  {
    m.hide(F_MONTHS);
    m.show(F_TRIMS);
  }
}      


bool Visliq_app::sheet_action(TSheet_field& s, int r, KEY k)
{                    
  if (k == K_ENTER)
    app()._sh_dirty = TRUE;
  // non si possono cancellare o aggiungere righe
  return (k != K_DEL && k != K_INS);
}

bool Visliq_app::vers_action(TSheet_field& s, int r, KEY k)
{                    
  if (k == K_ENTER)
    app()._sv_dirty = TRUE;
  // non si possono cancellare o aggiungere righe 
  return (k != K_DEL && k != K_INS);
}

const char* Visliq_app::link_handler(TMask& m, 
                                     int n, const char* txt, bool doubleclick)
{
  // con click visualizza, con double click modifica
  TString st(txt);                                   
  bool iscred = FALSE;
  static int group; 
  int firstfoc = 0;

  if (group != 0) m.hide(group);    
  
  if (st.find(TR("Iva chiesta a rimborso")) >= 0 || st.find(TR("Rimborsi")) >= 0) 
  { group = -1;  firstfoc = F_RIMBORSO;  }
  else if (st.find(TR("debito")) >= 0 || st.find(TR("credito")) >= 0)
  { group = -2;  firstfoc = F_RETTIFICA; }
  else if (st.find(TR("acconto")) >= 0)
  { group = -3;  firstfoc = F_ACCONTO;   } 
  else if (st.find(TR("Versamenti")) >= 0)                 
  { group = -4;  firstfoc = F_DELDATE;   } 
  else if (st.find(TR("Descrizione")) >= 0)                 
  { group = -5;  firstfoc = F_DESCR3;   } 
  else if (st.find(TR("Variazioni d'imposta")) >= 0)                 
  { group = -6; firstfoc = F_VARIMP; } 
  else if (st.find(TR("Imposta non versata")) >= 0)                 
  { group = -7; firstfoc = F_IMPNONVER; } 
  if (st.find(TR("Crediti")) >= 0) 
  { group = -8;  firstfoc = F_CREDSPEC;  }
  
  m.show(group);
  if (app()._is_annual && (group != -3 || app()._freqviva == "M"))
    m.disable(group);
  else
  {
    m.enable(group);  
    if (doubleclick && firstfoc > 0) 
      m.field(firstfoc).set_focus();
  }

  return NULL;
}                                               


void Visliq_app::main_loop()
{
  vis_liq();       
}                

// handlers
bool Visliq_app::set_ditta(TMask_field& f, KEY k)
{                               
  bool found = TRUE;

  if (k == K_F9)
    return app().select_butt(f.mask());

  if (k == K_TAB && f.focusdirty())
  {
    found = FALSE;
    TString ditta = f.get();
    TArray_sheet* sh = app().get_ditte_sheet();
    for (int i = 0; i < sh->items(); i++)
    { 
      TToken_string& row = sh->row(i);
      if (ditta == row.get(0))
      { 
        if (sh->row_enabled(i))
        {
          f.mask().field(F_CODDITTA).set(row.get(0));
          f.mask().field(F_RAGSOC).set(row.get(1));
          app().set_freqviva(row.get(2));
          app().set_mask_freq(f.mask()); 
          found = TRUE;
        }
        else 
        { 
          f.warning_box(FR("Non sono definiti i parametri liquidazione per la ditta %ld"),
                      atol(ditta));
          f.reset(); 
        }
        break;
      }
    }
  }
  if (!found) f.reset(); 
  return found;
}

bool Visliq_app::set_ragsoc(TMask_field& f, KEY k)
{   
  bool found = TRUE;

  if (k == K_F9)
    return app().select_butt(f.mask());

  if (k == K_TAB && f.focusdirty())
  {
    found = FALSE;
    TString ditta = f.get();
    TArray_sheet* sh = app().get_ditte_sheet();
    for (int i = 0; i < sh->items(); i++)
    { 
      TToken_string& row = sh->row(i);
      TString ts(row.get(1));
      if (ts.find(ditta) != -1)
      { 
        if (sh->row_enabled(i))
        {
          f.mask().field(F_CODDITTA).set(row.get(0));
          f.mask().field(F_RAGSOC).set(row.get(1));
          app().set_freqviva(row.get(2)); 
          app().set_mask_freq(f.mask()); 
          found = TRUE;
          break;
        }
      }
    }
  } 
  if (!found) f.reset(); 
  return found;  
}


bool Visliq_app::sel_mese_sh1 (TMask_field& f, KEY k)
{                                                  
  if (k != K_SPACE) return TRUE;
  
  TMask& m = *(app().get_main_mask());
  TSheet_field& sh = m.sfield(F_VISLIQ1);
  TSheet_field& sv = m.sfield(F_VISLIQ2);  
  int sel   = sh.selected();
  int month = sh.selected()+1;
  TToken_string& tt = sh.row(sh.selected());
  if (sh.items() == 4) month *= 3;  
  
  bool ok = FALSE;
  
  //if (m.dirty() || sh.sheet_mask().dirty())
  if (m.field(F_CREDPREC).dirty() || app()._sh_dirty || app()._sv_dirty)
  {             
    KEY k = yesnocancel_box(TR("Registrazione modifiche effettuate?"));
    if (k ==  K_YES)
      app().write_general(m); 
    else if (k == K_NO)
      app().read_general(m);  
    ok = (k == K_YES || k == K_NO);  
  } 
  else ok = TRUE;   

  TMask& sm = sh.sheet_mask();
  if (ok) 
  {
    if (sm.is_running()) sm.stop_run(K_ENTER);
    app().vis_one(month); 
    const bool new_age_2000 = (app()._year >= 2000) && (app()._lia->get("S9") == "NV");
    if (new_age_2000)
      app().read_general(m);  
  }
  
  app().set_liq_rows(sh);
  
  if (sm.is_running())
  {
    // TBC controllare se sono i dati giusti in tt
    sm.field(102).set(tt.get(1));
    sm.field(103).set(tt.get(2));
    sm.field(104).set(tt.get(3));
    sm.field(105).set(tt.get(4));
    sm.field(106).set(tt.get(5));  
  }
  
  sh.row(sel) = tt;
  
  sh.force_update(sel);

  if (app().look_del(month,1))
  {                                         
    TToken_string& tv = sv.row(sel == (sh.items() - 1) ? sel -1 : sel);
    tv.add(app().del()->get("D0"),1);
    tv.add(app().del()->get("S7"),2);
    tv.add(app().del()->get("S8"),3);
    tv.add(app().del()->get("S9"),4);
    tv.add(app().del()->get("R0"),5);
    sv.force_update(sel == (sh.items() - 1) ? sel -1 : sel);
  }
  
  return TRUE;
}


bool Visliq_app::sel_mese_sh2 (TMask_field& f, KEY k)
{               
  if (k != K_SPACE) return TRUE;

  TMask& m = *(app().get_main_mask());
  TSheet_field& sh = (TSheet_field&)m.field(F_VISLIQ2);
  int sel   = sh.selected();
  int month = sh.selected()+1;
  if (sh.items() < 12) 
    month *= 3;      
  
  // click su acconto
  if (month  > 12) return TRUE;

  bool ok = FALSE;  
  //if (m.dirty())         
  if (m.field(F_CREDPREC).dirty() || app()._sh_dirty || app()._sv_dirty)
  {             
    KEY k = yesnocancel_box(TR("Registrazione modifiche effettuate?"));
    if (k ==  K_YES)
      app().write_general(m); 
    else if (k == K_NO)
      app().read_general(m);  
    ok = k == K_YES || k == K_NO;  
  } 
  else ok = TRUE;   
  
  TMask& sv = sh.sheet_mask();
  if (ok)
  {
    if (sv.is_running()) sv.stop_run(K_ENTER);
    app().vis_one(month);
    const bool new_age_2000 = (app()._year >= 2000) && (app()._lia->get("S9") == "NV");
    if (new_age_2000)
      app().read_general(m);  
  }
  
  app().set_vers_rows(sh);
  
  if (app().look_del(month, /* sel == (sh.items() - 1) ? 7 : */ 1))
  {  
    TToken_string& tv = sh.row(sel);
    tv.add(app().del()->get("D0"),1);
    tv.add(app().del()->get("S7"),2);
    tv.add(app().del()->get("S8"),3);
    tv.add(app().del()->get("S9"),4);
    tv.add(app().del()->get("R0"),5);
    sh.force_update(sel);
  }
  
  return TRUE;
}


void Visliq_app::vis_liq()
{               
  const long ditta = get_firm();  // Memorizza ditta corrente da ripristinare alla fine
  set_freqviva();
  
  TMask m("cg5500a");
  _mask = &m;
  
  m.set_handler(F_CODDITTA, set_ditta);   
  m.set_handler(F_RAGSOC,   set_ragsoc);   
  m.set_handler(F_YEAR,     ch_year_handler);   

  set_mask_freq(m);
  _year = m.get_int(F_YEAR);
  
  KEY k;
  while ((k = m.run()) == K_ENTER)
  { 
    if (m.get(F_CODDITTA).empty() || m.get(F_RAGSOC).empty())  
    { 
      beep();
      continue;
    }

    const long dtt = m.get_long(F_CODDITTA); 
    set_firm(dtt); 
    
    TIva_round ir; 
    ir.set_default_iva_mode(_year, FALSE);

    const int month = m.get_int(_freqviva == "M" ? F_MONTHS : F_TRIMS);
    _is_annual = (month == 13);
    if (month == 0)
      vis_all();
    else
      vis_one(month);
    _mask = &m;   
  } 

  set_firm(ditta);
}    


bool Visliq_app::vis_all()
{                                               
  if (!look_lia())
    return FALSE;    
  
  // mask diverse per trimestrale e annuale
  _mask = new TMask(_freqviva == "M" ? "cg5500b" : "cg5500c"); 
  
  TSheet_field& sh = _mask->sfield(F_VISLIQ1); 
  TSheet_field& sv = _mask->sfield(F_VISLIQ2); 
  _liq_sheet  = &sh;
  _vers_sheet = &sv;
  
  // disabilita aggiunta/eliminazione righe
  sh.set_notify(sheet_action);
  // qui occorre modificare le deleghe
  sv.set_notify(vers_action);

  sh.sheet_mask().set_handler(100,sel_mese_sh1);
  sv.sheet_mask().set_handler(100,sel_mese_sh2);
  
  const bool new_age_2000 = (_year >= 2000) && (_lia->get("S9") == "NV");
  const bool new_print_2000 = _year >= 2000;
  TMask& shm = sh.sheet_mask();
  
  for (int id = 103; shm.id2pos(id) > 0; id++)
  {                
    TMask_field& f = shm.field(id);
    if ((f.in_group(11) && new_print_2000) || (f.in_group(12) && !new_print_2000))
    {
      f.hide();
      sh.delete_column(id);
    }        
    if (id == 108 || id == 110)
      sh.enable_column(id, new_age_2000);
  }

  // fill the mask in
  read_general(*_mask);

  for (bool stop = FALSE; !stop;)
  {
    KEY k = _mask->run();        
    
    switch(k)
    {
    case K_ESC: 
    case K_QUIT: 
      if (_mask->dirty())
      {
        KEY k = yesnocancel_box(TR("Registrazione modifiche effettuate?"));

        if (k ==  K_YES)
          write_general(*_mask); 
        else
          read_general(*_mask);
        
        if (k == K_YES || k == K_NO) 
          stop = TRUE;
        break;  
      } 
      else stop = TRUE;
      break;      
    case K_SAVE:     
      // write values 
      if (_mask->dirty()) 
        write_general(*_mask);
      break;
    }
  }

  delete _mask;
  _mask = NULL; 
  
  _vers_sheet = NULL;
  _liq_sheet  = NULL;   
  
  return TRUE;
}    


bool Visliq_app::vis_one(int m)
{       
  begin_wait();
  TMask msk("cg5500d");
  
  bool recorded = TRUE;
  TString nomem(TR("Liquidazione IVA "));

  nomem << itoname(m);
  nomem << " " << _year;
  
  msk.show(F_PERIODOM, _freqviva == "M");
  msk.show(F_PERIODOT, _freqviva != "M");
  msk.set(_freqviva == "M" ? F_PERIODOM : F_PERIODOT, m);
  
  // ricalcolo liquidazione
  TFilename f;
  f.temp("prliq");
  
  TToken_string body(36);
  body.add(_year);
  body.add(m);
  body.add(get_firm());
  body.add("V");        // visualizzazione: no ff alla fine, zeri stampati
  body.add(""); 
  body.add(f);     
  body.add('X');
  
  TMessage msg("cg4 -2 -S", "RCL", body);
  msg.send();

  TBrowsefile_field& brw = (TBrowsefile_field&)msk.field(F_VISFLQ); 
  brw.set_link_handler(link_handler);
  brw.enable_link(TR("Modifica: "), 'r');            

  TExternal_app liq("cg4 -2");

  end_wait();
  TProgind* pp = new TProgind(10,TR("Estrazione liquidazione: prego attendere"),FALSE,FALSE);
  liq.run();  
  if (liq.exitcode())
  {
    beep();
    return FALSE;
  }    

  look_lim(m);
  look_lia();

  real rimborso  = _lim->get_real("R1");
  real rettifica = _lim->get_real("R5");
  
  if (_lim->get_bool("B2"))
    nomem << TR(" (diritto al rimborso infraannuale)");
  
  real acconto(0.0);       
  
  if (m == 12 && look_del(12,7))
    acconto = _del->get_real("R0"); else
  if (m == 13)
    acconto = _lim->get_real("R11");

  
  msk.field(F_YEAR).set(nomem);
  msk.set(F_RIMBORSO, rimborso);
  
  // Ottima procedura di 16 righe, di cui 14 inutili!
  if (rettifica.sign() < 0)
  {              
    real rabs = abs(rettifica);
    msk.field(F_RETTIFICA).set(rabs.string());             
    msk.field(F_DEBCRE).set("C");
  }
  else if (rettifica.sign() > 0)
  {
    msk.field(F_RETTIFICA).set(rettifica.string()); 
    msk.field(F_DEBCRE).set("D");
  } 
  else                                              
  {
    msk.field(F_RETTIFICA).set(""); 
    msk.field(F_DEBCRE).set("");
  } 
  
  TString desc1 = _lim->get("S0"), desc2 = _lim->get("S1"), desc3 = _lim->get("S2");
  msk.field(F_DESCR1).set(desc1);             
  msk.field(F_DESCR2).set(desc2);             
  msk.field(F_DESCR3).set(desc3);
  msk.set(F_ACCONTO, acconto);
  
  real varimp = _lim->get("R17");
  real impnonver= _lim->get("R18");
  real credspec = _lim->get("R19");
  
  msk.set(F_VARIMP, varimp >= ZERO ? varimp : -varimp);
  msk.set(F_VARIMP_DC, varimp >= ZERO ? "D" : "C");

  msk.set(F_IMPNONVER, impnonver);
  msk.set(F_CREDSPEC, credspec);
  
  begin_wait();
  brw.set_text(f, TR("CALCOLO LIQUIDAZIONE D'IMPOSTA")); 
  brw.goto_pos(brw.lines()-16l, 9);
  delete pp;            

  TViswin & vsw = brw.vis_win();
  bool is_delega = FALSE;

  real vers; TDate date; TString abi(5), cab(5), con(3);
  
  if (is_delega = look_del(m,1))
  {
    vers = _del->get_real("R0"); 
    date = _del->get_date("D0");
    abi  = _del->get("S7");
    cab  = _del->get("S8");
    con  = _del->get("S9");
  }

  msk.field(F_DELDATE).set(date.string());
  msk.field(F_DELIMP).set(vers.string());
  msk.field(F_DELABI).set(abi);
  msk.field(F_DELCAB).set(cab);
  msk.field(F_DELCON).set(con);

  end_wait();

  bool    l_mod = FALSE;
  bool    d_mod = FALSE;

  _from_one = TRUE;
  
  for(;;)
  {
    KEY k = msk.run();  
    
    if (k == K_ESC) break;
    
    real    n_acconto  (msk.get(F_ACCONTO));
    real    n_rimborso (msk.get(F_RIMBORSO));
    real    n_rettifica(msk.get(F_RETTIFICA));
    real    n_delimp(msk.get(F_DELIMP));
    TString n_desc1 (msk.get(F_DESCR1));
    TString n_desc2 (msk.get(F_DESCR2));
    TString n_desc3 (msk.get(F_DESCR3));
    real    n_vers  (msk.get(F_DELIMP));
    TDate   n_date  (msk.get(F_DELDATE));
    TString n_abi   (msk.get(F_DELABI));
    TString n_cab   (msk.get(F_DELCAB));
    TString n_con   (msk.get(F_DELCON));
    real    n_varimp(msk.get(F_VARIMP));
    real    n_impnonver(msk.get(F_IMPNONVER));
    real    n_credspec(msk.get(F_CREDSPEC));
    
    if (msk.field(F_DEBCRE).get()[0] == 'C')
      n_rettifica = -n_rettifica;
      
    if (msk.get(F_VARIMP_DC)[0] == 'C')
      n_varimp = -n_varimp;

    if (msk.field(F_RETTIFICA).dirty() || msk.field(F_DEBCRE).dirty())
    { 
      rettifica = n_rettifica;
      l_mod = TRUE;  
    }
    if (msk.field(F_ACCONTO).dirty())
    {  
      acconto = n_acconto;
      l_mod = TRUE;  
    } 
    if (msk.field(F_RIMBORSO).dirty())
    {               
      bool ok = TRUE;
      if (!n_rimborso.is_zero())
      {
         const bool old_rim = !rimborso.is_zero();
        // check diritto (se non ce n'era gia' uno prima)
        if (!_lim->get_bool("B2") && !old_rim)
          ok = yesno_box(FR("Non risulta diritto al rimborso per il mese %d. Si desidera "
                         "confermare ugualmente?"), m);
      }                    
      if (ok)
      {
        rimborso = n_rimborso;
        l_mod = TRUE;  
      }
      else
      { 
        msk.field(F_RIMBORSO).set(rimborso.string());
        msk.field(F_RIMBORSO).set_dirty(FALSE);
      }
    }
    if (msk.field(F_DESCR1).dirty())
    {                        
      desc1 = n_desc1;
      l_mod = TRUE;  
    }
    if (msk.field(F_DESCR2).dirty())
    {                 
      desc2 = n_desc2;
      l_mod = TRUE;  
    }                     
    if (msk.field(F_DESCR3).dirty())
    {                 
      desc3 = n_desc3;
      l_mod = TRUE;  
    }                     
    if (msk.field(F_DELDATE).dirty())
    { 
      date  = n_date;
      d_mod = TRUE;
    }        
    if (msk.field(F_DELIMP).dirty())
    {     
      real itt = _lim->get_real("R10"); 
      vers = n_vers;
      d_mod = TRUE;
    }
    if (msk.field(F_DELABI).dirty())
    {               
      abi = n_abi;
      d_mod = TRUE;
    }
    if (msk.field(F_DELCAB).dirty())
    {             
      cab = n_cab;
      d_mod = TRUE;
    }
    if (msk.field(F_DELCON).dirty())
    {             
      con = n_con;
      d_mod = TRUE;
    }
    if (msk.field(F_VARIMP).dirty() || msk.field(F_VARIMP_DC).dirty())
    {
      varimp = n_varimp;
      l_mod = TRUE;
    }
    if (msk.field(F_IMPNONVER).dirty())
    {
      impnonver = n_impnonver;
      l_mod = TRUE;
    }
    
    if (msk.field(F_CREDSPEC).dirty())
    {
      credspec = n_credspec;
      l_mod = TRUE;
    }
    
    if (recorded) recorded = !(d_mod || l_mod); 
    
    if (k == K_INS || k == K_SAVE)
    {
      recalc_liq_data(&vsw, rimborso, rettifica, vers, acconto, varimp, impnonver, credspec,
                      desc1, desc2, desc3, date, abi, cab, con);
    }  
    if (k == K_SAVE) 
    {
      { write_liq(); recalc_next_liq(m, _liq_sheet, _vers_sheet); }
      if (d_mod) { write_del(); }
      l_mod = d_mod = FALSE;   
      recorded = TRUE;   
    }
    if (k == K_QUIT)
    {
      if (!recorded)
      {
        KEY kk = yesnocancel_box(TR("Modifiche non registrate: salvare?"));
        if (kk == K_YES)
        {    
          if (l_mod) { write_liq(); recalc_next_liq(m, _liq_sheet, _vers_sheet); }
          if (d_mod) { write_del(); }  
          l_mod = d_mod = FALSE;   
          recorded = TRUE;
        } 
        if (kk == K_YES || kk == K_NO) 
          break;
      }
      else break;
    }
  }  

  remove(f);

  return recorded;
}    


real Visliq_app::credito_utilizzato(int year, int month) const
{
  real credito;

  TTable lim("LIM");
  TString16 cod;
  for (int m = 1; m <= month; m++)
  {       
    cod.format("%04d%02d", year, m);
    lim.put("CODTAB", cod);
    if (lim.read() == NOERR)
    {
      if (m < month)
        credito += lim.get_real("R15"); // Credito utilizzato IVA
      if (m < 13)
        credito += lim.get_real("R16"); // Credito utilizzato F24
    }
  }
  
  return credito;
}

HIDDEN void replace_number(TViswin* vsw, long rig, real num, int tab)
{
  TString16 str;
  if (num.is_zero())
    str.spaces(15);
  else
  {
    const TCurrency c(num);
    str = c.string(TRUE);
    str.right_just(15);
  }
  vsw->replace(rig, str,  tab);
}

real Visliq_app::min_vers(int anno, int month)
{
  TInteressi_IVA_table ver;  
  real min;
  if (month > 12)
  { 
    if (ver.read(_year, 12) == NOERR)
      min = ver.get(I_ANNUALE);
  }
  else
  {
    if (ver.read(_year, month) == NOERR)
      min = ver.get(I_PERIODICO);
  }
  return min;
}

void Visliq_app::recalc_liq_data(TViswin* vsw, real& rimb, real& rett, real& vers, 
                                 real& acc, real& varimp, real& impnonver, real & credspec,
                                 TString& d1, TString& d2, TString& d3, TDate& date, 
                                 TString& abi, TString& cab, TString& con)
{                                   
  // ricalcola tutto, scrive nei lim, NON salva e riaggiusta
  // la paginata della liquidazione            
  //                                         Descrizione               Da ricalcolare  
  // -------------------------------------------------------------------------------
  real iva_ven  = _lam->get_real("R0");   // IVA acquisti              no
  real iva_acq  = _lam->get_real("R1");   // IVA vendite               no
  real cre_pre  = _lam->get_real("R2");   // credito precedente        no (solo dopo)
  real deb_pre  = _lam->get_real("R3");   // debito precedente         no (solo dopo)
  real ris      = _lim->get_real("R0");   // risultato                 si
  real rmb      = _lim->get_real("R1");   // rimborso                  si
  real rtt      = _lim->get_real("R5");   // rettifica                 si
  real udt      = _lim->get_real("R6");   // ult. detrazioni           no
  real cgp      = _lim->get_real("R7");   // conguaglio prorata        no
  real vrs      = _lim->get_real("R8");   // versamenti                no
  real vri      = _lim->get_real("R9");   // versamenti integrativi    no
  real itt      = _lim->get_real("R10");  // tasso interesse           no
  real act      = _lim->get_real("R11");  // acconto                   si
  real crd      = _lim->get_real("R12");  // totale a credito          si
  real dbt      = _lim->get_real("R13");  // totale a debito           si
  real itr      = _lim->get_real("R14");  // interesse totale          si
  real cui      = _lim->get_real("R15");  // Credito utilizzato iva    si
  real var      = _lim->get_real("R17");  // Variazioni d'imposta      no
  real inv      = _lim->get_real("R18");  // Imposta non versata       no
  real crs      = _lim->get_real("R19");  // Crediti speciali          no
  // -------------------------------------------------------------------------------
  const int year = atoi(_lim->get("CODTAB").mid(0, 4));
  const int month = atoi(_lim->get("CODTAB").mid(4, 2));
  const bool after2000 = _year >= 2000;  // CM000222

  if (month == 13 || after2000)   
  {
    // molto codice duplicato, ma ne val la pena (vedi sopra)
    round_imposta(vrs);
    round_imposta(vers);
    round_imposta(rmb);
    round_imposta(rimb);
    round_imposta(rtt);
    round_imposta(rett);
    round_imposta(act);
    round_imposta(acc);
    round_imposta(var);
    round_imposta(varimp);
    round_imposta(inv);                          
    round_imposta(impnonver);
    round_imposta(crs);                          
    round_imposta(credspec);
  }
 
  // calcola vecchio risultato: se e' diverso da R0 ci sono cazzi strani
  // e invalidiamo B0 cosi' impara                                      
  real risul = iva_ven - iva_acq - udt + rmb + cgp - vri + rtt - act - cre_pre + deb_pre +
               var + inv - cui - crs;

  if (risul != ris) 
  { 
#ifdef DBG
    yesnofatal_box("Porca vacca: Risultato non coincidente!");
#endif
    _lim->put("B0", "X");
  }
  

  // calcola nuovi dati
  real riscr   = iva_acq + udt  + acc + cre_pre + credspec;
  real risdb   = iva_ven + rimb + deb_pre + impnonver;

  if (rett.sign() < 0) riscr -= rett;
  else                 risdb += rett;
  if (cgp.sign() < 0)  riscr -= cgp;
  else                 riscr += cgp;                     
  if (varimp.sign() < 0) riscr -= varimp;
  else                   risdb += varimp;

  real credito_utilizzato_iva = ZERO;
  const bool new_age_2000 = (_year >= 2000) && look_lia() && (_lia->get("S9") == "NV");
  if (new_age_2000)
  {
    real credito_utilizzabile_inizio_anno = _lia->get_real("R0") - _lia->get_real("R15");
    if (credito_utilizzabile_inizio_anno < ZERO)
      credito_utilizzabile_inizio_anno = ZERO;
   
    risul = risdb - riscr;
    if (risul > ZERO && credito_utilizzabile_inizio_anno > ZERO)
    {                      
      real credito_utilizzabile = credito_utilizzabile_inizio_anno;
     
      credito_utilizzabile -= credito_utilizzato(year, month); 
      if (credito_utilizzabile < ZERO) credito_utilizzabile = ZERO;
      if (month < 13)
        credito_utilizzato_iva = min(risul, credito_utilizzabile);
      else
        credito_utilizzato_iva = credito_utilizzabile;             
      round_imposta(credito_utilizzato_iva);
      riscr += credito_utilizzato_iva;
    }
  }

  risul = risdb - riscr;
  
  real intr(0.0);

  if (!itt.is_zero() && risul.sign() > 0)
  {
    // calcola interesse
    intr = risul * itt / real(100.0);
    intr.ceil();
    if (after2000)
      round_imposta(intr); 
  }

  // riaggiusta LIM
  _lim->put("R0",  risul);
  _lim->put("R1",  rimb);
  _lim->put("R5",  rett);
  _lim->put("R8",  vers);
  _lim->put("R11", acc);
  _lim->put("R12", riscr);
  _lim->put("R13", risdb);
  _lim->put("R14", intr);
  _lim->put("R15", credito_utilizzato_iva);
  _lim->put("R17", varimp);
  _lim->put("R18", impnonver);
  _lim->put("R19", credspec);

  _lim->put("S0", d1);
  _lim->put("S1", d2);
  _lim->put("S2", d3);

  // i dati dei versamenti si schiaffano in LIM: 
  // D0 la data, S4/5/6 le tre cazzate ABI CAB CON 
  _lim->put("D0",  date);
  _lim->put("S4",  abi);
  _lim->put("S5",  cab);
  _lim->put("S6",  con);

  // determina righe da cambiare  
  // una sburlata di search ......
  int  x       = 0;  
  long lvers   = -1l;
  long line    = vsw->search(TR("CALCOLO LIQUIDAZIONE D'IMPOSTA"), x);
  int  wasdebt = ris.sign();
  long lrisd   = vsw->search(TR("RISULTATO"), x, line, TRUE);     // RISULTATO a debito
  long lrisc   = vsw->search(TR("RISULTATO"), x, lrisd+1, TRUE);  //            credito
  long lrettc  = vsw->search(TR("Rettifiche IVA a credito"),x,line,TRUE);
  long lrettd  = vsw->search(TR("Rettifiche IVA a debito"), x,line,TRUE);
  long lacct   = vsw->search(TR("Versamento acconto dicembre"),x,line,TRUE);
  long lintr   = vsw->search(TR("Interesse"),x,line,TRUE);
  long livdv   = vsw->search(TR("IVA DOVUTA"),x,line,TRUE);
  long lrivr   = vsw->search(TR("Versamenti effettuati"),x,line,TRUE);
  long lvari   = vsw->search(TR("Variazioni d'imposta"),x,line,TRUE);
  long limnv   = vsw->search(TR("Imposta non versata"),x,line,TRUE);
  long lcicd   = vsw->search(TR("Credito IVA compensabile detratto"),x,line,TRUE);
  long iadoc   = vsw->search(TR("IVA a debito o a credito per il periodo"),x,line,TRUE);
  long lrimb   = vsw->search(iadoc > 0 ? TR("Rimborsi") : TR("Iva chiesta a rimborso"),x,line,TRUE);

  if (wasdebt != 0)
    lvers = vsw->search(wasdebt < 0 ? TR("CREDITO ATTUALE") : TR("IVA DA VERSARE"),
                        x, line, TRUE);
  if (lvers == -1l)                      
    lvers = vsw->search(TR("IVA A DEBITO DA NON VERSARE"), x, line, TRUE);
  if (lvers == -1l) 
    lvers = lrisc+1l;
  
  // ... seguita da una sburlata di replace                  
  replace_number(vsw, lrimb, rimb, 75);
  
  replace_number(vsw, lrisd, risdb, 75);
  replace_number(vsw, lrisc, riscr, 58);
  replace_number(vsw, lacct, acc,   58);                    
  
  if (rett.sign() > 0)
  {
    replace_number(vsw, lrettd, rett, 75);
    vsw->replace(lrettc, "               ", 58);
  }                  
  else if (rett.sign() < 0)
  {                                     
    real rabs = abs(rett);
    replace_number(vsw, lrettd, rabs, 58);
    vsw->replace(lrettd, "               ", 75);
  } 
  else
  {
    vsw->replace(lrettc, "               ", 58);
    vsw->replace(lrettd, "               ", 75);
  }
    
  if (iadoc > 0)  // New Age 2000
  {
    int tab1 = 75, tab2 = 58;
    real v = iva_ven + rett - iva_acq;
    if (v < ZERO)
    {
      v = -v; tab1 = 58; tab2 = 75;
    }
    if (v.is_zero())
      vsw->replace(iadoc, "               ", tab1);
    else
      replace_number(vsw, iadoc, v, tab1);
      
    vsw->replace(iadoc, "               ", tab2);

    iadoc   = vsw->search(TR("IVA dovuta o a credito per il periodo"),x,line,TRUE);
    v = risul + credspec;
    if (v < ZERO)
    {
      v = -v; tab1 = 58; tab2 = 75;
    }
    if (v.is_zero())
      vsw->replace(iadoc, "               ", tab1);
    else
      replace_number(vsw, iadoc, v, tab1);

    vsw->replace(iadoc, "               ", tab2);

    TString256 ln;
    long lcrs    = vsw->search(TR("Crediti speciali"),x,line,TRUE);
     
    if (credspec.is_zero())
      vsw->replace(lcrs, "               ", 58);
    else
      replace_number(vsw, lcrs, credspec, 58);

    const bool print_intr = _freqviva == "T" && intr != 0.0;
    const char* desc_inter = TR("Interessi dovuti per liquidazioni trimestrali");
    lintr = vsw->search(desc_inter, x, line, TRUE);    
    
    if (print_intr)
    { 
      if (lintr == -1)
      {
        lintr = iadoc + 2;        
        TString desc;
        desc.format("%s %s%%", desc_inter, itt.stringa(6,2));
        vsw->replace(lintr, desc, 11);
      }
      replace_number(vsw, lintr, intr,  75);
      risul += intr;
    } 
    else
      if (lintr > 0)
      {
        ln.spaces(90);
        vsw->replace(lintr, ln, 11);
      }
    
    long idv = vsw->search(TR("IMPORTO DA"), x, iadoc, TRUE);    
    if (idv < 0)  
      idv = iadoc+6;
                     
    if (risul > ZERO)
    {  
      ln = TR("IMPORTO DA ");
      if (risul < min_vers(_year, month) && month < 13)
        ln << TR("NON ");
      ln << TR("VERSARE    ");
      replace_number(vsw, idv, risul,  75);
    }
    else              
      ln.spaces(90);
    vsw->replace(idv, ln, 23);
  }
  else
  {
    // non scrive e si sciroppa la viswin
    TString256 ln;
    ln.spaces(); ln.cut(136);       
    if (risul.sign() < 0) // Significa che in questo momento il risultato e' a credito
    {                          
      TCurrency rabs(-risul);
      TString16 str = rabs.string(TRUE); str.right_just(15);
      
      ln.overwrite(TR("CREDITO ATTUALE"), 23);
      ln.overwrite(str, 58);
      if (lintr > 0) // Quindi niente riga "Interessi " ...
      {
        vsw->replace(lintr,"         ",23);
        vsw->replace(lintr,"      ",33);
        vsw->replace(lintr," ",41);
        vsw->replace(lintr,"               ",75);
      }
      if (livdv > 0) // ...ed "IVA DOVUTA"
      {
        vsw->replace(livdv,"               ",23);
        vsw->replace(livdv,"               ",75);
      }
    }
    else if (risul.sign() >= 0) // ... altrimenti siamo a debito, in tal caso si hanno gli interessi (solo trimestrali of course)
    {                                     
      const bool print_intr = _freqviva == "T" && intr != 0.0;
      if (print_intr)
      {
        if (lintr == -1)
        {
          lintr = lrisc + 2;
          vsw->replace(lintr, TR("Interesse"), 23);
          vsw->replace(lintr, itt.stringa(6,2), 33);
          vsw->replace(lintr, "%", 43);
        }
        if (livdv == -1)
        {
          livdv = lrisc + 1;
          vsw->replace(livdv, TR("IVA DOVUTA"), 23);  
        }
        if (lintr > 0)
          replace_number(vsw, lintr, intr, 75);
        if (livdv > 0)
        {
          replace_number(vsw, livdv, risul, 75);
          risul += intr;
        }
      }
      ln.overwrite(TR("IVA DA VERSARE"), 23);

      TCurrency rabs(risul);
      TString16 str = rabs.string(TRUE); str.right_just(15);
      ln.overwrite(str, 75);
    }                                    
    vsw->replace(lvers, ln, 0);   
  }  

  if (lrivr >= 0)
  { 
    if (vers.is_zero())
      vsw->replace(lrivr, "               ", 58);                    
    else  
      replace_number(vsw, lrivr, vers, 58);
  }
  
  if (lvari >= 0)
  {
    int tab1 = 75, tab2 = 58;
    real v = varimp;
    if (v < 0)
    {
      v = -v;
      tab1 = 58; 
      tab2 = 75;
    }     
    if (!v.is_zero())
      replace_number(vsw, lvari, v, tab1);
    else
      vsw->replace(lvari, "               ", tab1);
    vsw->replace(lvari, "               ", tab2);
  }
  if (limnv >= 0)
  {   
    if (!impnonver.is_zero())
      replace_number(vsw, limnv, impnonver, 75);
    else
      vsw->replace(limnv, "               ", 75);
  }
  if (lcicd >= 0)
  { 
    if (credito_utilizzato_iva.is_zero())
      vsw->replace(lcicd, "               ", 58);
    else
      replace_number(vsw, lcicd, credito_utilizzato_iva, 58);
  }

  vsw->refresh();
}   

void Visliq_app::recalc_next_liq(int start_month, TSheet_field* sl, TSheet_field* sv)
{
  // riaggiusta le liquidazioni successive da li' in poi finche' ce n'e'
  // rimette a posto i valori nelle tokenstrunz dello sheet  
  // soltanto nello start_month i valori di LIM sono stati cambiati
  
  int step  = _freqviva == "M" ? 1 : 3;
  real rstart = _lim->get("R0");
  
  for (int i = start_month; i < 13; i += step) 
  {
    int row = (i/step) - 1;

    if (i > start_month)
    {
      if (!look_lim(i))
        break;
      
      // ricalcola LIM e LAM
      real cred = _lam->get_real("R2");
      real debt = _lam->get_real("R3");
      real risl = _lim->get_real("R0");
      real vers = _lim->get_real("R8");
      real risc = _lim->get_real("R12");
      real risd = _lim->get_real("R13"); 
      real intt = _lim->get_real("R10");
      real crf24 = _lim->get_real("R16");

      // toglie vecchio credito e debito
      risl += cred;
      risl -= debt;
      risc -= cred;  
      risd -= debt;
      
      // aggiunge nuovo credito o debito         
      real min = min_vers(_year, i);
      if (rstart.sign() < 0 || (rstart.sign() > 0 && rstart < min))
        risl += rstart;
      
      real newcred(0.0);
      real newdebt(0.0);
      if (rstart.sign() < 0) 
      {
        newcred = -rstart;  
        risc   -= rstart;
      }
      if (rstart.sign() > 0 &&  rstart < min)
      {
        newdebt = rstart;
        risd += rstart;
      }
      
      _lam->put("R2",  newcred);  
      _lam->put("R3",  newdebt);
      _lim->put("R0",  risl);
      _lim->put("R12", risc);
      _lim->put("R13", risd);
      if (intt.sign() > 0) // interessi
      {
        real intr = risl * intt / real(100.0);
        if (_year >= 2000)
          round_imposta(intr);
        _lim->put("R14",intr);
      }  
      _lim->put("R16", crf24);

      _lim->rewrite();
      _lam->rewrite();
      
      rstart = risl;
    }
    
    if (sl != NULL)
    {                  
      TToken_string& t =  sl->row(row);
      t.add(itoname(i),0);

      int sr0 = (_lim->get_real("R0")).sign();
      int sr5 = (_lim->get_real("R5")).sign();
                     
      real r0abs = abs(_lim->get_real("R0"));               
      real r5abs = abs(_lim->get_real("R5"));               
      t.add(r0abs.string(),1);  
      t.add(sr0 == 0 ? "" : (sr0 > 0 ? "D" : "C"), 2);
      t.add((_lim->get_real("R1")).string(),3);
      t.add(r5abs.string(),4);

      t.add(sr5 == 0 ? "" : (sr5 > 0 ? "D" : "C"),5);
      
      for (int kk = 3; kk < 6 ; kk++) 
        sl->enable_cell(row, kk);
      sl->enable_cell(row, 7);
      sl->enable_cell(row, 9);
      
      sl->force_update(row);
    }                             
  }                     

  // se non si fa questa non scrive una delega,
  // bensi' una bovazza (escremento bovino)
  look_lim(start_month);
}

void Visliq_app::write_liq()
{ 
  // piccola, ma simpatica
  // naturalmente era much bigger
  _lim->rewrite();
}

void Visliq_app::write_del()
{ 
  bool wasdel = FALSE;
  
  int month = atoi(*_lim_mese);
  TString abi(_lim->get("S4"));
  TString cab(_lim->get("S5"));
  TString con(_lim->get("S6"));  
  TDate  date(_lim->get("D0"));
  real   vers(_lim->get_real("R8"));   
  real   intr(_lim->get_real("R10"));

  if (vers.is_zero() && (wasdel = look_del(month,1)))
  {
    _del->remove();    
    _del->rewrite(); // ???
    return;
  }           
  
  if (!wasdel) 
    look_del(month,1,TRUE);  // Crea delega

  real inter(0.0);             
  
  if (!intr.is_zero())
  {
    // riapplica il tasso di interesse  
    // se trimestrale e' stato scorporato rispetto
    // all'eventuale input utente
    inter = vers*real(100.0)/(real(100.0)+intr);    
    inter = vers - inter;
    inter.ceil(); 
    if (_year >= 2000)
      round_imposta(inter);
  }
  
  _del->put("R0",vers);
  _del->put("R1",inter);
  _del->put("D0",date);
  _del->put("S7",abi);
  _del->put("S8",cab);
  _del->put("S9",con);

  int ctri = _freqviva == "M" ? 6000 + month : 6030 + (month/3);
  _del->put("S6", ctri);
  
  _del->rewrite();                    
}                 


void Visliq_app::read_general(TMask& m)
{
  TString abi(5);
  TString cab(5);
  TString cnc(5);
  const int step = _freqviva == "M" ? 1 : 3;
  const bool new_age_2000 = (_year >= 2000) && (_lia->get("S9") == "NV");
  
  TSheet_field& sh = m.sfield(F_VISLIQ1); 
  TSheet_field& sv = m.sfield(F_VISLIQ2); 
  TMask_field & crprec = m.field(F_CREDPREC);
                                                     
  if (new_age_2000)
    crprec.set_prompt(TR("Credito compensabile inizio anno "));
  else
    crprec.set_prompt(TR("Credito inizio anno "));
  real cr_res  = _lia->get_real("R0");
  crprec.set(cr_res.string());
  if (new_age_2000)
    cr_res -= _lia->get_real("R15");
 

  // set sheet
  for (int i = step; i < 13; i+=step)
  {                      
    int row = (i/step) - 1;    

    if (!is_month_ok(i)) 
      continue;     
    
    if (!look_lim(i))
    {
      if (sh.items() < row)
        sh.row(row) = *(new TToken_string("||||||")); 
      else 
        sh.row(row) = "||||||";
      
      sh.disable_cell(row, -1);
      continue;
    }                                   
    
    TToken_string* tt = NULL;
    if (sh.items() < row) 
      tt = new TToken_string(80); 
    else                
      tt = &(sh.row(row));
    
    real r0abs = abs(_lim->get_real("R0"));
    real r5abs = abs(_lim->get_real("R5"));
    tt->add(itoname(i),0);
    tt->add(r0abs.string(),1);
    
    int sr0 = (_lim->get_real("R0")).sign();
    int sr5 = (_lim->get_real("R5")).sign();

    tt->add(sr0 == 0 ? "" : (sr0 > 0 ? "D" : "C"),2);
    tt->add(_lim->get_real("R1").string(),3);
    tt->add(r5abs.string(),4);
    tt->add(sr5 == 0 ? "" : (sr5 > 0 ? "D" : "C"),5);
            
    const real criva = _lim->get_real("R15");
    tt->add(criva.string(), 6);
    const real crf24 = _lim->get_real("R16");
    tt->add(crf24.string(),7);
    if (new_age_2000)
    {
      if (cr_res > ZERO)
      {
        cr_res -= crf24;
        cr_res -= criva;
      }
      if (cr_res < ZERO)
        cr_res = ZERO;
      tt->add(cr_res.string(), 8);
    }
    else
      tt->add("", 8);
    tt->add(_lim->get("S3"), 9);
    
    sh.row(row) = (*tt);
  }  
  
  // calcola versamenti
  real  versamenti[13];   
  TDate date[13];   
  TToken_string banche[13]; 
  
  for (_del->first(); !_del->eof(); _del->next())
  {                    
    if (atol(*_del_ditta) != get_firm()  ||
        atoi(*_del_anno)  != _year)
      continue;
    
    // uso solo deleghe normali (tipo == 1) e acconti (tipo == 7)                              
    int tipod = atoi(*_del_tipo);
    if (tipod != 1 && tipod != 7) 
      continue;
    
    // somma versamenti nel mese adeguato  
    int m = atoi(*_del_mese);

    if (m >= 12)
      m = tipod == 7 ? 12 : 13; 
    // supercauto
    if (m <= 0) continue;
    
    versamenti[m-1] += _del->get_real("R0");
    date[m-1]        = _del->get_date("D0");
    banche[m-1].add(_del->get("S7"),0);
    banche[m-1].add(_del->get("S8"),1);
    banche[m-1].add(_del->get("S9"),2);
  }

  // Sheet versamenti
  TString nomemese;          
  sv.destroy();
  for (i = 1; i <= 13; i++)
  {  
    if (!is_month_ok(i) && i != 13) 
      continue;

    TToken_string tt; 
    nomemese = itoname(i == 13 ? 12 : i);              
    
    if (nomemese == "4 Trimestre") 
      nomemese = "4 Tr.";
    
    if (i == 12) nomemese << TR(" acconto");
    if (i == 13) nomemese << TR(" saldo");
    
    tt.add(nomemese,0);                // mese
    tt.add(date[i-1].string(),1);      // data vers.
    tt.add(banche[i-1].get(0),2);      // azienda
    tt.add(banche[i-1].get(1),3);      // dipendenza
    tt.add(banche[i-1].get(2),4);      // concessionaria
    tt.add(versamenti[i-1].string(),5);// versamenti 
    
    sv.row(-1) = tt;    
    if (i == 12) 
      sv.enable_cell(sv.items() - 1, -1, FALSE);
  }  
  
  // sh.enable_column(0, FALSE);
  // sv.enable_column(0, FALSE);

  sh.force_update();
  sv.force_update();
  
  // save initial rows
  _vers_rows = sv.rows_array();
  _liq_rows  = sh.rows_array();

  m.field(F_CREDPREC).set_dirty(FALSE);
  m.field(F_VISLIQ1).set_dirty(_sh_dirty=FALSE);
  m.field(F_VISLIQ2).set_dirty(_sv_dirty=FALSE);
}

void Visliq_app::write_general(TMask& m)
{ 
  TSheet_field& sh = (TSheet_field&)m.field(F_VISLIQ1); 
  TSheet_field& sv = (TSheet_field&)m.field(F_VISLIQ2); 
  const bool new_age_2000 = (_year >= 2000) && (_lia->get("S9") == "NV");

  if (m.field(F_CREDPREC).dirty())
  {                
    const real r = m.get(F_CREDPREC);
    _lia->put("R0",r);
    _lia->rewrite();        
  }                             
  
  // credito iniziale
  real rstart = _lia->get_real("R0");  
  real cr_res;
  if (!new_age_2000)
  {
    if (!rstart.is_zero())
      rstart = -rstart;
  } 
  else 
    cr_res = rstart - _lia->get_real("R15");
  
  // indicatore ricalcolo crediti e debiti OK
  int step    = _freqviva == "M" ? 1 : 3;
  bool carry  = TRUE;
  bool was_lim;
  TMask& shm = sh.sheet_mask();
  TMask& svm = sv.sheet_mask();
  
  for (int i = step; i < 13; i += step)
  {
    // this is a true bordel                            
    const int row = (i/step) - 1;    
    
    bool lfrommask = sh.selected() == row && (shm.is_running() || _from_one);
    bool vfrommask = sv.selected() == (i == 12 ? row + 1 : row) && svm.is_running();
    
    TToken_string& tt_lo = (TToken_string&)_liq_rows[row]; 
    TToken_string& tt_ln = sh.row(row);  
    
    // risolve menata del dettaglio si'/no  
    if (lfrommask)
    {    
      for (int i = 1; i <= 9; i++)
        tt_ln.add(shm.get(101+i),i);
    }

    // saltare una riga se dicembre (riga 11 == acconto)  
    TToken_string& tt_vo = (TToken_string&)_vers_rows[i == 12 ? row + 1 : row]; 
    TToken_string& tt_vn = sv.row(i == 12 ? row + 1 : row); 

    if (vfrommask)
    { 
      for (int i = 1; i <= 5; i++)
        tt_vn.add(svm.get(101+i),i);
    }
    
    // traduci contenuto righe in real pila
    real    orett(tt_lo.get(4));
    real    nrett(tt_ln.get(4));
    real    orimb(tt_lo.get(3));
    real    nrimb(tt_ln.get(3));
    real    overs(tt_vo.get(5));
    real    nvers(tt_vn.get(5));
    real    crf24(tt_ln.get(7));
    TDate   odate(tt_vo.get(1));
    TDate   ndate(tt_vn.get(1));
    TString odbcr(tt_lo.get(5));
    TString ndbcr(tt_ln.get(5));
    TString oabi (tt_vo.get(2));
    TString nabi (tt_vn.get(2));
    TString ocab (tt_vo.get(3));
    TString ncab (tt_vn.get(3));
    TString ocon (tt_vo.get(4));
    TString ncon (tt_vn.get(4));
    TString descr(tt_ln.get(9));

    if (odbcr == "C") orett = -orett;
    if (ndbcr == "C") nrett = -nrett;
    
    // acconto (si considerera' solo a dicembre)
    TToken_string& vo = (TToken_string&)_vers_rows[_freqviva == "M" ? 11 : 3]; 
    TToken_string& vn = sv.row(_freqviva == "M" ? 11 : 3);     
    real    oacct (vo.get(5));
    real    nacct (vn.get(5));
    TDate   aodate(vo.get(1));
    TDate   andate(vn.get(1));
    TString aoabi (vo.get(2));
    TString anabi (vn.get(2));
    TString aocab (vo.get(3));
    TString ancab (vn.get(3));
    TString aocon (vo.get(4));
    TString ancon (vn.get(4));
          
    was_lim = look_lim(i);      
    if (!was_lim)
      carry = FALSE; // blocca riporto crediti e debiti
    
    // ricalcola crediti e debiti se non ci sono 
    // liquidazioni non calcolate in mezzo
    if (carry)
    {
      bool rt_mod = FALSE, rm_mod = FALSE, vr_mod = FALSE;

      real risl = _lim->get_real("R0");
      real vers = _lim->get_real("R8");
      real risc = _lim->get_real("R12");
      real risd = _lim->get_real("R13"); 

      // ricalcola acconto se occorre
      // e crea/aggiorna la delega
      if (i == 12)
      { 
        bool ac_mod = FALSE;
        if (oacct != nacct)
        {
          risc -= oacct;
          risc += nacct;
          risl += oacct;  
          risl -= nacct;
          _lim->put("R11", nacct);
          ac_mod = TRUE;
        }           
        if (ndate != odate || anabi != aoabi || ancab != aocab || ancon != aocon)
          ac_mod = TRUE;                                                   
        // write delega acconto
        if (ac_mod)
        {
          look_del(12,7,TRUE);
          _del->put("R0",nacct);
          _del->put("R1","");
          _del->put("S7",anabi);
          _del->put("S8",ancab);
          _del->put("S9",ancon);   
          _del->put("S6","6013");
          _del->rewrite();
        }
      }
      
      // ricalcola versamenti se occorre 
      // e crea/aggiorna le deleghe
      if (nvers != overs)
      { 
        vr_mod = TRUE;
      } 
      if (vr_mod || ndate != odate || nabi != oabi || 
          ncab != ocab || ncon != ocon)
      {              
        _lim->put("R8", nvers);
        _lim->put("D0", ndate);
        _lim->put("S4", nabi);
        _lim->put("S5", ncab);
        _lim->put("S6", ncon); 
        write_del();
        vr_mod = TRUE;
      }

      // se modificate rettifiche 
      // sistemare
      if (nrett != orett && !_from_one)
      { 
        // toglie vecchie
        risl -= orett; 
        if (orett.sign() < 0)
          risc += orett;
        else
          risd -= orett;
        // aggiunge nuove
        risl += nrett; 
        if (orett.sign() < 0)
          risc -= nrett;
        else
          risd += nrett; 
        
        // scrivi
        _lim->put("R5",nrett); 
        tt_lo.add(nrett.string(), 4);
        tt_lo.add(nrett.sign() > 0 ? "D" : (nrett.is_zero() ? "" : "C"), 5);
        
        // elimina descrixioni se nuove rett. sono 0
        if (nrett.is_zero())
        {
          _lim->put("S0","");
          _lim->put("S1","");  
        }
      }
      
      // controlla se qualcosa e' modificato e scrivi 
      // il valore; check compatibilita' versamenti e rimborsi

      // rileggi dati
      real cred = _lam->get_real("R2");
      real debt = _lam->get_real("R3");
      real intt = _lim->get_real("R10");

      // toglie vecchio credito e debito
      risl += cred;
      risl -= debt;
      risc -= cred;  
      risd -= debt;
      
      // aggiunge nuovo credito o debito  
      real min = min_vers(_year, i);
      if (rstart.sign() < 0 || (rstart.sign() > 0 && rstart < min))
        risl += rstart;
      
      real newcred(0.0);
      real newdebt(0.0);
      if (rstart.sign() < 0) 
      {
        newcred = -rstart;  
        risc   -= rstart;
      }
      if (rstart.sign() > 0 &&  rstart < min)
      {
        newdebt = rstart;
        risd += rstart;
      }

      // se modificato rimborso sistemare     
      if (nrimb != orimb && !_from_one)
      {
        // check compatibilita'
        bool ok = TRUE; 
               
        if (!nrimb.is_zero()) 
        {              
          if (risc <= risd)  
            ok = yesno_box(FR("Il risultato IVA non evidenzia crediti nel mese %d. Si conferma "
                           " il rimborso?"), i); 
          if (!_lim->get_bool("B2") && ok)
            ok = yesno_box(FR("Non risulta diritto al rimborso per il mese %d. Si conferma"
                           " il rimborso?"), i); 
        }

        if (ok)
        {
          // togli vecchio
          risd -= orimb;
          risl -= orimb;  
          // aggiungi nuovo   
          risd += nrimb;
          risl += nrimb;   
          // scrivi
          _lim->put("R1", nrimb); 
          tt_lo.add(nrimb.string(), 3);
        }
      }         
      _lam->put("R2",  newcred);  
      _lam->put("R3",  newdebt);
      _lim->put("R0",  risl);
      _lim->put("R12", risc);
      _lim->put("R13", risd);

      if (intt.sign() > 0) // interessi
      {
        real intr = risl * intt / real(100.0);
        if (_year >= 2000)
          round_imposta(intr);
        _lim->put("R14",intr);
      }  

      _lim->put("R16", crf24);
      if (new_age_2000)
      {
        const real criva(tt_ln.get(6));
        if (cr_res > ZERO)
        {
          cr_res -= crf24;
          cr_res -= criva;
        }
        if (cr_res < ZERO)
          cr_res = ZERO;
      }         
      _lim->put("S3", descr);

      _lim->rewrite();
      _lam->rewrite();
      
      rstart = risl;
    }
    else 
    {
      // salva i valori modificati senza fare controlli
      // e rimetti a lui i suoi debiti mettendo B0 a FALSE   
      if (was_lim)
      {
        if (orett != nrett)
          _lim->put("R5", nrett);
        if (orimb != nrimb)
          _lim->put("R1", nrimb);
        _lim->put("R16", crf24);
        _lim->put("S3", descr);
        _lim->put("B0", ""); 
        _lim->rewrite(); 
      }
    }  

    // Rimetti a posto righe sheet se serve
    if (was_lim)
    {
      int sr0 = (_lim->get_real("R0")).sign();
      int sr5 = (_lim->get_real("R5")).sign();
    
      real r0abs = abs(_lim->get_real("R0"));
      real r5abs = abs(_lim->get_real("R5"));
    
      tt_ln.add(r0abs.string(),1);  
      tt_ln.add(sr0 == 0 ? "" : (sr0 > 0 ? "D" : "C"), 2);
      tt_ln.add((_lim->get_real("R1")).string(),3);
      tt_ln.add(r5abs.string(),4);
      tt_ln.add(sr5 == 0 ? "" : (sr5 > 0 ? "D" : "C"),5);
      tt_ln.add(cr_res.string(),8);
    
      // sh.force_update(row);
    }
    _from_one = FALSE;      
  } // for mese liq. (riga sheet)

  sh.force_update(); 
  if (shm.is_running())
    sh.force_update(sh.selected()); 
  // Rileggi array righe vecchie
  set_vers_rows(sv);  
  set_liq_rows(sh); 

  // m.dirty() deve ritornare FALSE  
  m.field(F_CREDPREC).set_dirty(FALSE);
  m.field(F_VISLIQ1).set_dirty(_sh_dirty=FALSE);
  m.field(F_VISLIQ2).set_dirty(_sv_dirty=FALSE);
}



int cg5500(int argc, char* argv[])
{
  Visliq_app app;
  app.run(argc, argv, TR("Visualizzazione Liquidazione"));
  return 0;
}