#include <relapp.h>
#include <msksheet.h>
#include <sheet.h>
#include <utility.h>
#include <lffiles.h>
#include <comuni.h>
#include "ef0.h"
#include "ef0100.h"
#include "ef0101.h"           

///////////////////////////////////////////////////////////////
// Classe per la gestione di effetti con metodi standard di: //
// inserimento, modifica, cancellazione.                     //
///////////////////////////////////////////////////////////////

class TVariazione_effetti: public TRelation_application
{
  TMask *_msk;
  TEffetto *_effetto;
  TRelation *_rel; 
  TLocalisamfile *_reff, *_cess, *_com; 
protected:                                
  virtual void init_query_mode(TMask&); 
  virtual void init_insert_mode(TMask&);
  static bool handle_sheet(TMask_field& f, KEY);
  static bool codval_handler(TMask_field& f, KEY k);
  static bool impeff_notify(TSheet_field& s, int r, KEY key);
  virtual const char* get_next_key();
  TSheet_field& cess_sheet() const; 
  TSheet_field& righe_sheet() const;
  void common_f(const TMask& m);
  static void calcola_totali();
  virtual int read(TMask& m);
  virtual int rewrite(const TMask& m);
  virtual int write(const TMask& m);
  virtual bool remove();
  bool user_create();
  bool user_destroy();
  virtual TMask* get_mask(int mode) {return _msk;}
  virtual bool changing_mask(int mode) {return FALSE;}
public:
  virtual TRelation* get_relation() const {return _rel;}
  TVariazione_effetti() {};
  virtual ~TVariazione_effetti() {};
};

// restituisce un riferimento all' applicazione
inline TVariazione_effetti& app() {return (TVariazione_effetti&)main_app();}

// quando si va in query mode resetta i due campi della maschera
// relativi ai totali
void TVariazione_effetti::init_query_mode(TMask&) 
{ 
  _msk->reset(F_TOTIMP);
  _msk->reset(F_TOTIMPVAL);
}   

// quando si va in insert mode resetta i due campi della maschera relativi 
// ai totali, inserisce una riga vuota nello sheet e setta il flag dirty 
// dello sheet per forzare l'utente all'inserimento di una riga  
void TVariazione_effetti::init_insert_mode(TMask&)
{ 
  _msk->reset(F_TOTIMP);
  _msk->reset(F_TOTIMPVAL);
  TToken_string riga("|||||||||");
  righe_sheet().row(0) = riga;
  righe_sheet().set_dirty();
}
 
// ritorna il prossimo numero valido di chiave   
const char* TVariazione_effetti::get_next_key()
{
  TLocalisamfile& effetti = _rel->lfile();
  long nprogtr = 1L;
  if ( !effetti.empty() )
  {
    effetti.zero();
    effetti.setkey(1);
    effetti.last();
    if ( effetti.good() )
      nprogtr += effetti.get_long(EFF_NPROGTR);
  }
  return format("%d|%ld",F_NPROGTR,nprogtr);
}

// ritorna un riferimento allo sheet dei cessionari
TSheet_field& TVariazione_effetti::cess_sheet() const
{
  TSheet_field& o_sheet = (TSheet_field&)_msk->field(F_SHEET_EFF);
  return o_sheet;
}

// ritorna un riferimento allo sheet delle righe 
TSheet_field& TVariazione_effetti::righe_sheet() const
{
  TSheet_field& r_sheet = (TSheet_field&)_msk->field(F_SHEET_RIGHE);
  return r_sheet;
}

// metodo che permette di scivere su file i dati inseriti nella maschera;
// comune alla write e alla rewrite 
void TVariazione_effetti::common_f(const TMask& m)
{
  long nprogtr = m.get_long(F_NPROGTR);
  m.autosave(*_rel);
  _effetto->head() = _rel->curr();      
  TSheet_field& shcess = cess_sheet();
  TSheet_field& shrighe = righe_sheet();
  int items = shcess.items();
  _effetto->destroy_rows_c();            
  int ii = 1;
  // scarico tutte le righe dei cessionari dallo sheet sul file
  for (int i = 0; i < items; i++)
  {   
    TToken_string& row = shcess.row(i);
    if ( row.items()== 0 ) continue; // salta le righe vuote
    TRectype& rec = _effetto->row_c(ii, TRUE);
    row.restart();                                  
    rec.zero();
    rec.put(CES_NPROGTR, nprogtr);
    rec.put(CES_NRIGA, ii);
    rec.put(CES_RAGSOC, row.get());
    rec.put(CES_LOCALITA, row.get());
    rec.put(CES_STATO, row.get_int());
    rec.put(CES_COM, row.get());
    ii++;
  }                                  
  items = shrighe.items();
  _effetto->destroy_rows_r();           
  ii = 1;                  
  // scarico tutte le righe dell'effetto dallo sheet sul file
  for (i = 0; i < items; i++)
  {                   
    TToken_string& row = shrighe.row(i);    
    real imp_eff(row.get(1));
    if (imp_eff == 0.0) continue; // salta le righe con importo nullo 
    row.restart();
    TRectype& rec = _effetto->row_r(ii, TRUE);
    rec.zero();
    rec.put(REFF_NPROGTR, nprogtr);
    rec.put(REFF_NRIGATR, ii);
    rec.put(REFF_IMPFATT, row.get());
    rec.put(REFF_IMPORTO, row.get());
    rec.put(REFF_IMPFATTVAL, row.get());
    rec.put(REFF_IMPORTOVAL, row.get());
    rec.put(REFF_ANNO, row.get_int());
    rec.put(REFF_NUMPART, row.get());
    rec.put(REFF_NRIGA, row.get_int());
    rec.put(REFF_NRATA, row.get_int());
    rec.put(REFF_PROVV, row.get()[0]);
    rec.put(REFF_CODNUM, row.get());
    rec.put(REFF_ANNODOC, row.get_int());
    rec.put(REFF_NFATT, row.get());
    rec.put(REFF_DATAFATT, row.get());
    ii++;
  }
  _effetto->renum(_effetto->numero());
}

// carica nella maschera i dati dai files 
int TVariazione_effetti::read(TMask& m)
{
  m.autoload(*_rel);
  TLocalisamfile f(LF_EFFETTI);
  int err = _rel->status();
  if (err == NOERR)
  {
    // legge l'effetto dal record corrente della relazione
    err = _effetto->read(f, _rel->curr()); 
    if (err == NOERR)
    { 
      TString16 codcom(3);
      TToken_string riga(80);
      TSheet_field& shcess = cess_sheet();
      shcess.reset(); 
      TSheet_field& shrighe = righe_sheet();
      shrighe.reset();  
      int items = _effetto->rows_c();    
      // carica tutti i cessionari nello sheet dal file
      for (int i = 1; i <= items; i++)
      {
        const TRectype& rec = _effetto->row_c(i);
        riga.cut(0);
        riga.add(rec.get(CES_RAGSOC));
        riga.add(rec.get(CES_LOCALITA));
        riga.add(rec.get(CES_STATO));
        // per caricare nello sheet dei cessionari la denominazione 
        // del comune di cui si conosce il codice
        codcom = rec.get(CES_COM);
        riga.add(codcom);         
        _com->zero();
        _com->put(COM_COM, codcom);
        if (_com->read() == NOERR) 
        	riga.add(_com->get(COM_DENCOM));
        shcess.row(i-1)=riga;
      }    
      items = _effetto->rows_r();                             
      // carica tutte le righe dell'effetto nello sheet dal file
      for (i = 1; i <= items; i++)
      {
        const TRectype& rec = _effetto->row_r(i);
        riga.cut(0);
        riga.add(rec.get(REFF_IMPFATT));
        riga.add(rec.get(REFF_IMPORTO));
        riga.add(rec.get(REFF_IMPFATTVAL));
        riga.add(rec.get(REFF_IMPORTOVAL));
        riga.add(rec.get(REFF_ANNO));
        riga.add(rec.get(REFF_NUMPART));
        riga.add(rec.get(REFF_NRIGA));
        riga.add(rec.get(REFF_NRATA));
        char tipo_num = rec.get(REFF_PROVV)[0];
        if (tipo_num == 'D')
        	riga.add("Definitiva");
        else
        	riga.add("Provvisoria");
        riga.add(rec.get(REFF_CODNUM));
        riga.add(rec.get(REFF_ANNODOC));
        riga.add(rec.get(REFF_NFATT));
        riga.add(rec.get(REFF_DATAFATT));
        shrighe.row(i-1) = riga;
      }
    }
  }
  return err;
}

// riscrive effetto
int TVariazione_effetti::rewrite(const TMask& m)
{
  common_f(m);// scarica i dati dalla maschera                  
  TLocalisamfile f(LF_EFFETTI);
  return _effetto->rewrite(f);
}

// scrive i dati su file
int TVariazione_effetti::write(const TMask& m)
{
  common_f(m);// scarica i dati dalla maschera                     
  TLocalisamfile f(LF_EFFETTI);
  int err = _effetto->write(f);
  if (err == NOERR)  
    _rel->read();// rilegge per posizionare correttamente la relazione
  return err;
}

// rimuove l'effetto 
bool TVariazione_effetti::remove() 
{                            
  TLocalisamfile f(LF_EFFETTI);             
  return _effetto->remove(f) == NOERR;
}

// crea la relap
bool TVariazione_effetti::user_create()
{
  _msk = new TMask("ef0100a") ;
  _rel = new TRelation(LF_EFFETTI);  
  _reff = new TLocalisamfile(LF_REFFETTI);
  _cess = new TLocalisamfile(LF_CESS);  
  _com = new TLocalisamfile(LF_COMUNI);  
  _effetto = new TEffetto;  
  _msk->set_handler(F_CODVAL, codval_handler); 
  _msk->set_handler(F_SHEET_RIGHE, handle_sheet);
  righe_sheet().set_append(TRUE);
  righe_sheet().set_notify(impeff_notify);
  return TRUE;
}

// distrugge la relap
bool TVariazione_effetti::user_destroy()
{
  delete _msk;
  delete _rel;
  delete _effetto;
  delete _reff;
  delete _cess;
  delete _com;
  return TRUE;
}

// handler che permette di effettuare il controllo sul fatto
// che venga inserita almeno una riga per un effetto
bool TVariazione_effetti::handle_sheet(TMask_field &f, KEY k)
{
 TMask& m = f.mask();
 const int mode = m.mode();
  // se si vuole salvare e si č in uno dei due modi di funzionamento 
  if ( k == K_ENTER && (mode == MODE_INS || mode == MODE_MOD) ) 
  { // si controllano le righe del effetto nello sheet                                                            
    TSheet_field& sf = (TSheet_field&)m.field(F_SHEET_RIGHE); 
    int items = sf.items();
    bool found = FALSE;
    for (int i = 0; i < items && !found; i++)// scandisco tutte le righe dello sheet
    {           
      TToken_string& row = sf.row(i);
      real imp_eff(row.get(1));
      // controlla che le righe abbiano un importo 
      if (imp_eff != 0.0) found = TRUE;
    }
    // se non ha trovato righe nello sheet oppure se quelle che ci sono non
    // hanno importo
    if (!found)
    { // non permetto di salvare l'effetto
      error_box("L'effetto non puņ contenere righe con importo nullo!");
      return FALSE;
    }
  } 
  return TRUE;
}

// handler che permette il controllo sulla abilitazione dei campi collegati 
// al codice valuta
bool TVariazione_effetti::codval_handler(TMask_field& f, KEY k)
{ 
  TMask &m = f.mask(); 
  TString val(f.get()); 
  if (f.to_check(k, TRUE))
  {
      // se non c'e valuta o se č lire disabilito i campi collegati
      const bool condition = (val == "LIT" || val.empty());
      m.enable(-1,!condition);                             
      TSheet_field& sf = (TSheet_field&)m.field(F_SHEET_RIGHE); 
      if (condition)
      {           
        m.reset(-1);
        m.reset(F_TOTIMPVAL);
        int items = sf.items();         
        for (int i = 0; i < items; i++)
        {
          TToken_string& row = sf.row(i);   
          row.add(" ", 2);
          row.add(" ", 3);
        }             
      }  
      sf.enable_column(F_IMPFATTVAL, !condition);
      sf.enable_column(F_IMPEFFVAL, !condition);         
      sf.force_update();
  } 
  return TRUE;
}

// funzione chiamata dal notify dello sheet per effettuare il calcolo degli
// importi totali (in lire ed in valuta) dell'effetto
void TVariazione_effetti::calcola_totali()
{ 
  TMask* m = app()._msk;
  TSheet_field& sf = (TSheet_field&)m->field(F_SHEET_RIGHE);
  int items = sf.items();         
  real imp, impval, impeff, impeffval;  
  // scandisco tutte le righe dello sheet e ne prendo gli importi
  // (in lire ed in valuta) e li sommo al totale
  for (int i = 0; i < items; i++)
  {                              
     TToken_string& row = sf.row(i);   
     imp = row.get(1);
     impeff += imp;
     impval = row.get(3);
     impeffval += impval;
  }
  m->set(F_TOTIMP, impeff);
  m->set(F_TOTIMPVAL, impeffval);   
}  

// notify per il calcolo dei totali dell'effetto e per il controllo che non
// vengano eliminate tutte le righe dell'effetto, almeno una deve rimanere
bool TVariazione_effetti::impeff_notify(TSheet_field& s, int r, KEY key)
{            
  if (s.to_check(key, TRUE)) 
  {
  	calcola_totali();
  }      
  if (key == K_ENTER)
  {
  	TToken_string& row = s.row(s.selected());
  	char tipo_num = row.get(8)[0];
    if (tipo_num == 'D')
     	row.add("Definitiva",8);
    else
       	row.add("Provvisoria",8);
  }
  //se rimane una sola riga nello sheet non la si puņ cancellare
  if (key == K_DEL && s.items() == 1)
  {
    error_box("IMPOSSIBILE CANCELLARE: L'effetto deve contenere almeno una riga!");
    return FALSE;
  }
  return TRUE;
}

int ef0100(int argc, char* argv[])
{
  TVariazione_effetti a ;
  a.run(argc, argv, "Variazione Effetti");
  return 0;
}
