#ifndef __PAGAMENT_H
#define __PAGAMENT_H

#ifndef __MSKSHEET_H
#include <msksheet.h>
#endif                                         

#ifndef __RELATION_H
#include <relation.h>
#endif

#ifndef __TABUTIL_H
#include <tabutil.h>
#endif

// Error codes for pagation
const word P_OK     = 0x0000;     // ok
const word P_RSUM   = 0x0001;     // percentages do not sum up to 100
const word P_IMPNC  = 0x0002;     // inconsistenza percentuali / importi
const word P_SCAD   = 0x0004;     // scadenze non consecutive 
const word P_INIZIO = 0x0008;     // data 1a rata < data inizio pagamenti
const word P_NEG    = 0x0010;     // importo specificato < minimo possibile
const word P_TROP   = 0x0020;     // importo specificato > massimo possibile
const word P_TOTNC  = 0x0040;     // totale importi != totale pagamento
const word P_MCOMM  = 0x0080;     // inconsistenza mese commerciale/scadenze

class TPagamento : public TObject
{   
  TString   _code;       // codice
  TString   _name;       // descrizione
  real      _imponibile; // imponibile da affettare
  real      _imposta;    // imposta da affettare
  real      _spese;      // spese da affettare
  real      _cambio;     // cambio valuta
  TDistrib  _slicer;     // affettatrice
  bool      _new;        // non letto da database
  TString_array _rate;   // rate medesime
  char      _inscad;     // inizio scadenze:    S1    
  bool      _mcomm;      // mese commerciale:   B0   
  bool      _rdiff;      // rate differenziate: B1
  int       _tpr;        // tipo prima rata:    S3
  bool      _dirty;      // modificato (strutturalmente!)
  TDate     _inizio;     // data inizio pagamenti
  bool      _inited;     // vero se c'e' un movimento di riferimento
  real      _firstr;     // importo da pagare in prima rata (o distribuire se tpr == 0)
  real      _secndr;     // importo da distribuire
  
  int       _fixd[3];    // giorni scadenza fissa, se desiderati
  int       _round;      // decimali arrotondamento importo 
  int       _int_rate;   
  
  int       _rata_ifield(int n, int f) const;
  long      _rata_lfield(int n, int f) const;
  real      _rata_rfield(int n, int f) const;
  TDate     _rata_dfield(int n, int f) const;
  const char* _rata_sfield(int n, int f) const;
  
  int       _def_tpr;    // tipo rata default
  TString16 _def_ulc;    // ulteriore classificazione default
  
public:

  // pregasi notare la straordinaria dovizia di const
  int    n_rate()             const { return _rate.items();    }
  bool   is_new()             const { return _new;             }  
  bool   dirty()              const { return _dirty;           }

  real   imponibile()         const { return _imponibile;      }
  real   imposta()            const { return _imposta;         }
  real   spese()              const { return _spese;           }

  int   scad_rata(int n) const  { return _rata_ifield(n,0);}               
  real  perc_rata(int n) const  { return _rata_rfield(n,1);}
  int   tipo_rata(int n) const  { return _rata_ifield(n,2);}
  TDate data_rata(int n) const  { return _rata_dfield(n,3);}
  real  tpay_rata(int n) const  { return _rata_rfield(n,4);}
  const char* ulc_rata(int n) const { return _rata_sfield(n,5);}
  bool  ratapagata(int n) const { return _rata_sfield(n,6)[0] > ' ';}
  real  tlit_rata(int n) const  { return _rata_rfield(n,7);}

  char   inizio_scadenza()    const { return _inscad;   }           
  bool   mese_commerciale()   const { return _mcomm;    }           
  bool   rate_differenziate() const { return _rdiff;    }
  int    tipo_prima_rata()    const { return _tpr;      }
  int    intervallo_rate()    const { return _int_rate; }
  int    decs()               const { return _round;    }
  
  const TString& name()       const { return _name;     }                                    
  const TString& code()       const { return _code;     }                                    
  const char* desc_tpr()      const;
  const char* desc_tipo(int tipo, char ulc)  const;
  
  // giorni scadenza fissi, aggiunti poi  
  void  set_fixed_scad(int a, int ind) { _fixd[ind] = a;  }
  // aggiusta scadenze fisse (tutte in un colpo)
  void  adjust_fixed_scad();
  
  // queste vengono usate solo per movimenti editabili nella struttura
  // (da tabella pagamenti) e riaggiustano tutte le rate in accordo
  // con il parametro modificato
  void   set_intervallo_rate(int i);     
  void   set_mese_commerciale(bool v, int& sscad);          
  void   set_rate_differenziate(int v);
  void   set_tipo_prima_rata(int v, int sscad = -1);
  void   set_percrata(int n, real r);
  real   recalc_percrata(int i);
  void   set_numero_rate(int n, int sscad = -1, int rdiff = 1);
  
  void   set_inizio(const TDate& d);  // resetta tutto                                                       
  void   set_inizio_scadenza(char v)    { _inscad = v; }           
  void   set_code(const char* c)        { _code = c;   }       
  void   set_round(int n)               { _round = n;  }
  void   set_cambio(const real& ex);      
  bool   in_valuta() const { return _cambio != 1.0; }
  
  // check consistency: returns word with errors flagged, 0 if ok
  word   validate() const;
  void   strerr(word err, TString& s);
  
  // read/write from database 
  // relapp passa i files, se no vengono aperti
  bool   read(TTable* cpg = NULL, TTable* rpg = NULL);
  
  // chiamabili solo da relapp, agiscono solo su %RPG
  int   write(TTable& rpg);
  int   rewrite(TTable& rpg);
  int   remove(TTable& rpg);
  
  // modifica rate manualmente o non
  TToken_string&   rata(int r) { return (TToken_string&)_rate[r]; }
  TToken_string&   add_rata (real perc, int day, int type, const char* ulc = "");
  TToken_string&   set_rata (int index, real perc, int day, int type, 
                             const char* ulc = NULL, const char* imp = NULL,
                             const char* data = NULL);     

  // questa calcola percentuali e scadenze a partire dagli importi
  TToken_string& set_rata(int index, const real& howmuch, const real& quanto,
                          const TDate& date, int type, const char* ulc, bool pagata);                    
  
  // settano tipo rata e ult. class default per le rate; se bool = TRUE
  // modificano anche le eventuali rate esistenti
  void set_default_type(int type, bool change_existing = TRUE);
  void set_default_ulc(const char* ulc, bool change_existing = TRUE);
  
  void   remove_rata(int r);  
  void   zap_rate () { _rate.destroy(); } 
  // calcola le rate automaticamente secondo quanto specificato
  void   set_rate_auto();          
  // data una rata esistente, riaggiusta gli importi usando lo slicer e 
  // le scadenze usando la data di inizio
  void   set_imprata(int i, const real& r);

  // slicer interface
  void   set_total(const real& ib, const real& im, const real& sp);
  
  // istanzia uno sheet field come diobue comanda                                   
  void   set_sheet(TSheet_field& sf, int sscad = -1);         
  // ricalcola automaticamente tutto il ricalcolabile
  // alla modifica di una percentuale (o di un importo)
  // ritorna TRUE se non si poteva; non occorre che sia inizializzato
  // con un importo
  word   recalc_rate(int row, bool is_perc_modified, const char* new_value,
                     const char* scad, const char* typ, const char* ulc, int rdiff,
                     bool mcomm, bool& need_recalc);
  
  // determina la prossima scadenza
  void   next_scad(TDate& d, int scad, bool mcomm, int rata);

  // se codtab non e' NULL legge da file (e da' errore se non c'e')
  // se si vuole fare un pagamento nuovo si da' il codice con set_code                                                              
  TPagamento(const char* codtab = NULL, const char* data = NULL);
  virtual ~TPagamento() {}
};                          

#endif   
