#include <relapp.h>
#include <msksheet.h>
#include <sheet.h>
#include <utility.h>
#include <lffiles.h>
#include <clifo.h>
#include "ef0.h"
#include "ef0300.h"
#include "ef0301.h"

//////////////////////////////////////////////////////////////////////////////
//Classe per la gestione di distinte (inserimento, modifica, cancellazione) // 
//  e per la creazione automatica di distinte per importi.                  //
//////////////////////////////////////////////////////////////////////////////
class TVariazione_distinte: public TRelation_application
{
  TMask *_msk, *_m2;
  TDistinta *_distinta;
  TRelation *_rel;                          
  TLocalisamfile *_reff, *_cession, *_clifo;
protected:                            
  virtual void init_query_mode(TMask&); 
  virtual void init_insert_mode(TMask&); 
  virtual void init_modify_mode(TMask&);
  virtual const char* get_next_key();  
  virtual int read(TMask& m);
  virtual int rewrite(const TMask& m);
  virtual int write(const TMask& m);
  virtual bool remove();    
  virtual TMask* get_mask(int mode) {return _msk;}
  virtual bool changing_mask(int mode) {return FALSE;} 
  static bool codval_handler(TMask_field& f, KEY k);
  static bool tipodist_handler(TMask_field& f, KEY k);
  static bool importo_handler(TMask_field& f, KEY k);
  static bool imp_aut_handler(TMask_field& f, KEY k);
  static bool impdist_notify(TSheet_field& s, int r, KEY key); 
  static bool imp_notify(TSheet_field& s, int r, KEY key);       
  static bool conferma_handler(TMask_field& f, KEY k);
  static bool annulla_handler(TMask_field& f, KEY k); 
  static bool from_data_handler(TMask_field& f, KEY k);
  static bool to_data_handler(TMask_field& f, KEY k);
  static bool ordina_handler(TMask_field& f, KEY k);
  static void calcola_totale(); 
  static void calcola();                    
  static void aggiungi();      
  static void carica_riba(int tipopag);
  static void ord_data();
  static void ord_fatt();
  TSheet_field& righe_sheet() const;
  TSheet_field& righe_sel_sheet() const;
  bool cerca(long num);
  bool user_create();
  bool user_destroy();
  void aggiorna();
  void elimina();  
  TToken_string* common_f(const TMask& m);
public:
  virtual TRelation* get_relation() const {return _rel;}
  TVariazione_distinte() {};
  virtual ~TVariazione_distinte() {};
};

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

// quando si va in query mode abilita i campi relativi alla chiave 
// di ricerca e resetta i campi relativi ai totali
void TVariazione_distinte::init_query_mode(TMask&) 
{ 
  _msk->enable(F_NUMBER);
  _msk->enable(F_TIPODIST);
  _msk->reset(F_TOTIMP);
  _msk->reset(F_TOTIMPVAL);
}   

// quando si va in insert mode resetta i campi della maschera relativi
// ai totali, abilita i campi relativi alla valuta e disabilta i campi 
// relativi alla chiave di ricerca
void TVariazione_distinte::init_insert_mode(TMask&)
{ 
  _msk->reset(F_TOTIMP);
  _msk->reset(F_TOTIMPVAL);
  _msk->enable(F_TOTIMPVAL);
  _msk->enable(F_CODVAL);
  _msk->disable(F_NUMBER);
  _msk->disable(F_TIPODIST);
} 

// quando si va in modify mode disabilta i campi relativi alla chiave
// di ricerca
void TVariazione_distinte::init_modify_mode(TMask&)
{ 
  _msk->disable(F_NUMBER);
  _msk->disable(F_TIPODIST);
} 

// ritorna il prossimo numero di distanta valido   
const char* TVariazione_distinte::get_next_key()
{                                                           
  long ndist = 1L;                        
  char tipodist = 'B';
  TLocalisamfile& effetti = _rel->lfile(); 
  effetti.first();// mi posiziono all'inizio del file
  effetti.put(EFF_TIPODIST,tipodist); 
  effetti.put(EFF_NDIST,ndist); 
  effetti.setkey(4);
  int err = effetti.read(_isgteq);                    
  if ( (err == _iskeynotfound) || (err == _iseof) )
  { //se non esiste alcuna distinta: il numero sarà 1                                                                
    err == NOERR;                              
    return format("%d|%ld", F_NUMBER, ndist);
  }
  while (err == NOERR)                         
  { // se esitono già delle distinte:                                                        
    // le leggo tutte  e ne prendo il  numero 
    long n = effetti.get_long(EFF_NDIST);
    // lo confronto con i numero maggiore che ho letto                                                        
    if (n > ndist)                                     
      ndist = n; 
    effetti.setkey(4);  
    err = effetti.next();  
  }                            
  return format("%d|%ld",F_NUMBER,++ndist);  
}  

// ritorna un riferimento allo sheet degli effetti (righe) nella 
// distinta 
TSheet_field& TVariazione_distinte::righe_sheet() const
{
  TSheet_field& r_sheet = (TSheet_field&)_msk->field(F_SHEET_RIBA);
  return r_sheet;
}

// ritorna un riferimento allo sheet delle righe 
TSheet_field& TVariazione_distinte::righe_sel_sheet() const
{
  TSheet_field& r_sheet = (TSheet_field&)_m2->field(F_SHEET);
  return r_sheet;
}

// ritorna TRUE se trovo nell'array delle righe distinta l'effetto 
// passato
bool TVariazione_distinte::cerca(long num)
{
  bool trovato = FALSE;
  int items = _distinta->items(); 
  TArray& righedist = _distinta->righe(); 
  for (int i = 0; i < items; i++)// ciclo sugli elementi dell'array
  {                                                       
     TEffetto& eff = (TEffetto&)righedist[i];
     long num_eff = eff.get_long(EFF_NPROGTR);
     if (num_eff == num) 
     {
      trovato = TRUE;                            
      break;// esco quando ho già trovato l'effetto che cercavo
     }   
  }
  return trovato;   
}         

// metodo che permette di scivere sull'array (in memoria) gli 
// effetti presenti nello sheet
void TVariazione_distinte::aggiorna()
{       
  TSheet_field& shrighe = righe_sheet();
  int items = shrighe.items();                   
  for (int i = 0; i < items; i++)// prendo tutte le righe dello sheet
  {                   
    TToken_string& row = shrighe.row(i);                
    row.restart();               
    long num = row.get_long(1);              
    if (!cerca(num))// se non è già presente in memoria
    {               // carico l'effetto nell'array
      TLocalisamfile eff(LF_EFFETTI);
      TRectype rec = eff.curr();
      eff.setkey(1);
      rec.zero();
      rec.put(EFF_NPROGTR, num);
      int err = eff.read();      
      TEffetto* effetto= new TEffetto(rec);
      TArray& righedist = _distinta->righe();
      righedist.add(effetto);
    }
  }  
}

// Metodo che permette di prendere i dati dalla maschera e metterli in 
// una TToken_string che servirà per passarli alla write della distinta
TToken_string* TVariazione_distinte::common_f(const TMask& m)
{ 
  char tipodist = m.get(F_TIPODIST)[0];// prendo i dati
  long ndist = m.get_long(F_NUMBER);  // identificatvi della
  TDate datadist = (TDate)m.get(F_DATA);// distinta
  long codabi = m.get_long(F_CODABIP);  // dalla maschera
  long codcab = m.get_long(F_CODCABP);  
  m.autosave(*_rel); 
  TToken_string* datidist= new TToken_string; // creo la token string   
  datidist->cut(0);                           
  datidist->add(tipodist); // inserisco i dati nella
  datidist->add(ndist);    // token string
  datidist->add(datadist);
  datidist->add(codabi);
  datidist->add(codcab);
  return datidist;
}

// carica nella maschera i dati dai files 
int TVariazione_distinte::read(TMask& m)
{ 
  m.autoload(*_rel);          
  int err = _rel->status();
  if (err == NOERR)
  {                                                     
    //resetto l'array che contiene gli effetti nella distinta
    err = _distinta->reset();
    // legge la distinta dal record corrente della relazione
    err = _distinta->read(_rel->curr());   
    if (err == NOERR)
    { 
      TToken_string riga(80);
      TSheet_field& shrighe = righe_sheet();
      shrighe.reset();                             
      // prendo il numero di effetti nella distinta 
      int items = _distinta->items();
      TArray& righedist = _distinta->righe();
      // carico tutti gli effetti della distinta nello sheet
      for (int i = 0; i < items; i++) 
      { 
        TEffetto& eff = (TEffetto&)righedist[i];
        riga.cut(0);    
        riga.add(' ');
        const long numero = eff.get_long(EFF_NPROGTR); 
        riga.add(numero);
        riga.add(eff.get(EFF_DATASCAD));                                      
        //prendo la ragione sociale del cliente conoscendone il codice
        long codcf = eff.get_long(EFF_CODCF); 
        _clifo->zero();                                      
        _clifo->put(CLI_TIPOCF , 'C');
        _clifo->put(CLI_CODCF, codcf);
        if (_clifo->read() == NOERR) riga.add(_clifo->get(CLI_RAGSOC));
        if (eff.fatt(numero))// se l'effetto contiene solo una fattura 
        { // metto i riferimenti al documento ed al numero di rata
          const TRectype& rec_r = eff.row_r(1); 
          riga.add(rec_r.get(REFF_NFATT));
          riga.add(rec_r.get(REFF_DATAFATT));
          if (eff.rows_r() == 1) riga.add(rec_r.get(REFF_NRATA));
          else riga.add(("Varie"));
        }
        else// se l'effetto contiene più di una fattura 
        { // non metto i riferimenti al documento ed al numero di rata
          riga.add(("Varie"));
          riga.add(("Varie"));
          riga.add(("Varie"));   
        }
        //gestisco il controllo sulla presenza o meno di una valuta
        TString codval(3);                         
        codval = eff.get(EFF_CODVAL);
        if (i == 0)
        {
          const bool condition = (codval.empty() || codval == "LIT"); 
          m.enable(F_CODVAL, !condition);
          m.enable(F_TOTIMPVAL, !condition);
          if (!condition) 
            m.set(F_CODVAL, codval);
        }
        riga.add(codval);
        riga.add(eff.get(EFF_IMPORTO));
        riga.add(eff.get(EFF_IMPORTOVAL));
        shrighe.row(i) = riga;
      }
    }
  }
  return err;
}

// Si prendono tutte le righe dello sheet e si controlla il primo campo
// se e' a true si distrugge la riga e si aggiorna il file.
// GLI EFFETTI PRESENTI NELLO SHEET DEVONO GIA ESSERE STATI REGISTRATI
// NEL FILE.
void TVariazione_distinte::elimina()
{  
    TEffetto eff;
    TLocalisamfile file(LF_EFFETTI); 
    char tipodist = _msk->get(F_TIPODIST)[0];
    long ndist = _msk->get_long(F_NUMBER);
    TDistinta* distinta = app()._distinta;
    TSheet_field& sf = (TSheet_field&)_msk->field(F_SHEET_RIBA);
    bool condition = FALSE, deleted = FALSE;       
    TArray& righedist = distinta->righe();
    //ciclo sugli elementi dello sheet
    for (int i = 0, k = i+1; i < sf.items(); i++, k++)
    {  
       // per posizionarsi correttamente sulla prima riga dello sheet
       // se ci sono state già delle cancellazioni
       if (deleted) i--;                                          
       if (sf.items() == 1)
       { // non posso cancellare l'effetto se è l'unico della distinta   
         error_box("IMPOSSIBILE CANCELLARE: La distinta deve contenere almeno un effetto!");
         break;
       }
       TToken_string& row = sf.row(i);   
       condition = *row.get(0) == 'X';
       if (condition)
       {                                 
             long num = row.get_long(1);
             //ciclo sugli elementi dell'array
             for (int j = 0; j < distinta->items(); j++)  
             {
                TEffetto& eff = (TEffetto&)righedist[j];
                long num_eff = eff.get_long(EFF_NPROGTR);
                if (num_eff == num)               
                {
                  // tolgo l'effetto dall'array
                  righedist.destroy(j,TRUE);                
                  break;
                }  
             }                                                          
             // tolgo l'effetto dallo sheet       
             sf.destroy(i); deleted = TRUE;
             eff.read(file, tipodist, ndist, k);
             eff.zero(EFF_TIPODIST);
             eff.zero(EFF_NDIST);
             eff.zero(EFF_DATADIST);
             eff.zero(EFF_NRIGADIST);
             eff.zero(EFF_CODABIP);
             eff.zero(EFF_CODCABP); 
             eff.rewrite(file); 
       }    
       else deleted = FALSE;
    }
}          

// riscrive distinta
int TVariazione_distinte::rewrite(const TMask& m)
{
  // prima di riscrive controllo se ci sono effetti nello sheet 
  // selezionati per l'eliminazione
  TSheet_field& sf = righe_sheet();
  bool condition = FALSE;       
  for (int i = 0; i < sf.items(); i++)
  {
    TToken_string& row = sf.row(i);                      
    // se trovo un effetto selezionato esco dal ciclo
    if (condition = *row.get(0) == 'X') break;           
  }             
  if (condition)                                                      
     if (yesno_box("Vuoi veramete eliminare gli effetti selezionati"))
     	elimina();               
  //resetto l'array che contiene gli effetti nella distinta
  int err = _distinta->reset();
  char tipodist = m.get(F_TIPODIST)[0];               
  long ndist =  m.get_long(F_NUMBER); 
  aggiorna();                                                             
  err = _distinta->rewrite(common_f(m));
  if (err == NOERR)                 
  { // riposiziono la relazione                             
    _rel->lfile().setkey(4); 
    TRectype& curr = _rel->curr();
    curr.put(EFF_TIPODIST, tipodist);
    curr. put(EFF_NDIST, ndist);
    curr. put(EFF_NRIGADIST, 1);
    _rel->read();
  } 
  return err;  
}

// scrive distinta
int TVariazione_distinte::write(const TMask& m)
{                                                                        
  //resetto l'array che contiene gli effetti nella distinta
  int err = _distinta->reset();
  char tipodist = m.get(F_TIPODIST)[0];
  long ndist =  m.get_long(F_NUMBER);              
  aggiorna();                                                    
  err = _distinta->write(TRUE, common_f(m));
  if (err == NOERR)           
  {  //riposiziono la relazione                         
    _rel->lfile().setkey(4); 
    TRectype& curr = _rel->curr();
    curr.put(EFF_TIPODIST, tipodist);
    curr. put(EFF_NDIST, ndist);
    curr. put(EFF_NRIGADIST, 1);
    _rel->read();
  } 
  return err;  
}

// Metodo che permette di eliminare una distinta, l'eliminazione 
// consiste nell'andare a togliere dagli effetti i dati ad essa 
// relativi.
bool TVariazione_distinte::remove() 
{                                           
  TMask* m = app()._msk;
  char tipodist = m->get(F_TIPODIST)[0];
  long ndist =  m->get_long(F_NUMBER);    
  int err = _distinta->remove(tipodist, ndist) == NOERR;
  return err;  
}

// creo la relap
bool TVariazione_distinte::user_create()
{
  _msk = new TMask("ef0300a");  
  _m2 = new TMask("ef0300c");
  _rel = new TRelation(LF_EFFETTI);
  _reff = new TLocalisamfile(LF_REFFETTI);
  _cession = new TLocalisamfile(LF_CESS);  
  _clifo = new TLocalisamfile(LF_CLIFO); 
  _distinta = new TDistinta;  
  set_search_field(F_NUMBER);//setto il campo di ricerca della distinta
  _msk->set_handler(F_CODVAL, codval_handler); 
  _msk->set_handler(F_TIPODIST, tipodist_handler); 
  _msk->set_handler(F_IMP, importo_handler);
  _m2->set_handler(F_TOTIMPDIST, imp_aut_handler);
  _m2->set_handler(DLG_OK, conferma_handler);
  _m2->set_handler(DLG_CANCEL, annulla_handler);
  _m2->set_handler(F_DADATA, from_data_handler);
  _m2->set_handler(F_ADATA, to_data_handler);
  _m2->set_handler(F_TIPORD, ordina_handler);
  righe_sheet().set_notify(impdist_notify);  
  righe_sel_sheet().set_notify(imp_notify); 
  return TRUE;
}

// distruggo la relap
bool TVariazione_distinte::user_destroy()
{
  delete _msk;  
  delete _m2;
  delete _rel;                          
  delete _reff;
  delete _cession;                    
  delete _clifo;
  delete _distinta;
  return TRUE;
}

// Permette di caricare lo sheet per la selezione delle riba da 
// aggiungere alla distinta: vengono presi tutti gli effetti sul file
// LF_EFFETTI che non hanno ancora un riferimento ad una distinta;
// inoltre è possibile inserire nella distinta effetti aventi lo stesso
// tipo di pagamento.
void TVariazione_distinte::carica_riba(int tipopag)
{                                     
// deve caricare solo quegli effetti che non hanno riferimento alla
// distinta quindi setta i campi ad essa relativi a zero  
  char tipodist = 0;                       
  long ndist = 0;
  long nrigadist = 0;
  TEffetto eff;     
  TLocalisamfile f(LF_EFFETTI);             
  // per prendere la ragione sociale del cliente di cui ho il codice
  TLocalisamfile * clifo = app()._clifo;
  TToken_string riga(80);           
  TMask* m2 = app()._m2;              
  m2->reset();
  TSheet_field& sf = (TSheet_field&)m2->field(F_SHEET);
  sf.reset();                    
  int err, i = 0;
  err = eff.read(f, tipodist, ndist, nrigadist);           
  int tipop =  eff.get_int(EFF_TIPOPAG); 
  while ( (err == NOERR) && (tipodist == 0)) 
  {  
     bool condition = (tipopag == tipop);
     // se effetti di tipo cambiario (pagherò, tratta, tratta accettata)
     if (tipopag == 2 || tipopag ==5 || tipopag == 7)
        condition = (tipop == 2 || tipop ==5 || tipop == 7); 
     // se non indico un tipo di effetto prendo il tipo del primo che 
     // seleziono   
     if (tipopag == 0) condition =TRUE;
     if (condition)
    {
        riga.cut(0);
        riga.add(' ');
        const long numero = eff.get_long(EFF_NPROGTR); 
        riga.add(numero);
        riga.add(eff.get(EFF_DATASCAD)); 
        long codcf = eff.get_long(EFF_CODCF);
        clifo->zero();
        clifo->put(CLI_TIPOCF, 'C');
        clifo->put(CLI_CODCF, codcf);
        if (clifo->read() == NOERR) riga.add(clifo->get(CLI_RAGSOC));
        if (eff.fatt(numero))// se l'effetto contiene solo una fattura 
        {   // metto i riferimenti al documento ed al numero di rata
            const TRectype& rec_r = eff.row_r(1); 
            riga.add(rec_r.get(REFF_NFATT));
            riga.add(rec_r.get(REFF_DATAFATT));
            if (eff.rows_r() == 1) riga.add(rec_r.get(REFF_NRATA));
            else riga.add(("Varie"));
        }
        else// se l'effetto contiene più di una fattura 
        {   // non metto i riferimenti al documento ed al numero di rata
            riga.add(("Varie"));
            riga.add(("Varie"));
            riga.add(("Varie"));   
        }
        riga.add(eff.get(EFF_CODVAL));
        riga.add(eff.get(EFF_IMPORTO));
        riga.add(eff.get(EFF_IMPORTOVAL));
        sf.row(i) = riga;
        i++;
    }      
    f.setkey(4);
    err = eff.next(f);//leggo l'effetto successivo 
    tipodist = eff.get(EFF_TIPODIST)[0];// e ne prendo il tipo distinta 
    if (tipopag == 0) 
    	tipopag = tipop;
    tipop =  eff.get_int(EFF_TIPOPAG);
  } 
}

// Handler che permette il controllo sulla abilitazione dei campi
// collegati al codice valuta
bool TVariazione_distinte::codval_handler(TMask_field& f, KEY k)
{ 
  TMask &m = f.mask(); 
  TString val(f.get()); 
  if (f.to_check(k, TRUE))
  {
      const bool condition = (val == "LIT" || val.empty());
      m.enable(F_TOTIMPVAL,!condition);  
      if (condition)
        m.reset(F_TOTIMPVAL);
  } 
  return TRUE;
}

// Handler per gestire il fatto che una distinta allo sconto può 
// contenere solo effetti cambiari
bool TVariazione_distinte::tipodist_handler(TMask_field& f, KEY k)
{ 
  TMask &m = f.mask(); 
  char tipo(f.get()[0]); 
  if(k == K_SPACE)
  {
     if(tipo == 'S')
     	m.set(F_TIPOPAG,2);
  } 
  return TRUE;
}

// Handler per gestire il caricamento degli effetti nella distinta 
// in automatico relativamente ad un importo fissato (per la maschera
// princiapale)
bool TVariazione_distinte::importo_handler(TMask_field& f, KEY k)
{ 
  TMask& m = f.mask();        
  TSheet_field& sf_riba = (TSheet_field&)m.field(F_SHEET_RIBA);
  if (f.to_check(k, TRUE))
  {
    const int mode = m.mode();
    if( mode == MODE_INS || mode == MODE_MOD ) 
    {     
      TMask* m2 = app()._m2;
      long imp_pres = m.get_long(F_TOTIMP);// importo presentato
      long imp = m.get_long(F_IMP);// importo distinta
      long impdist = imp - imp_pres;   
      int tipopag = m.get_int(F_TIPOPAG); 
// se importo distinta maggiore importo presentato si devono andare a
// caricare effetti in automatico per un valore minore uguale alla 
// differenza dei suddetti importi 
      if (impdist > 0)
      { 
        app().begin_wait();
        carica_riba(tipopag);     
        app().end_wait();
        m2->reset(F_TOTIMPDIST);
        m2->reset(F_IMPSEL);
        m2->set(F_TOTIMPDIST, impdist);
        m2->run();
      }
      if (impdist < 0)
        error_box("Il valore di presentazione non può superare l'importo della distinta");        
    }
  }                                        
  sf_riba.force_update();
  return TRUE;
}
    
// Handler per gestire il caricamento degli effetti nella distinta in
// automatico relativamente ad un importo fissato (per la maschera 
// secondaria)
bool TVariazione_distinte::imp_aut_handler(TMask_field& f, KEY k)
{ 
  TMask& m2 = f.mask();
// se quando si entra nell maschera il campo contiene un valore 
// significa che si deve procedere con il caricamento automatico 
// di effetti per l'importo iscritto nel campo
  if (f.to_check(k, TRUE))
  {
    TMask* m = app()._msk; 
    TSheet_field& sf = (TSheet_field&)m2.field(F_SHEET);
    TSheet_field& sf_riba = (TSheet_field&)m->field(F_SHEET_RIBA); 
    long impdist = m->get_long(F_IMP) - m->get_long(F_TOTIMP);
    long tot_imp_dist = m2.get_long(F_TOTIMPDIST), 
         impsel = 0;
    if (tot_imp_dist != 0 && impdist != 0)
    { // se i due importi sono diversi da zero  
      TString val = m->get(F_CODVAL);
      int items = sf.items();                       
      // cerca se esiste un effetto con importo uguale a quello
      // da caricare    
      bool caricato = FALSE;
      for(int i = 0; i < items && !caricato; i++)
      {
         TToken_string& row = sf.row(i);
         TString codval = row.get(7);
         // se la valuta non appare o è lire faccio in modo che vengano
         // presi gli effetti con valuta inesistente 
         if (codval == " " || codval == "LIT")
            codval.trim();     
         long imp = row.get_long(8);        
         if (imp == tot_imp_dist && codval == val) 
         {  
            row.add('X',0);
            impsel += imp;
            caricato = TRUE;
         } 
      }
      // se non esiste un effetto con importo uguale a quello
      // da caricare carico l'importo sommando più effetti    
      if (!caricato)
      {
        for(int i = 0; i < items; i++)
        {
           TToken_string& row = sf.row(i);
           TString codval = row.get(7);
           // se la valuta non appare o è lire faccio in modo che 
           // vengano presi gli effetti con valuta inesistente 
           if (codval == " " || codval == "LIT")
              codval.trim();     
           long imp = row.get_long(8);        
          // se l'importo, della riga corrente dello sheet, è minore 
          // dell 'importo che si deve caricare e se lo rimane anche 
          // sommato all'importo già selezionato, si procede a rendere 
          // la riga selezionata per il caricamento                                                       
           if ((imp <= tot_imp_dist) && ((impsel+imp) <= tot_imp_dist)) 
           {  
              if ((sf_riba.items() == 0) && (val.empty()|| val == "LIT"))//se non è stata specificata una valuta si prende quella del
              { //primo effetto che si carica nella distinta
                 m->set(F_CODVAL, codval);    
                 val = m->get(F_CODVAL);
              }
              if (codval == val)
              {
                 row.add('X',0);
                 impsel += imp;
              }
           } 
           if (impsel <= tot_imp_dist) continue;
           else break;     
        }
      }  
      sf.force_update();
      calcola();      
    }  
  }
  return TRUE;
} 

// Handler per gestire la pressione del bottone conferma della maschera
// per l'aggiunta delle riba (ef0300c)
bool TVariazione_distinte::conferma_handler(TMask_field& f, KEY k)
{  
  TMask* msk = app()._msk;
  TSheet_field& sf_riba = (TSheet_field&)msk->field(F_SHEET_RIBA);    
  if (k==K_ENTER)
  { 
    TMask& m = f.mask();
    m.close(); // chiudo la maschera secondaria
// scarico tutte le righe, selezionate, dello sheet della maschera
// secondaria nello sheet della maschera primaria della relap (ef0300a)   
    TSheet_field& sf = (TSheet_field&)m.field(F_SHEET);
    int items = sf.items();  
    bool condition = FALSE;       
    for (int i = 0; i < items; i++)
    {
       TToken_string& row = sf.row(i);   
       condition = *row.get(0)== 'X';
       if (condition) 
       { 
         row[0] = ' ';
         sf_riba.row(-1) = row;
       }  
    }                  
  }   
  sf_riba.force_update();// obbligo all'aggiornamento dello sheet
  calcola_totale(); // obbligo al ricalcolo del totale 
  return TRUE;  
}             

// Handler per gestire la pressione del bottone annulla della maschera
// per l'aggiunta delle riba (ef0300c)
bool TVariazione_distinte::annulla_handler(TMask_field& f, KEY k)
{    
  TMask& m = f.mask();
  m.close();  
  return TRUE;  
}             

// Handler per gestire la scelta per data, nella maschera di scelta 
// delle riba (ef0300c)
bool TVariazione_distinte::from_data_handler(TMask_field& f, KEY k)
{
  if (k == K_TAB)
  {                   
   TMask& m = f.mask();
   if (!f.get().empty())
   {                                        
      bool deleted = FALSE;    
      TDate data = m.get_date(F_DADATA);
      TSheet_field& sf = (TSheet_field&)m.field(F_SHEET);
// tolgo dallo sheet gli effetti che hanno una data minore a quella 
// indicata nel campo della maschera      
      for(int i = 0; i < sf.items(); i++)
      {
          if (deleted) i--;
          TToken_string& row = sf.row(i);
          TDate data_sh = (TDate)row.get(2);
          if (data_sh < data)               
          {
             sf.destroy(i); 
             deleted = TRUE; 
          }
          else deleted = FALSE;   
      }   
   }
  }
  return TRUE;  
}
                     
// Handler per gestire la scelta per data, nella maschera di scelta 
// delle riba (ef0300c)
bool TVariazione_distinte::to_data_handler(TMask_field& f, KEY k)
{              
  if (k == K_TAB)
  {        
   TMask& m = f.mask();                         
   if (!f.get().empty())
   {                             
      bool deleted = FALSE;    
      TDate data = m.get_date(F_ADATA);
      TSheet_field& sf = (TSheet_field&)m.field(F_SHEET);
// tolgo dallo sheet gli effetti che hanno una data maggiore a quella
// indicata nel campo della maschera            
      for(int i = 0; i < sf.items(); i++)
      {
          if (deleted) i--;
          TToken_string& row = sf.row(i);
          TDate data_sh = (TDate)row.get(2);
          if (data_sh > data)               
          {
             sf.destroy(i); 
             deleted = TRUE; 
          }
          else deleted = FALSE;  
      }   
   }
  }  
  return TRUE; 
}  

// COMPARE FUNCTION per l'ordinamento per data degli effetti presenti
// nello sheet, nella maschera di scelta delle riba (ef0300c)
HIDDEN int confronta_data(const TObject** o1, const TObject** o2)
{
  int val;
  TToken_string* s1 = (TToken_string*) *o1; 
  TToken_string* s2 = (TToken_string*) *o2;   
  TDate data1 = s1->get(2);
  TDate data2 = s2->get(2);
  if (data1 == data2)
    val = 0;
  else
   val = (data1 > data2) ? +1 : -1; 
  return val;  
}

// Handler per gestire l'ordinamento per data degli effetti presenti 
// nello sheet, nella maschera di scelta delle riba (ef0300c) 
void TVariazione_distinte::ord_data()
{     
  TMask* m = app()._m2;
  TSheet_field& sf = (TSheet_field&)m->field(F_SHEET);
  // scarico tutte le righe dello sheet in un array
  TArray& effetti = sf.rows_array();
  app().begin_wait();
  // faccio l'ordinamento degli elementi dell'array
  effetti.sort(confronta_data);
  app().end_wait();
  sf.force_update();
}

// COMPARE FUNCTION per l'ordinamento per numero e data fattura degli
// effetti presenti nello sheet, nella maschera di scelta delle riba
HIDDEN int confronta_fatt(const TObject** o1, const TObject** o2)
{ 
  int val;
  TToken_string* s1 = (TToken_string*) *o1; 
  TToken_string* s2 = (TToken_string*) *o2;
  long num1 = s1->get_long(4);
  long num2 = s2->get_long(4);
  TDate data1 = s1->get(5);
  TDate data2 = s2->get(5);
  // ordinamento sul numero fattura
  if (num1 != num2)     
  {
    val = (num1 > num2) ? +1 : -1;
    return val;
  }
  // ordinamento sulla data fattura  
  if (data1 == data2)
  {
    val = 0; 
    return val;
  }  
  else 
  {
    val = (data1 > data2) ? +1 : -1;
    return val;  
  }
}
                     
// Handler per gestire l'ordinamento per numero e data fattura degli
// effetti presenti nello sheet, nella maschera di scelta delle riba
void TVariazione_distinte::ord_fatt()
{
  TMask* m = app()._m2;
  TSheet_field& sf = (TSheet_field&)m->field(F_SHEET);
  // scarico le righe dello sheet in un array
  TArray& effetti = sf.rows_array();
  app().begin_wait();
  effetti.sort(confronta_fatt);// ordino gli elementi dell'array
  app().end_wait();
  sf.force_update();
}
                  
// Handler per gestire i diversi ordinamenti, nella maschera di scelta
// delle riba (ef0300c) 
bool TVariazione_distinte::ordina_handler(TMask_field& f, KEY k)
{              
  if (f.to_check(k, TRUE))
  {
    char ord = f.get()[0];
    if (ord == 'S')//ordino gli effetti nello sheet per data
      ord_data();
    if (ord == 'F')
      ord_fatt();//ordino gli effetti nello sheet per fattura   
  }
  return TRUE; 
}

// Metodo che calcola i totali relativi alla distinta (totale in 
// lire e totale in valuta(se presente)) nella maschera principale
void TVariazione_distinte::calcola_totale()
{ 
  TMask* m = app()._msk;
  TSheet_field& sf = (TSheet_field&)m->field(F_SHEET_RIBA);
  int items = sf.items();         
  real imp, impval, impdist, impdistval;  
  for (int i = 0; i < items; i++)
  {
     TToken_string& row = sf.row(i);     
// se l'effetto è selezionato per l'eliminazione tolgo il suo importo 
// dal totale presentazione della distinta    
     bool condition = *row.get(0) == 'X';
     if (condition)
     {
       imp = row.get(8);
       impdist -= imp;
       impval = row.get(9);
       impdistval -= impval;
     }
// se l'effetto no è selzionato aggiungo il suo importo al totale
// presentazione della distinta   
     imp = row.get(8);
     impdist += imp;
     impval = row.get(9);
     impdistval += impval; 
  }
  m->set(F_TOTIMP, impdist);
  m->set(F_TOTIMPVAL, impdistval);   
  m->set(F_IMP, impdist);
}  

// Metodo che calcola i totali relativi alla selezione effetti per la
// distinta nella maschera di scelta delle riba (ef0300c)
void TVariazione_distinte::calcola()
{ 
  TMask* m2 = app()._m2;                   
  TMask* m = app()._msk;   
  TSheet_field& sf = (TSheet_field&)m2->field(F_SHEET);
  int items = sf.items();         
  real imp, impsel;                  
  long imp_pres = m->get_long(F_TOTIMP);
  long importo = m->get_long(F_IMP);
  long impdist = importo - imp_pres;
  if (impdist == 0)
    m2->set(F_TOTIMPDIST, importo); 
  m2->set(F_IMPSEL, impsel);  
  for (int i = 0; i < items; i++)
  {
     TToken_string& row = sf.row(i);     
// se l'effetto è selezionato aggiungo il suo importo al totale importo
// selezionato     
     bool condition = *row.get(0) == 'X';
     if (condition)
     {
       imp = row.get(8);
       impsel += imp;
       m2->set(F_IMPSEL, impsel);
       if (impdist == 0 && imp_pres == 0)
         m2->set(F_TOTIMPDIST, impsel);  
     }
  }
}  

// Notify per il calcolo dei totali relativi alla selezione effetti 
// per la distinta nella maschera di scelta delle riba (ef0300c)
bool TVariazione_distinte::imp_notify(TSheet_field& s, int r, KEY key)
{            
  if (s.to_check(key, TRUE)) 
    calcola();
  return TRUE;
}

// Metodo che permette di aggiungere effetti alla distinta caricandoli
// tra quelli non ancora assegnati, chiamato quando si aggiunge una 
// riga allo sheet degli effetti della distinta 
void TVariazione_distinte::aggiungi()
{
    TMask* m = app()._msk;  
    TMask* m2 = app()._m2;   
    int tipopag = m->get_int(F_TIPOPAG); 
    app().begin_wait();
    carica_riba(tipopag);     
    app().end_wait();
    m2->reset(F_TOTIMPDIST);
    m2->reset(F_IMPSEL);
    m2->run();
}

// Notify per il calcolo dei totali relativi alla distinta  
// nella maschera della relap (ef0300a)
bool TVariazione_distinte::impdist_notify(TSheet_field& s, int r, KEY key)
{            
  if (s.to_check(key, TRUE)) 
    calcola_totale();
  if (key == K_CTRL + K_INS) 
    aggiungi();  
  return TRUE;
}

int ef0300(int argc, char* argv[])
{
  TVariazione_distinte a ;
  a.run(argc, argv, "Variazione Distinte");
  return 0;
}