#ifndef __SALDACON_H
#define __SALDACON_H

#ifndef __ASSOC_H
#include <assoc.h>
#endif                                         

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

#ifndef __MASK_H
class TMask;
#endif                                         

#ifndef __CONTO_H
#include "conto.h"
#endif                                         

#ifndef __PARTITE_H
#include <partite.h>
#endif

class TTree_rectype : public TRectype
{
protected:
  TRecord_array _recarr;
  int fill_array();

protected: // TRectype 
  virtual TObject* dup() const;
  
  virtual int read(TBaseisamfile& f, word op = _isequal);
  virtual int next(TBaseisamfile& f);
  virtual int write(TBaseisamfile& f) const;
  virtual int rewrite(TBaseisamfile& f) const;
  virtual int remove(TBaseisamfile& f) const;
  virtual void renum_key(const char* field, const char* val);
  
  const TRecord_array& rows_array() const { return _recarr; }
  TRecord_array& rows_array() { return _recarr; }

public:
  const TRectype& row(int r) const { return _recarr.row(r); }
  TRectype& row(int r) { return _recarr.row(r, TRUE); }
  TRectype& new_row(int r = 0);
  void destroy_rows() { _recarr.destroy_rows(); }
  void copy_key_to_row(TRectype& row) const;
  
  int first() const { return _recarr.first_row(); }
  int last() const { return _recarr.last_row(); }
  int pred(int r) const { return _recarr.pred_row(r); }
  int succ(int r) const { return _recarr.succ_row(r); }
  bool exist(int r) const { return _recarr.exist(r); }

  TTree_rectype(const TRectype& testata, const TRectype& riga, const char* num);   
  TTree_rectype(int testata, int riga, const char* num);   
  TTree_rectype(const TTree_rectype& t);
  virtual ~TTree_rectype() {}
};


///////////////////////////////////////////////////////////
// Valuta
///////////////////////////////////////////////////////////

class TValuta : public TSortable
{ 
  TString16 _cod;
  TDate _dat;
  real _cam;
  
protected:
  void adjust();     // Controlla il cambio per le lire

protected:           // TSortable
  virtual int compare(const TSortable& s) const;

public:                
  const TString& codice() const { return _cod; }
  const TDate& data() const { return _dat; }
  const real& cambio() const { return _cam; }
  
  real lit2val(const real& lit) const;
  real val2lit(const real& val) const;
  void val2lit(real& val) const;
  void val2lit(TImporto& imp) const;
  bool in_lire() const { return _cam == 1.0; }
  bool in_valuta() const { return _cam != 1.0; }
  
  void get(const TRectype& rec);
  void put(TRectype& rec) const;
  
  void set(TMask& m, short v, short d, short c) const;
  void get(const TMask& m, short v, short d, short c); 
  
  TValuta();
  TValuta(const char* cod, const TDate& dat, const real& cam);
  TValuta(const TRectype& rec) { get(rec); }
  TValuta(const TMask& m, short v, short d, short c) { get(m, v, d, c); }
  virtual ~TValuta() {}
};    

///////////////////////////////////////////////////////////
// TDecoder
///////////////////////////////////////////////////////////

class TDecoder : private TAssoc_array
{ 
  TLocalisamfile* _file;
  TString _if, _of;
  
public:            
  const TString& decode(const char* code);

  TDecoder(int num, const char* inf, const char* outf);
  TDecoder(const char* table);
  virtual ~TDecoder();
};

///////////////////////////////////////////////////////////
// Riga scadenza
///////////////////////////////////////////////////////////

class TRiga_scadenze : public TTree_rectype
{              
  friend class TPartita;      
  friend class TRiga_partite;      
  
  TRiga_partite* _riga;
  
protected:                                       
  char calcola_abbuono(int p, TImporto& abbuono, bool update);
  TImporto calcola_differenza_cambio(int p, bool update);

  bool modifica_pagamento(const TRectype& new_pag, const TValuta& valuta,
                          char& old_ap, TImporto& old_abb, TImporto& old_diffcam,
                          char& new_ap, TImporto& new_abb, TImporto& new_diffcam, bool update);
  bool elimina_pagamento(int p);

protected:  // TRecord_tree
  virtual TObject* dup() const;
  
public:
  bool chiusa(bool update = FALSE) const;     
  
  bool in_valuta() const;
  
  TPartita& partita() const;
  TRiga_partite& riga() const { return *_riga; } // Riga partite
  
  TImporto importo_pagato(bool val, int mode = 0xF) const;
  TImporto importo(bool val) const;
  TImporto residuo(bool val, int mode = 0xF) const;   // Differenza delle due funzioni precedenti

  TRiga_scadenze(TRiga_partite* riga);
  TRiga_scadenze(const TRiga_scadenze& s);
  virtual ~TRiga_scadenze() {}
};

enum tipo_movimento { tm_nessuno = 0, tm_fattura = 1, tm_nota_credito = 2, 
                      tm_pagamento = 3, tm_insoluto = 5, tm_pagamento_insoluto = 6 };

class TRiga_partite : public TTree_rectype
{         
  friend class TPartita;
  friend class TRiga_scadenze;
  TPartita* _partita;

protected:
  void update_rigaptr();

public: // TTree_rectype     
  virtual TObject* dup() const { return new TRiga_partite(*this); }
  virtual int read(TBaseisamfile& f, word op);
  virtual int write(TBaseisamfile& f) const;
  virtual int rewrite(TBaseisamfile& f) const;
  virtual int remove(TBaseisamfile& f) const;

public:
  int rate() const { return _recarr.rows(); }
  TRiga_scadenze& rata(int r) const { return (TRiga_scadenze&)_recarr.row(r); }
  void elimina_rata(int r = 0);
  TRiga_scadenze& new_row(int r = 0);
  
  tipo_movimento tipo() const;                 
  bool is_fattura() const { return tipo() == tm_fattura; }
  bool is_nota_credito() const { return tipo() == tm_nota_credito; }
  int ultima_ratapagata() const;
  int ultimo_pagamento(int rata) const;
  int rata_con_abbuoni_diffcam() const;

  char sezione() const { return get_char(PART_SEZ); }
  TImporto importo(bool valuta, int mode = 0xF) const;
  
  bool in_valuta() const { return get(PART_CODVAL).not_empty(); }

  bool update(const TRectype& vec, const TRectype& nuo, const char* field);
  bool update(const TImporto& vec, const TImporto& nuo, const char* sez, const char* val);

  TPartita& partita() const { CHECK(_partita, "Partita nulla"); return *_partita; }

  TRiga_partite(TPartita* game);
  TRiga_partite(const TRiga_partite& r);
  virtual ~TRiga_partite() {}
};

class TPartita : public TSortable
{                     
  TBill _conto;
  int _anno;
  TString16 _num;
  char _align;        // current _num alignment
  
  TRecord_array _part;
  TRecord_array _unassigned;
  
  static char _cli_align, _for_align;  // default _num alignment

protected:
  const char* build_key(TString& key) const;

  char allineamento_iniziale() const { return _align; }
  char allineamento_corrente() const;
  void allinea(char all = ' ');
  
public: // TObject
  virtual bool ok() const { return _part.rows() > 0; }
  virtual int compare(const TSortable& s) const;
  
public:
  enum { NUMLEN = 7, UNASSIGNED = 9999 };

  TRiga_partite& riga(int r) const { return (TRiga_partite&)_part.row(r); } 
  TRiga_partite& new_row(int r = 0);
  void  rimuovi_riga(int r);
  TRiga_scadenze& rata(int nriga, int nrata) const;
  TRectype& pagamento(int nriga, int nrata, int nrigp);
  bool rata_chiusa(int nriga, int nrata) const;
  bool esiste(int nriga, int nrata = 0, int nrigp = 0) const;
  bool esistono_abbuoni_diffcam(long nreg = 0) const;
  
  // assegna riga e figli ad altra partita
  void sposta_riga(int r, TPartita& part);
  // de-assegna tutti i pagamenti di una riga e li distrugge 
  void scollega_pagamenti(int riga, int rata = 1);
  
  int succ(int r) const { return _part.succ_row(r); } 
  int pred(int r) const { return _part.pred_row(r); } 
  int first() const { return _part.first_row(); }
  int last() const { return _part.last_row(); }

  bool reread();         
  bool read(const TBill& clifo, int anno, const char* num);
  bool write(bool re = FALSE) const;
  bool rewrite() const { return write(TRUE); }
  bool remove() const;
  
  int mov2rig(long nreg, int rmov) const;
  int rig2mov(int rmov) const;
  int prima_fattura(long nreg = -1) const;
  int primo_pagamento(long nreg = -1) const; 
  
  bool utilizzata(int r) const;    // Controlla se esistono pagamenti sommati alla riga r
  TRecord_array& unassigned() { return _unassigned; }
  
  bool chiusa(bool update = FALSE);

  const TBill& conto() const { return _conto; }
  int anno() const { return _anno; }
  const TString& numero() const { return _num; }
  const TString& descrizione() const;

  TImporto importo_speso(long numreg, int numrig) const;
  void update_reg(long nreg, const TRectype& mov);
  void calcola_saldo(TImporto& saldo, TImporto& doc, TImporto& pag, TImporto& imp) const;
  TImporto calcola_saldo(bool valuta) const;
  TImporto calcola_saldo_al(bool valuta, const TDate& al, const TDate& data_rischio = botime) const;
  
  bool modifica_pagamento(const TRectype& new_pag, const TValuta& valuta,
                          char& old_ap, TImporto& old_abb, TImporto& old_diffcam,  
                          char& new_ap, TImporto& new_abb, TImporto& new_diffcam, 
                          bool update);
  bool modifica_pagamento(const TRectype& new_pag, const TValuta& valuta, bool update);
  
  static void carica_allineamento();
  char allineamento_richiesto() const;

  TPartita(const TBill& clifo, int anno, const char* num);
  TPartita(const TRectype& part);
};           


class TPartite_array : private TAssoc_array
{ 
  TString80 _key;    // Work string
  long _numreg;      // Last registration loaded
  
protected:
  const TString& key(const TBill& clifo, int anno, const char* num); // Build key for TAssoc_array
  TPartita* find(const TBill& clifo, int anno, const char* numero, bool create);
  TPartita* find(const TRectype& part, bool create);

public:              // TAssoc_array
  virtual void destroy();

public:
  TPartita& partita(const TBill& clifo, int anno, const char* numero);
  TPartita& partita(const TRectype& r);
  
  TPartita* exist(const TBill& clifo, int anno, const char* numero) const
  { return ((TPartite_array*)this)->find(clifo, anno, numero, FALSE); }
  
  TPartita* exist(const TRectype& part) const
  { return ((TPartite_array*)this)->find(part, FALSE); }
  
  bool destroy(const TBill& clifo, int anno, const char* num);
  
  bool write(bool re = FALSE);
  bool rewrite() { return write(TRUE); }
  
  int add_numreg(long numreg);    // Carica tutte le partite relative alla registrazione numreg
  TImporto importo_speso(long numreg, int numrig);
  void update_reg(const TRectype& mov, long old_reg = 0);
  
  // Controlla se esistono righe di pagamento relative alla riga numrig
  bool utilizzata(long numreg, int numrig);    
  
  TPartita* first() { restart(); return next(); }
  TPartita* next() { return (TPartita*)get(); }
  
  TPartite_array() : _numreg(0) {} 
  virtual ~TPartite_array() {}
};

#endif   
