#include <recarray.h>

#include "prlib.h"
#include "provv.h"
#include <doc.h>

// TProvvigioni_agente


TProvvigioni_agente::TProvvigioni_agente() : TRectype(LF_AGENTI)
{
//  _rows = new TRecord_array(LF_PROVV,PROV_NRIGA);
  _provv_rel = new TRelation(LF_PROVV);
  _provv_cur = new TCursor(_provv_rel);
}

TProvvigioni_agente::TProvvigioni_agente(const char* agente) : TRectype(LF_AGENTI)
{
  //_rows = new TRecord_array(LF_PROVV,PROV_NRIGA);
  _provv_rel = new TRelation(LF_PROVV);
  _provv_cur = new TCursor(_provv_rel);
  read(agente);
}

TProvvigioni_agente::~TProvvigioni_agente()
{
//  delete _rows;
  unlock();
  delete _provv_rel;
  delete _provv_cur;
}

void TProvvigioni_agente::unlock()
{
  if (_agente.not_empty())
  {
    TLocalisamfile age(LF_AGENTI);
    TRectype::put(AGE_CODAGE,_agente);
    TRectype::read(age, _isequal, _unlock); // Sblocca eventuali caricamenti precedenti
  }
}

int TProvvigioni_agente::read(const char* agente, const int anno, const char* codnum, const long ndoc)
{
  int err = NOERR;
  
  unlock();
  destroy(); // Cancella eventuali residui

  TLocalisamfile age(LF_AGENTI);
  TRectype::put(AGE_CODAGE,agente);
  err = TRectype::read(age, _isequal, _testandlock); // Carica i dati dell'agente
  if (err != NOERR)
    return err;

  // Legge tramite chiave 2 del file (per documento)  
  _agente = agente;

  TRectype rec_from(LF_PROVV);

  rec_from.put(PROV_CODAGE,agente);
  if (anno != 0)
    rec_from.put(PROV_ANNO, anno);
  if (codnum != NULL)
    rec_from.put(PROV_CODNUM, codnum);
  if (ndoc != 0L)
    rec_from.put(PROV_NDOC, ndoc);
  
  TRectype rec_to(rec_from);
  
  _provv_cur->setregion(rec_from, rec_to); // Cursore da leggere contenente le provvigioni
  // Sara' bello, un giorno, poter bloccare tutti i record del cursore contemporaneamente...
  
  const long items = _provv_cur->items();
  TRectype& r = _provv_cur->file().curr();
  TString key, codnum1;
  int     anno1;
  long    ndoc1;
  for (long i = 0; i < items; i++)  // Compila l'assoc_array per documenti/rate
  {
    *_provv_cur = i; // posiziona il cursore
    
    anno1   = r.get_int(PROV_ANNO);
    codnum1 = r.get(PROV_CODNUM);
    ndoc1   = r.get_long(PROV_NDOC);
    key.format("%4d%4s%7ld",anno1,(const char*)codnum1,ndoc1); // Compone la chiave

    const bool exist = _rate.is_key(key);  // Guarda se esiste gia' questo documento
   
    if (!exist)
      _rate.add(key,(TRate_doc*)new TRate_doc(r), exist);
  
    TRate_doc& rd = (TRate_doc&)_rate[key];
   
    //TRate_doc  com_rata(r);
    //TRate_doc& rd = exist ? (TRate_doc&) _rate[key] : com_rata;
    TRata* rt = new TRata(r);
    rd.add_rata(rt);

    //_rate.add(key,rd,exist); // Sostituisce/aggiunge l'elemento
  }
  
  // Dopo aver letto le righe, ordina le rate per ogni documento
  for (TRate_doc* rd = (TRate_doc*) _rate.first_item(); rd != NULL; rd = (TRate_doc*) _rate.succ_item())
    rd->sort_rate();

  return err;
}

int TProvvigioni_agente::rate2rows(int action)
{
  // Scorre gli elementi di _rate (TDoc_rate) uno ad uno
  // per settare le righe provvigionali 
  // Scrive tramite chiave 1: utilizzando un solo record array (CODAGE+ANNO+CODNUM+NDOC+NRIGA)
  int err = NOERR;
  
  if (_agente.not_empty())
  {
    TString_array kl;
    int nrow = 1; // Numero riga per agente e per documento
    const int items = documenti(kl); // Prende l'elenco dei documenti
    kl.sort();                       // ordina per documento
    for (int i = 0; i < items && err == NOERR; i++)
    {
      TRate_doc& rd = (TRate_doc&)_rate[kl.row(i)];
      const int  anno = rd.anno();
      const long ndoc = rd.ndoc();
      TString    codnum(rd.codnum());
      TDate      datadoc(rd.datadoc());
      real       impdoc   = rd.impdoc();
      real       impprdoc = rd.impprdoc();
      real       impnet   = rd.impnet();
      const long codcf    = rd.codcf();
      TString    codval(rd.codval());
      TDate      datacam(rd.datacam());
      real       cambio   = rd.cambio();
      // Chiave del TRecord_array
      TRecord_array * rows = new TRecord_array(LF_PROVV,PROV_NRIGA);
      TRectype* k = new TRectype(LF_PROVV);
      k->put(PROV_CODAGE, _agente);
      k->put(PROV_ANNO, anno);
      k->put(PROV_CODNUM, codnum);
      k->put(PROV_NDOC, ndoc);
      rows->set_key(k);
      const int ritems = rd.items(); // Ciclo per rate di questo documento
      for (int j = 0; j < ritems; j++)
      {
        TRata& rt        =  rd[j];
        TRectype* record =  new TRectype(LF_PROVV);
        record->put(PROV_CODAGE,_agente);
        record->put(PROV_ANNO,anno);
        record->put(PROV_CODNUM,codnum);
        record->put(PROV_NDOC,ndoc);
        //record->put(PROV_NROW,nrow++);
        record->put(PROV_NRIGA,j+1);
        record->put(PROV_NRATA,rt.rata());
        record->put(PROV_GENERATA,rt.generata());
        record->put(PROV_SALDATA,rt.saldata());
        record->put(PROV_TIPOPAGPR,rt.tipopagpr());
        record->put(PROV_DATADOC,datadoc);
        record->put(PROV_IMPDOC,impdoc);
        record->put(PROV_IMPPRDOC,impprdoc);
        record->put(PROV_IMPNETDOC,impnet);
        record->put(PROV_CODCLI,codcf);
        record->put(PROV_CODVAL,codval);
        record->put(PROV_DATACAMBIO,datacam);
        record->put(PROV_CAMBIO,cambio);
        record->put(PROV_DATASCAD,rt.datascad());
        record->put(PROV_IMPRATA,rt.imprata());
        record->put(PROV_TIPOPAG,rt.tipopag());
        record->put(PROV_IMPPROVV,rt.impprovv());
        record->put(PROV_PAGATO,rt.pagato());
        record->put(PROV_PROVVPAG,rt.provvpag());
        record->put(PROV_PAGMAT,rt.pagmat());
        record->put(PROV_PROVVMAT,rt.provvmat());
        rows->add_row(record);
      } // Ciclo per rata
      switch (action)
      {
        case 0: // write
          err = rows->write();
          break;
        case 1: // rewrite
          err = rows->rewrite();
          break;
        case 2: // remove
          err = rows->remove();
          break;
        default: // remove
          break;
      }
      unlock();
      
      delete rows;
    } // Ciclo per documento
  }
  return err;
}

TRate_doc& TProvvigioni_agente::rate(int anno, const char* codnum, long ndoc, bool create)
{
  TString k;
  
  k.format("%4d%4s%7ld",anno,codnum,ndoc);
  return rate(k,create);
}

TRate_doc& TProvvigioni_agente::rate(const char* key, bool create)
{
  const bool exist = _rate.is_key(key);
  if (!exist)
  {
    if (create)
    {
      TRectype r(LF_PROVV);
      TString  k(key);
      r.put(PROV_ANNO,k.sub(0,4));
      r.put(PROV_CODNUM,k.sub(4,8));
      r.put(PROV_NDOC,k.sub(8));
      TRate_doc* rd = new TRate_doc(r);
      _rate.add(key,rd);
    }
    else
      fatal_box("Impossibile trovare l'elemento %s tra le righe provvigionali",key);
  }
  return (TRate_doc&) _rate[key];
}

void TProvvigioni_agente::remove_rate(int anno, const char* codnum, long ndoc)
{
  TString k;
  
  k.format("%4d%4s%7ld",anno,codnum,ndoc);
  remove_rate(k);
}

void TProvvigioni_agente::remove_rate(const char* key)
{
  const bool exist = _rate.is_key(key);
  if (exist)
    _rate.remove(key);
  else
    fatal_box("Impossibile trovare l'elemento %s tra le righe provvigionali", key);
}

/////////////////////////////////////////////////////////////////////////////////
// TRate_doc
/////////////////////////////////////////////////////////////////////////////////
TRate_doc::TRate_doc(const TRectype& rec)
{
  set(rec); // bleah!
}

const bool TRate_doc::exist(const int i)
{
 return _rows.objptr(i) != NULL;
}

TRata& TRate_doc::row(int i, bool create)
{
  if (create && !exist(i) ) // Parametro di creazione
    _rows.add(new TRata(),i);
  return (TRata&) _rows[i];
}

bool TRate_doc::ok_provvigione()
{
  real totprov;
  const int its = items();

  for (int i = 0; i < its; i++) // Somma le provvigioni di tutte le rate
    totprov += row(i).impprovv();
    
  return totprov <= _impprdoc; // controlla che tale somma e' compresa nel totale provvigione del documento 
}

void TRate_doc::set(const TRectype& rec)
{
  CHECK(rec.num() == LF_PROVV,"Il record non ha il tracciato di LF_PROVV");
  _anno       = rec.get_int(PROV_ANNO);
  _codnum     = rec.get(PROV_CODNUM);
  _codval     = rec.get(PROV_CODVAL);
  _ndoc       = rec.get_long(PROV_NDOC);
  _codcf      = rec.get_long(PROV_CODCLI);
  _datadoc    = rec.get_date(PROV_DATADOC);
  _datacambio = rec.get_date(PROV_DATACAMBIO);
  _impdoc     = rec.get_real(PROV_IMPDOC);
  _impprdoc   = rec.get_real(PROV_IMPPRDOC);
  _impnetdoc  = rec.get_real(PROV_IMPNETDOC);
  _cambio     = rec.get_real(PROV_CAMBIO);
}

void TRate_doc::set(const TRate_doc& r)
{
  _anno       = r._anno;
  _codnum     = r._codnum;
  _codval     = r._codval;
  _ndoc       = r._ndoc;
  _codcf      = r._codcf;
  _datadoc    = r._datadoc;
  _datacambio = r._datacambio;
  _impdoc     = r._impdoc;
  _impprdoc   = r._impprdoc;
  _impnetdoc  = r._impnetdoc;
  _cambio     = r._cambio;
}

void TRate_doc::set(TToken_string& t)
{
  CHECK(t.items() >= 11, "Numero di items non valido");
  _anno       = t.get_int(0);
  _codnum     = t.get(1);
  _ndoc       = t.get_long(2);
  _datadoc    = t.get(3);
  _impdoc     = t.get(4);
  _impprdoc   = t.get(5);
  _impnetdoc  = t.get(6);
  _codcf      = t.get_long(7); 
  _codval     = t.get(8); 
  _cambio     = t.get(9); 
  _datacambio = t.get(10); 
}

/////////////////////////////////////////////////////////////////////////////////
// TRata
/////////////////////////////////////////////////////////////////////////////////
int TRata::compare(const TSortable& s) const
{
  const TRata& r = (const TRata&) s;
  
  if (_nrata > r.rata()) 
    return 1; // Numero maggiore
  else
    if (_nrata < r.rata());
      return -1; // Numero minore
  
  return 0; // Stesso numero di rata
}

void TRata::set(TToken_string& t)
{
  CHECK(t.items() == 11, "Troppi pochi elementi nella token string");
  _nrata    = t.get_int(0);
  _datascad = t.get(1);
   _tipopag = t.get_int(2);
  _imprata  = t.get(3);
  _impprovv = t.get(4);
  _pagmat   = t.get(5);
  _provvmat = t.get(6);
  _pagato   = t.get(7);
  _provvpag = t.get(8);
  _saldata  = t.get(9)[0] == 'X' ? TRUE : FALSE;
  _tipopagpr = t.get_int(10);
}

void TRata::set(const TRectype& rec)
{
  CHECK(rec.num() == LF_PROVV,"Il record non ha il tracciato di LF_PROVV");
  _datascad = rec.get_date(PROV_DATASCAD);
  _tipopag  = rec.get_int(PROV_TIPOPAG);
  _imprata  = rec.get_real(PROV_IMPRATA);
  _impprovv = rec.get_real(PROV_IMPPROVV);
  _pagato   = rec.get_real(PROV_PAGATO);
  _provvpag = rec.get_real(PROV_PROVVPAG);
  _pagmat   = rec.get_real(PROV_PAGMAT);
  _provvmat = rec.get_real(PROV_PROVVMAT);
  _saldata  = rec.get_bool(PROV_SALDATA);
  _nrata    = rec.get_int(PROV_NRATA);
  _generata = rec.get_char(PROV_GENERATA);
  _tipopagpr = rec.get_int(PROV_TIPOPAGPR);
}

TRata::TRata(const TRectype& rec)
{
  set(rec);
}

void TRata::set(const TRata& r)
{
  _datascad = r._datascad;
  _tipopag  = r._tipopag;
  _imprata  = r._imprata;
  _impprovv = r._impprovv;
  _pagato   = r._pagato;
  _provvpag = r._provvpag;
  _pagmat   = r._pagmat;
  _provvmat = r._provvmat;
  _saldata  = r._saldata;
  _nrata    = r._nrata;
  _generata = r._generata;
  _tipopagpr = r._tipopagpr;
}

int TAgente::read(const char * codice)
{
  TLocalisamfile f(LF_AGENTI);
  
  put("CODAGE", codice);
  int err = TRectype::read(f);
  if (err != NOERR)
  {
    zero();
    put("CODAGE", codice);
  }
  return err;  
}

TAgente::TAgente(const char * codice)
       : TRectype(LF_AGENTI)
{
  read(codice);
} 

TAgente::TAgente(const TAgente & a)
       : TRectype(LF_AGENTI)
{
  copy(a);
} 
TAgente::TAgente(const TRectype & rec)
       : TRectype(LF_AGENTI)
{
  TRectype::operator=(rec);
}