#include "pagament.h"
#include <utility.h>

int Pagamento::_rata_ifield(int n, int f) const
{                                     
  TToken_string& t = (TToken_string&)_rate[n];
  return t.get_int(f);
}                            

real Pagamento::_rata_rfield(int n, int f) const
{                                     
  TToken_string& t = (TToken_string&)_rate[n];
  return real(t.get(f));
}                            

TDate Pagamento::_rata_dfield(int n, int f) const
{                                     
  TToken_string& t = (TToken_string&)_rate[n];
  return TDate(t.get(f));
}                                 

const char* Pagamento::_rata_sfield(int n, int f) const
{                                     
  static char kak[6];
  TToken_string& t = (TToken_string&)_rate[n];
  strcpy(kak,t.get(f)); 
  return kak;
}                                 


bool Pagamento::ratapagata(int n)
{
  TToken_string& t = (TToken_string&)_rate[n];
  return t.items() > 6;
}



void Pagamento::set_intervallo_rate(int in)
{
  _dirty = TRUE;
  if (_mcomm  && (in % 30) != 0)
    _mcomm = FALSE;
  for (int i = 0; i < n_rate(); i++)
    {       
      TToken_string& ts = rata(i);
      ts.add(i == 0 ? (scad_rata(0) == 0 ? "0" : format("%d",in)) 
      	            : format("%d",in), 0);		
    }
}

void Pagamento::set_mese_commerciale(bool v, int& sscad)
{
  _dirty = FALSE;
  if (_mcomm == v) return;  
  if (sscad == -1) sscad = 30;
  
  if ((sscad % 30) != 0) sscad = 30 * ((sscad/30)+1);
  set_intervallo_rate(sscad);
  
  _mcomm = v;	
}        

void Pagamento::set_rate_differenziate(int v)
{                           
  _dirty = FALSE;
  if (!_rdiff && v == 2) return; 
  
  if (v == 2 && (100 % n_rate()) == 0)
  {
      int p = 100 / n_rate();
      for (int i = _tpr == 0 ? 0 : 1; i < n_rate(); i++)
	  {
	    TToken_string& tt = rata(i);
	    tt.add(p,1);
	  }
      _rdiff = !(v == 2);
      _dirty = TRUE;
  }
}

void Pagamento::set_tipo_prima_rata(int v, int sscad)
{                           
  _dirty = FALSE;
  if (_tpr == v) return;
  
  if (v == 0 && _tpr > 0)
    {
      for (int i = n_rate() - 1; i > 0; i--)
    	{
	  TToken_string& tt = rata(i);
	  tt.add(scad_rata(i-1),0);
	  tt.add(tipo_rata(i-1),2);
	  tt.add(ulc_rata(i-1),5);
    	}
      _rate.add(NULL,0);
      _rate.pack();	
    }
  else if ( _tpr == 0 && v > 0)                    
    {   
      TToken_string* ttn = new TToken_string(32);
      ttn->add(0,0);
      ttn->add(0,1);
      ttn->add(1,2);
      ttn->add("",3);
      ttn->add("",4);
      ttn->add("",5);
      _rate.insert(ttn,0);
      for (int i = 0; i < (n_rate()-1); i++)
	  {
       	TToken_string& tt = rata(i);   
	    tt.add(scad_rata(i+1),0);
	    tt.add(tipo_rata(i+1),2);
	    tt.add(ulc_rata(i+1),5);
	  }
    }
  _tpr = v;    
  _dirty = TRUE;
}

void Pagamento::set_numero_rate(int n, int sscad)
{                         
  _dirty = FALSE;
  if (n == 0 || n == n_rate()) return; 
  
  int p =   100 / n;
  int nr = n_rate();
  int first = _tpr == 0 ? 0 : 1;
  
  for (int i = first, sum = 0; sum < 100; i++)
    {
      if ((100 - sum) < p) p = 100 - sum;
      sum += p; 
      
      set_rata(i, real(p), 
	       i == 0 ? (i < nr ? scad_rata(0) : 0):
	       (sscad == -1 ? (i < nr ? scad_rata(i) : scad_rata(nr-1)) : sscad),
	       (i < nr ? tipo_rata(i) : tipo_rata(nr-1)));
    }          
  // erase remaining  
  for (; i < n_rate(); i++) 
  	_rate.add(NULL,i);
  _rate.pack();
  
  _dirty = TRUE;
}


void Pagamento::next_scad(TDate& d, int scad, bool mcomm, int rata)
{
  if (mcomm)
    {
      int nm   = scad / 30;
      int ny   = nm   / 12;
      nm  %= 12;
      
      int newm = d.month() + nm;
      if (newm > 12) { newm -= 12; ny++; }
      
      bool last = d.is_end_month() && inizio_scadenza() == 'M';
      
      int dy = d.day();
      
      // la palla del febbraio & c.                                    
      if (rata > 1)
        {
	  TDate oldd(data_rata(rata-2));
	  if (oldd.day() > dy) dy = oldd.day();
        }	
      
      d.set_day(1);  // il giorno 1 ce l'hanno tutti
      d.set_month(newm);
      d.set_year(d.year()+ny);
      
      d.set_end_month();  
      if (!last && dy < d.day()) 
	d.set_day(dy);
    }
    else 
    {
	d += scad;
    }
}


void Pagamento::remove_rata(int i)
{                         
  // non fa nessun ricalcolo, si limita ad impacchettare se 
  // necessario
  _rate.add(NULL,i);
  _rate.pack();
  _dirty = TRUE;
}             

TToken_string& Pagamento::add_rata(real perc, int day, int type)
{
  TToken_string* tt = new TToken_string(16);
  tt->add(day);                // scadenza
  tt->add(perc.string());      // percentuale
  tt->add(type);               // tipo
  tt->add("");
  tt->add("");
  tt->add("");
  _rate.add(tt);             
  _dirty = TRUE;
  return *tt;
}

TToken_string& Pagamento::set_rata (int index, real perc, int day, int type,
				    const char* ulc, const char* imp, 
				    const char* data)
{                                   
  bool nwr = FALSE;
  TToken_string* tt = (TToken_string*)_rate.objptr(index);
  if (nwr = (tt == NULL)) tt = new TToken_string(16); 
  tt->add(day,0);                // scadenza
  tt->add(perc.string(),1);      // percentuale
  tt->add(type,2);               // tipo 
  tt->add(data == NULL ? "" : data,3);
  tt->add(imp  == NULL ? "" : imp,4);
  tt->add(ulc  == NULL ? "" : ulc,5);
  
  if (!nwr)
    {
      if (index > _rate.items()) 
	{   
	  error_box("Rate non contigue");
	  delete tt;
	}
    } 
  else 
    {
      _rate.add(tt,index);   
      _dirty = TRUE;
    }
  return *tt;
}                                

void Pagamento::set_imprata(int i, real r)
{
  TToken_string& tt = (TToken_string&)_rate[i];  
  TDate d = _inizio; 
  
  for (int n = 0; n <= i; n++)
    next_scad(d, scad_rata(n), _mcomm, n); 
  
  tt.add((const char*)d, 3);
  tt.add(r.string(), 4);
}
                                        
TToken_string& Pagamento::set_rata(int index, real howmuch, 
	TDate& date, int type,const char* ulc, bool pagato)
{
  // calcola percentuali e scadenze a partire dagli importi 
  bool nwr = FALSE;
  TToken_string* tt = (TToken_string*)_rate.objptr(index);
  if (nwr = (tt == NULL)) 
  	tt = new TToken_string(16); 

  TDate oldd = index > 0 ? data_rata(index -1) : _inizio;
  int day    = date - oldd; 
  real toshare(_tpr == 0 ? _firstr : _secndr);    
  real perc = (_tpr > 0 && index == 0) ? 0.0 : howmuch/toshare; 
  perc *= real(100.0);
  perc.round(2);
  
  tt->add(day,0);                // scadenza
  tt->add(perc.string(),1);      // percentuale
  tt->add(type,2);               // tipo 
  tt->add(date.string(),3);
  tt->add(howmuch.string(),4);
  tt->add(ulc,5);
  if (pagato) tt->add("X",6);

  if (!nwr)
    {
      if (index > _rate.items()) 
	  {   
	    error_box("Rate non contigue");
	    delete tt;
	  }
    } 
  else 
    {
      _rate.add(tt,index);   
      _dirty = TRUE;
    }
  return *tt;
}
                                        
                                        

word Pagamento::validate() const
{
  word res = 0x0000; 
  real r(0.0);
  
  int first    = _tpr == 0 ? 0 : 1;        
  real toshare(_tpr == 0 ? _firstr : _secndr);    
  TDistrib ds(toshare,0);          
  
  // check percentages & prepare slicer
  for (int i = first; i < n_rate(); i++)
    {                
      real p(perc_rata(i));
      ds.add(p);
      r += p; 
    }
  
  if (r != real(100.0))
    res |= P_RSUM;            
  
  
  if (_inited)
    {
      ds.init(toshare);
      // check importi rate consistenti con la percentuale
      for (int i = first; i < n_rate(); i++)
	{                 
	  real r1(tpay_rata(i));  
	  real r2(ds.get());
	  if (r1 != r2) 
	    { res |= P_IMPNC; break; }		
	}     
      
      // check errori date scadenze (se istanziate)
      TDate d(data_rata(0));
      if (d < _inizio) 
      	res |= P_INIZIO;
      for (i = 1; i < n_rate(); i++)
	{
	  if (data_rata(i) <= d) 
	    { res |= P_SCAD; break; }
	  d = data_rata(i);
	}     
    }
  return res;
}                                                                     


void Pagamento::strerr(word err, TString& s)
{
  s = "Errore:";
  if (err & P_RSUM)
    s << "\n   Le percentuali non sommano a 100";
  if (err & P_IMPNC)
    s << "\n   Le percentuali sono inconsistenti con gli importi";
  if (err & P_SCAD)
    s << "\n   Le scadenze non sono consecutive";
  if (err & P_INIZIO)
    s << "\n   La prima rata e' antecedente alla data movimento";
}

const char* Pagamento::desc_tpr() const
{            
  const char* o;
  switch (_tpr)
    {
    case 0: o = "Totale su tutte le rate"; break;
	  case 1: o = "Tutte le imposte su 1a"; break;
	  case 2: o = "Tutte le spese su 1a"; break;
	  case 3: o = "Imposte + spese su 1a"; break;
	  case 4: o = "Spese + merce su 1a"; break;
	  case 5: o = "Merce + imposte su 1a"; break;
	  case 6: o = "Tutta la merce su 1a"; break;
	  } 
  return o;
}                        

const char* Pagamento::desc_tipo(int i) const
{         
  const char* o;
  switch (i)
    {   
    case 1: o = "Rimessa diretta / contanti"; break;
	  case 2: o = "Tratta"; break;
	  case 3: o = "Ricevuta bancaria"; break;
	  case 4: o = "Cessione"; break;
	  case 5: o = "Paghero'"; break;
	  case 6: o = "Lettera di credito"; break;
	  case 7: o = "Tratta accettata"; break;                   
	  case 8: o = "Altro pagamento"; break;
	  } 
  return o;            
}

word Pagamento::recalc_rate(int row, bool is_perc_modified, 
                            const char* new_value, const char* scad, 
                            const char* typ, int rdiff, bool mcomm,
                            bool& need_recalc)
     // ricalcola le rate sulla base di parametri modificati sulla riga row
     // parametri: tutti i const char* possono essere NULL, il che vuol dire
     //              che i dati corrispondenti non sono stati modificati;
     //            se new_value non e' NULL puo' essere la percentuale (e 
     //              allora is_perc_modified e' TRUE) o l'importo. Non e'
     //              possibile modificare entrambi; se succede viene data
     //              priorita' alla percentuale.
{                                     
  CHECK(!(!is_perc_modified &&  new_value != NULL && !_inited), 
        "A'stronzo! E famme 'na pippa! Me dai n'importo che nun ce sta? Ma Vaffanculo!");
  
  if (_rate.items() == 0) return P_OK;
  
  real rsum(0.0), newv(0.0), rmax(0.0); 
  int oldtype    = tipo_rata(0);
  int oldscad    = scad_rata(0);
  TDate lastdate = data_rata(0);  
  int first      = _tpr == 0 ? 0 : 1;
  TArray srate(_rate);   // rate come erano   
  
  
  if (srate.items() > 1)
    {
  	// calcola defaults per tipo pagamento e scadenza
      // nel caso di rate nuove
      oldscad = scad_rata(1);
    }       
  
  if (oldscad == 0) oldscad = 30;
  if (oldtype == 0) oldtype = 1;
  
  if (new_value != NULL)
    {     
      newv = new_value;                       
      rmax = is_perc_modified? (real) 100.0 : (_tpr == 0 ? _firstr : _secndr);
      if (newv > rmax) return P_RSUM;
    }                                                   
  
  bool exhausted = FALSE;
  
  for (int i = first; i < srate.items(); i++)
    {
      if (i == row)
	{  
	  if (typ != NULL)
	    {	
	      TToken_string& tt = rata(row);
	      TToken_string& ss = (TToken_string&)srate[row];
	      tt.add(typ,2);
	      ss.add(typ,2);			                     
	      // no error is possible
	    }
	  
	  if (scad != NULL)
	    {		
	      // if !_inited scad e' il n. giorni, se no e' la rata 
	      if (_inited)
		{
		  TToken_string& tt = rata(row);
		  TToken_string& ss = (TToken_string&)srate[row];
		  lastdate = scad;                             
		  // controlla errore sulla data scadenza
		  if (i > 0) 
		    {
		      oldscad  =  (int)(lastdate - data_rata(i-1)); 
		      if (oldscad <= 0l) return P_SCAD;
		    }
		  else if (lastdate < _inizio) return P_INIZIO;
		  tt.add(scad,3);
		  ss.add(scad,3);      
		  // ricalcola rate successive: se si vuole modificarne solo una
		  // ci si fotte e si disabilita il ricalcolo
		  TDate ddd (lastdate);
		  for (int j = row+1; j < srate.items(); j++)
		    {	
		      TToken_string& tt = rata(j);
		      TToken_string& ss = (TToken_string&)srate[j];
		      next_scad(ddd,scad_rata(j),mcomm,j);
		      tt.add(ddd.string(),3);
		      ss.add(ddd.string(),3);
		      need_recalc = TRUE;      
		    }
		}
	      else
		{ 
		  // nulla di speciale visto che si memorizza la derivata
		  int sc = atoi(scad);
		  for (int i = 0; i < row; i ++)
		    sc -= scad_rata(i);
		  if (sc < 0 || (row > 0 && sc == 0)) return P_SCAD;
		  if (_mcomm && (sc % 30) != 0) _mcomm = FALSE;
		  TToken_string& tt = rata(row);
		  TToken_string& ss = (TToken_string&)srate[row];
		  tt.add(sc,0);
		  ss.add(sc,0);
		  need_recalc = TRUE;				
		}       
	    }                 
	  
	  // here's the bell
	  if (new_value != NULL)
	    {                       
	      if (newv == ZERO || (rsum+newv) > rmax) 
		return P_RSUM; 
	      // did not sforate
	      rsum += newv;         
	      TToken_string& rt = rata(row);
	      // setta nuovo valore e ricalcola cio' che ne consegue
	      if (is_perc_modified) rt.add(new_value,1);
	      else rt.add(new_value,4);
	      // riaggiusta le rate rimanenti
	      real remainder(0.0); remainder = rmax - rsum;
	      if (!(exhausted = (remainder == real(0.0))))
		{                                            
		  // controlla se rdiff e' compatibile con
		  // i dati e se e' il caso riaggiusta
		  if (rdiff == 3 && !((remainder % newv.integer()) == ZERO))
		    rdiff = 2;
		  if (rdiff == 2 && !((rmax % newv.integer()) == ZERO)) 
		    rdiff = 1;                   
		  _rdiff = (rdiff == 1 || rdiff == 3 || rdiff == 4);
		  
		  // procedi			
		  if (rdiff == 1) 
		    {
		      // cancella tutte le rate successive, aggiungi un'unica rata 
		      // con il resto dell'importo                                
		      if (row < (srate.items()-1))
			{
			  TToken_string& trt = rata(row+1);
			  trt.add(remainder.string(), is_perc_modified ? 1 : 4);     
			  for(int j = row+2; j < srate.items(); j++)
			    _rate.add(NULL,j);
			}
		      else
			{
			  // l'importante e' esagerare
			  for(int j = row+1; j < srate.items(); j++)
			    _rate.add(NULL,j); 
			  
			  TToken_string& trt = add_rata(is_perc_modified ? remainder : (real) 0.0,
																			oldscad, oldtype);
			  if (!is_perc_modified) trt.add(remainder.string(),4);
			  if (_inited)
			    { 
			      TDate dd = data_rata(row); 
			      next_scad(dd,oldscad,mcomm,row);
			      trt.add(dd.string(),3); 
			    }
			} 
		    }
		  else  // rate non differenziate (dall'inizio o da row)
		    {
		      // ripartisci l'importo nel numero necessario di rate per
		      // mantenere costante il valore 
		      real sum(0.0);
		      if (_inited) lastdate = data_rata(rdiff == 2 ? first : row);
		      
		      TDate dd(lastdate);
		      int type = oldtype;
		      int nscd = oldscad;                        
		      
		      int  frs = (rdiff == 3 || rdiff == 4) ? row+1     : first;
		      real mx  = (rdiff == 3 || rdiff == 4) ? remainder : rmax;
		      
		      // cancelliamo tutto, va'
		      for (int j = frs; j < srate.items(); j++)
			_rate.add(NULL,j);
		      
		      if (rdiff != 4)	
			for (j = frs; sum < mx; j++)
			  {	
			    // se c'e' la vecchia rata si tengono i parametri
			    // altrimenti si calcolano 
			    if (j < srate.items())
			      {   
				TToken_string& trt = (TToken_string&)srate[j];
				if (_inited) dd   = trt.get(3);
				type = atoi(trt.get(2));
				nscd = j == 0 ? 0 : atoi(trt.get(0));	
				if (type == 0) type = 1;
				if (j > 0 && nscd == 0) nscd = oldscad;
				if (_inited && dd == lastdate && j > 0) 
				  next_scad(dd,nscd,mcomm,j);
			      }
			    else if (_inited) 
			      {
				if (dd <= botime) dd = lastdate;
				next_scad(dd,nscd,mcomm,j); 
			      } 
			    
			    TToken_string& ttr = set_rata(j, is_perc_modified ? newv : ZERO,
							  nscd, type); 
			    if (_inited)
			      ttr.add(dd.string(), 3);
			    if (!is_perc_modified)
			      ttr.add(newv.string(),4);
			    sum += newv;
			  }			
		      else  // rdiff == 4; uguali finche' possibile
			{
			  bool basta = FALSE;       
			  for (j = frs; ; j++)
			    {	
			      // ultima rata puo' differire dalle precedenti     
			      if (mx - sum <= newv) 
				{
				  newv = mx - sum;
				  basta = TRUE;
				}
			      // se c'e' la vecchia rata si tengono i parametri
			      // altrimenti si calcolano 
			      if (j < srate.items())
				{   
				  TToken_string& trt = (TToken_string&)srate[j];
				  if (_inited) dd   = trt.get(3);
				  type = atoi(trt.get(2));
				  nscd = j == 0 ? 0 : atoi(trt.get(0));	
				  if (type == 0) type = 1;
				  if (j > 0 && nscd == 0) nscd = oldscad;
				  if (_inited && dd == lastdate && j > 0)
				    next_scad(dd,nscd,mcomm,j);
				}
			      else if (_inited) next_scad(dd,nscd,mcomm,j);  
			      
			      TToken_string& ttr = set_rata(j, is_perc_modified ? newv : ZERO,
							    nscd, type); 
			      if (_inited)
				ttr.add(dd.string(), 3);
			      if (!is_perc_modified)
				ttr.add(newv.string(),4);
			      if (basta) break; 
			      sum += newv;
			    }					
			}
		    }          
		  
		}
		else  // exhausted
		  {
		    for(int j = row+1; j < srate.items(); j++)
		      _rate.add(NULL,j);				
		  }             
	      
	      
	      if (_inited)
		{
		  // ricalcola il valore secondario (non modificato)
		  real toshare(100.0); 
		  if (is_perc_modified) 
		    toshare = (_tpr == 0 ? _firstr : _secndr);  
		  TDistrib dt(toshare,0);                 
		  
		  for (int j = first; j < _rate.items(); j++)
		    {   
		      real rvl = is_perc_modified ? perc_rata(j) : tpay_rata(j); 
		      real zpx = rvl/rmax; // percentuale
		      dt.add(zpx);				
		    }    
		  for (j = first; j < _rate.items(); j++)
		    {	              
		      TToken_string& tr = rata(j);
		      real rvl = dt.get();
		      tr.add(rvl.string(), is_perc_modified ? 4 : 1);				
		    }    
		}
	      
	      need_recalc = TRUE;            
	      return	P_OK;			
	    } // new_value != NULL
	  
	  
	}
	else  // i != row modified
	  {           
	    if (i > 0 && !((perc_rata(i-1) == perc_rata(i))))
	      {
		if (rdiff == 2) rdiff = 1;
		_rdiff = FALSE;
	      }
				if (is_perc_modified)
					rsum    += perc_rata(i);
				else
					rsum    += tpay_rata(i);  
	    
	    lastdate = data_rata(i);
	    oldtype  = tipo_rata(i);
	    oldscad  = scad_rata(i); 
	    if (_inited && i > 0) 
	      {
		if (data_rata(i) <= data_rata(i-1)) 
		  return P_SCAD;
	      }
	    else if (lastdate < _inizio) 
	      return P_INIZIO;
	  }    
    }
  
  return P_OK;
}


bool Pagamento::read(TTable* t, TTable* r)
{                                                         
  // puo' chiamarla chiunque
  bool istnew = FALSE;
  if (t == NULL) 
    { 
      t = new TTable("%CPG"); 
      istnew = TRUE; 
    }
  t->zero(); t->put("CODTAB",_code);
  if (t->read() != NOERR) return FALSE;
  
  // set everything 
  _rdiff  = t->get_bool("B1");
  _mcomm  = t->get_bool("B0");
  _tpr    = *((const char*)(t->get("S3")));
  _inscad = *((const char*)(t->get("S1")));
  _code   = t->get("CODTAB");
  _name   = t->get("S0");
  
  // TBI aggiusta _inizio secondo INSCAD; vedi mese commerciale etc.                         
  if (_inscad == 'M')
    {
      if (_mcomm) _inizio.set_month(_inizio.month() == 2 ? 28 : 30);
      else        _inizio.set_end_month();
    }
  else if (_inscad == 'F' && _mcomm && _inizio.month() == 31) 
    _inizio.set_month(30);
  
  // leggi rate e scadenze          
  bool isrnew = FALSE;
  if (r == NULL) 
    { 
      r = new TTable("%RPG"); 
      isrnew = TRUE; 
    }
  TString s(16); 
  
  for (int i = 0; ;i++)
    {   
      r->zero(); s.format("%s%3d",(const char*)_code, i);
      r->put("CODTAB", (const char*)s);
      if (r->read() != NOERR) break;
      TToken_string* tt = new TToken_string(16);
      tt->add((const char*)(r->get("I0")));  // scadenza
      tt->add((const char*)(r->get("R0")));  // percentuale
      tt->add((const char*)(r->get("I1")));  // tipo 
      // data e importo         
      TDate d = _inizio; 
      next_scad(d,(int)(r->get_long("I0")),_mcomm,i);
      tt->add((const char*)d);  
      tt->add("");                         
      tt->add(r->get("S1"));
      _slicer.add((real)r->get("R0"));
      _rate.add(tt);
    }
  
  if (istnew) delete t;
  if (isrnew) delete r;
  
  return TRUE;          
}


int Pagamento::write(TTable& r)
{   
  // Scrive soltanto le righe di pagamento; si assume sia stata chiamata da una
  // relapp, che ha scritto il file principale                                 
  
  TString s(16); int err = NOERR;
  for (int i = 0; err == NOERR && i < n_rate(); i++)
    {
      r.zero(); s.format("%s%3d",(const char*)_code, i);
      r.put("CODTAB", (const char*)s);
      r.put("I0", (long)scad_rata(i));
      r.put("R0", perc_rata(i).string());
      r.put("I1", (long)tipo_rata(i));
      r.put("S1", ulc_rata(i));
      err = r.write();
    }                                      
  return err;
}

int Pagamento::rewrite(TTable& r)
{
  TString s(16); int err = NOERR;
  for (int i = 0; err == NOERR && i < n_rate(); i++)
    {
      r.zero(); s.format("%s%3d",(const char*)_code, i);
      r.put("CODTAB", (const char*)s);
      bool was = (r.read() == NOERR);
      r.zero(); s.format("%s%3d",(const char*)_code, i);
      r.put("CODTAB", (const char*)s);
      r.put("I0", (long)scad_rata(i));
      r.put("R0", perc_rata(i).string());
      r.put("I1", (long)tipo_rata(i));
      r.put("S1", ulc_rata(i));
      err = (was ? r.rewrite() : r.write());
    }                                      
  // erase possible rates > current n. rates
  for (;err == NOERR;i++)
    { 
      r.zero(); s.format("%s%3d",(const char*)_code, i);
      r.put("CODTAB", (const char*)s);
      if (r.read() == NOERR) err = r.remove();
      else break;
    }
  return err;
}

int Pagamento::remove(TTable& r)
{          
  TString s(16); int err = NOERR;
  for (int i = 0 ; err == NOERR; i++)
    { 
      r.zero(); s.format("%s%3d",(const char*)_code, i);
      r.put("CODTAB", (const char*)s);
      if (r.read() == NOERR) err = r.remove();
      else break;
    }  
  return err;
}                               

void Pagamento::set_rate_auto()
{
  // vedi rate esistenti e tipo prima rata 
  // deve fare riferimento ad un tipo pagamento esistente
  // e sensato
  int first = 0;                           
  
  real toslice = _firstr;
  
  if (n_rate() == 0 || !_inited || (_tpr > 0 && n_rate() == 1))  return;
  if (_tpr > 1)           // ripartisci _firstr su tutte le rate
    {
      first = 1; 
      toslice = _secndr;
    }
  
  _slicer.init(toslice);
  
  if (_tpr > 0)
    // prima rata obbligatoria
    set_imprata(0, _firstr); 
  
  for (int i = first; i < n_rate(); i++)        
    // setta le fette e le date di scadenza
    set_imprata(i, _slicer.get());
}                                     



void Pagamento::set_total(real& imponibile, real& imposta, real& spese)
{
  _imponibile = imponibile;
  _imposta    = imposta;
  _spese      = spese;
  _inited     = TRUE;
  
  // istanzia _firstr e _secndr a seconda di _tpr  
  switch(_tpr)
    {          
    case 0:                                         
      _firstr = _imponibile + _imposta + _spese;
      _secndr = 0.0;
      break;              
    case 1: 
      _firstr = _imposta;
      _secndr = _imponibile + _spese;
      break;
    case 2: 
      _firstr = _spese;
      _secndr = _imposta + _imponibile;
      break;
    case 3:
      _firstr = _imposta + _spese; 
      _secndr = _imponibile;
      break;
    case 4: 
      _firstr = _spese + _imponibile;
      _secndr = _imposta;
      break;  
    case 5:     
      _firstr = _imponibile + _imposta;
      _secndr = _spese;
      break;  
    case 6:            
      _firstr = _imponibile;
      _secndr = _imposta + _spese;
      break;  
    }
  
  for (int i = 0; i < _rate.items(); i++)
    {
      TToken_string& t = (TToken_string&)_rate[i]; 
      real rr(t.get(1));
      _slicer.add(rr);
    }                   
}                            


void Pagamento::set_sheet(TSheet_field& sf, int sscad)
{
  sf.reset();
  if (_inited && _rate.items() > 0)
    {  
      // si istanzia uno sheet di primanota
      for (int i = 0; i < n_rate(); i++)
  	{
   	  TToken_string* ts = new TToken_string(36);
   	  // istanzia, o stronzo
	  ts->add((const char*)data_rata(i));
	  ts->add(perc_rata(i).string());
	  ts->add(tpay_rata(i).string());
	  ts->add(tipo_rata(i));
	  ts->add(desc_tipo(tipo_rata(i)));
	  sf.row(-1) = (*ts);                 
	  if (ratapagata(i)) 
	  {
	     sf.disable_cell(1,1); // percentuale
	     sf.disable_cell(1,2); // importo
	  }
	}
    }
  else if (_rate.items() > 0)  // not inited: set edit sheet
    {
      for (int i = 0, scr = 0; i < n_rate(); i++)
	{
	  TToken_string* s = new TToken_string(32);
	  scr += scad_rata(i);   	 	
	  s->add(format("%d",scr));
	  s->add(perc_rata(i).string());
	  s->add(format("%d",tipo_rata(i)));
	  s->add(desc_tipo(tipo_rata(i)));
	  s->add(ulc_rata(i));   	 	
	  sf.row(-1) = *s; 	 	
	}
    }
  else  // new: set with 1 or 2 rates according to tpr
    {        
      if (_tpr > 0) 
		add_rata(ZERO, sscad == -1 ? 0 : sscad, 1);
      add_rata(real(100.0), sscad == -1 ? (_tpr == 0 ? 0 :30) : sscad, 1);  
      
      _dirty = TRUE;
      
      for (int i = 0, scr = 0; i < n_rate(); i++)
	  {
	     TToken_string* s = new TToken_string(32);
	     scr += scad_rata(i);
	     s->add(format("%d",scr));
	     s->add(perc_rata(i).string());
	     s->add(format("%d",tipo_rata(i)));
	     s->add(desc_tipo(tipo_rata(i)));
	     s->add(ulc_rata(i));  
	     sf.row(-1) = *s; 	 	
	  }   	 
    }            
  if (_tpr > 0)
    {     
      // disabilita campi da non toccare sulla prima rata
      if (_inited)
	{        
	  sf.disable_cell(0,1); // percentuale
	  sf.disable_cell(0,2); // importo
	}
      else
	{
	  sf.disable_cell(0,1); // percentuale
	}
    }
  sf.force_update();   
}

Pagamento::Pagamento(const char* codtab, const char* data) : 
_slicer(0.0,0), _new(FALSE), _imponibile(0.0), _imposta(0.0), 
_spese(0.0), _code(codtab), _dirty(FALSE), _inited(FALSE)
{               
  if (data != NULL)     
    _inizio = data;
  if (_code.empty() || !read()) 
    _new = TRUE; 
  if (_new && data != NULL) error_box("Modalita' pagamento inesistente");
}
