#include <relapp.h>  
#include <msksheet.h>
#include <utility.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;                          

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;} 
  virtual bool has_filtered_cursor() const { return true; }
  static bool tipodist_handler(TMask_field& f, KEY k);
  static bool importo_handler(TMask_field& f, KEY k);
  static bool imp_sel_handler(TMask_field& f, KEY k);
  static bool check_handler(TMask_field& f, KEY k);
  static bool imp_notify(TSheet_field& s, int r, KEY key); 
  static bool dist_check_handler(TMask_field& f, KEY key);
  static bool impdist_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 data_handler(TMask_field& f, KEY k);
  static bool ordina_handler(TMask_field& f, KEY k);
  static bool uncontabilize_handler(TMask_field& f, KEY k);
  static void calcola_totale(); 
  static void calcola();                    
  static void aggiungi();      
  static bool effetto_aggiunto(const long numero);
  static void carica_riba(int tipopag, const bool reset = TRUE);
  static void ord_data();
  static void ord_fatt();
// ritorna un riferimento allo sheet degli effetti (righe) nella 
// distinta 
  TSheet_field& righe_sheet() const { return _msk->sfield(F_SHEET_RIBA); }
// ritorna un riferimento allo sheet delle righe 
  TSheet_field& righe_sel_sheet() const { return _m2->sfield(F_SHEET); }
  bool cerca(long num);
  bool user_create();
  bool user_destroy();
  void aggiorna();
  TToken_string* common_f(const TMask& m, TToken_string& datidist);

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->enable(F_TIPOPAG);
  _msk->enable(F_TIPOCF);
  _msk->hide(F_UNCONTABIL);
}   

// 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& m)
{ 
  m.reset(F_TOTIMP);
  m.enable(F_CODVAL);
  m.disable(F_NUMBER);
  m.disable(F_TIPODIST);    
  m.enable(F_TIPOPAG); 
  m.enable(F_TIPOCF);
} 

// quando si va in modify mode disabilta i campi relativi alla chiave
// di ricerca
void TVariazione_distinte::init_modify_mode(TMask& m)
{ 
  m.disable(F_NUMBER);
  m.disable(F_TIPODIST);
  m.disable(F_TIPOPAG);
  m.disable(F_TIPOCF);

  const bool cont = _distinta->contabilizzata();
  m.show(F_UNCONTABIL, cont);
} 

// ritorna il prossimo numero di distinta valido   
const char* TVariazione_distinte::get_next_key()
{                                                           
  const TString& tipodist = curr_mask().get(F_TIPODIST);
  TLocalisamfile& effetti = _rel->lfile(); 
  effetti.put(EFF_TIPODIST,tipodist); 
  effetti.put(EFF_NDIST,99999L); 
  effetti.setkey(4);
                                    
  long ndist = 1;                                  
  const int err = effetti.read(_isgreat); 
  if (err != _isemptyfile)
  {                 
    if (err == NOERR)
      effetti.prev();
    if (effetti.get(EFF_TIPODIST) == tipodist)
      ndist += effetti.get_long(EFF_NDIST);
  }

  return format("%d|%ld",F_NUMBER,ndist);  
}  

// ritorna TRUE se trovo nell'array delle righe distinta l'effetto 
// passato
bool TVariazione_distinte::cerca(long num)
{
  TArray& righedist = _distinta->righe(); 

  for (int i = _distinta->items() - 1; i >= 0; i--)// ciclo sugli elementi dell'array
  {                                                       
     TEffetto& eff = (TEffetto&)righedist[i];

     if (num == eff.get_long(EFF_NPROGTR))
       return TRUE;
  }
  return FALSE;   
}         

// 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(shrighe.cid2index(F_NRIBA));              
    if (!cerca(num))// se non � gi� presente in memoria
    {               // carico l'effetto nell'array
      const TRectype & rec = cache().get(LF_EFFETTI, num);

      TEffetto* effetto = new TEffetto((TRectype &) 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, TToken_string& datidist)
{ 
  const char tipodist = m.get(F_TIPODIST)[0];  // prendo i dati
  const long ndist = m.get_long(F_NUMBER);     // identificatvi della
  const TDate datadist = (TDate)m.get(F_DATA); // distinta
  const TString& codabi = m.get(F_CODABIP);    // dalla maschera
  const TString& codcab = m.get(F_CODCABP);  
  
  TString4 progbnp = m.get(F_PROG);
  if (real::is_null(progbnp))
    progbnp.cut(0);
  else
    progbnp.right_just(2, '0');

  m.autosave(*_rel); 
  
  datidist.add(tipodist); // inserisco i dati nella
  datidist.add(ndist);    // token string
  datidist.add(datadist);
  datidist.add(codabi);
  datidist.add(codcab);
  datidist.add(progbnp);
  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
    _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 
      const int items = _distinta->items();
      // carico tutti gli effetti della distinta nello sheet
      if (items > 0)
      {
        TString16 codice;  // Codice per cache

        TArray& righedist = _distinta->righe();
        TEffetto& e = (TEffetto&)righedist[0];
        m.set(F_DATA, e.get(EFF_DATADIST));// distinta
        m.set(F_CODABIP, e.get(EFF_CODABIP));  // dalla maschera
        m.set(F_CODCABP, e.get(EFF_CODCABP));  
        m.set(F_PROG, e.get(EFF_PROGBNP));  
        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
          
          codice.cut(0);
          codice << eff.get_tipo(); codice << '|' << eff.get(EFF_CODCF);
          riga.add(cache().get(LF_CLIFO, codice, CLI_RAGSOC));
            
          codice = eff.get(EFF_CODABI);
          TString desc = cache().get("%BAN", codice, "S0");
          codice << eff.get(EFF_CODCAB);
          desc << ' ' << cache().get("%BAN", codice, "S0");
          desc.cut(50);
          riga.add(desc);
          
          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(TR("Varie"));
          }
          else// se l'effetto contiene pi� di una fattura 
          { // non metto i riferimenti al documento ed al numero di rata
            riga.add(TR("Varie"));
            riga.add(TR("Varie"));
            riga.add(TR("Varie"));   
          }
          //gestisco il controllo sulla presenza o meno di una valuta
          const TString16 codval(eff.get(EFF_CODVAL));
          if (i == 0)
          {          
            const bool valuta = ::is_true_value(codval); 
            m.set(F_CODVAL, codval);
            m.enable(F_CODVAL, valuta);
          }
          riga.add(codval);
          const real soldi = eff.get_real(EFF_IMPORTO);
          riga.add(soldi.string());
          const real soldival = eff.get_real(EFF_IMPORTOVAL);
          if (!soldival.is_zero())
            riga.add(soldival.string());
  
          shrighe.row(i) = riga;
        }
      }
    }
  }
  return err;
}

// riscrive distinta
int TVariazione_distinte::rewrite(const TMask& m)
{
  // prima di riscrive controllo se ci sono effetti nello sheet 
  // selezionati per l'eliminazione
  TEffetto eff;
  TLocalisamfile file(LF_EFFETTI); 
  const char tipodist = _msk->get(F_TIPODIST)[0];
  const long ndist = _msk->get_long(F_NUMBER);
  TDistinta * distinta = app()._distinta;
  TSheet_field& sf = righe_sheet();
  int items = sf.items();
  int to_delete = 0;               
  for (int i = items - 1; i >= 0 ; i--)
  {
    TToken_string& row = sf.row(i);   
    if (*row.get(0) == 'X') // to delete
      to_delete++;
  }
  if (items <= to_delete)
  { // non posso cancellare tutti gli effetti di una distinta 
    error_box(TR("Impossibile escludere tutti gli effetti dalla distinta.\n Utilizzare elimina per cancellarla."));
    return NOERR;
  }
  if (to_delete > 0)
  {
    TArray& righedist = distinta->righe();
    //ciclo sugli elementi dello sheet
  
    for (int i = items - 1; i >= 0; i--)
    {  
      TToken_string& row = sf.row(i);   
      if (*row.get(0) == 'X') // to delete
      {                                 
        const long num = row.get_long(1);
        //ciclo sugli elementi dell'array
        for (int j = 0; j < distinta->items(); j++)  
        {
          TEffetto& eff = (TEffetto&)righedist[j];
          if (num == eff.get_long(EFF_NPROGTR))
          {
            // tolgo l'effetto dall'array
            righedist.destroy(j,TRUE);                
            break;
          }  
        }                                                          
        // tolgo l'effetto dallo sheet       
        sf.destroy(i);
        eff.read(file, tipodist, ndist, i + 1);
        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.zero(EFF_PROGBNP); 
        eff.rewrite(file); 
      }    
    }
  }
  //resetto l'array che contiene gli effetti nella distinta
  int err = _distinta->reset();
  aggiorna();                      
  
  TToken_string datidist;                                       
  err = _distinta->rewrite(common_f(m, datidist));
  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();                                      
  
  TToken_string datidist;              
  err = _distinta->write(TRUE, common_f(m, datidist));
  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 = _msk;
  char tipodist = m->get(F_TIPODIST)[0];
  long ndist =  m->get_long(F_NUMBER);    
  bool err = _distinta->remove(tipodist, ndist) == NOERR;
  return err;  
}

// creo la relap
bool TVariazione_distinte::user_create()
{
  open_files(LF_TAB, LF_TABCOM, LF_EFFETTI, LF_REFFETTI, LF_CESS, NULL);
  _msk = new TMask("ef0300a");  
  _m2 = new TMask("ef0300c");
  _rel = new TRelation(LF_EFFETTI);
	if (_rel->last() == NOERR)
		_msk->set(F_TIPODIST, _rel->curr().get("TIPODIST"));

  _distinta = new TDistinta;  
  set_search_field(F_NUMBER);//setto il campo di ricerca della distinta
  
  _msk->set_handler(F_TIPODIST, tipodist_handler); 
  _msk->set_handler(F_IMPBUTTON, importo_handler);
  _msk->set_handler(F_UNCONTABIL, uncontabilize_handler);
  righe_sheet().set_notify(impdist_notify);  
  righe_sheet().sheet_mask().set_handler(FIRST_FIELD, dist_check_handler);

  _m2->set_handler(F_IMPSEL, imp_sel_handler);
  _m2->set_handler(DLG_OK, conferma_handler);
  _m2->set_handler(DLG_CANCEL, annulla_handler);
  _m2->set_handler(F_DADATA, data_handler);
  _m2->set_handler(F_ADATA, data_handler);
  _m2->set_handler(F_TIPORD, ordina_handler);
  righe_sel_sheet().set_notify(imp_notify);  
  righe_sel_sheet().sheet_mask().set_handler(FIRST_FIELD, check_handler);
  return TRUE;
}

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

// Cerca se la riba indicata da <numero> e' gia stato inserita nello spreadsheet principale
bool TVariazione_distinte::effetto_aggiunto(const long numero)
{
  TMask* m = app()._msk;
  TSheet_field& sf_riba = (TSheet_field&)m->field(F_SHEET_RIBA); 
  bool rt = FALSE;
  const int items = sf_riba.items();
  for (int i=0; i<items && !rt; i++)
  {
    TToken_string& row = sf_riba.row(i);
    if (row.get_long(1) == numero)
      rt = TRUE;
  }
  
  return rt;
}

// 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, const bool reset)
{                                     
// 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;
  int nrigadist = 0;
  TEffetto eff;     
  TLocalisamfile f(LF_EFFETTI);             
  // per prendere la ragione sociale del cliente di cui ho il codice
  TToken_string riga(80);           
  TMask* m2 = app()._m2;              
  if (reset)
    m2->reset();
  TSheet_field& sf = (TSheet_field&)m2->field(F_SHEET);
  if (reset)
    sf.reset();                    

  TString16 codval = app()._msk->get(F_CODVAL);
  TString16 codtab;

  int err, i = 0;
  err = eff.read(f, tipodist, ndist, nrigadist);           
  int tipop =  eff.get_int(EFF_TIPOPAG); 
  int tipod = app()._msk->get(F_TIPOCF)[0];  
  
  while ( (err == NOERR) && (tipodist == 0)) 
  {  
     // se effetti di tipo cambiario (pagher�, tratta, tratta accettata)
     // se non indico un tipo di effetto prendo il tipo del primo che 
     // seleziono   
    const bool to_select = (tipopag == 0) || (tipopag == tipop) ||
                           ((tipopag == 2 || tipopag ==5 || tipopag == 7) &&
                           (tipop == 2 || tipop ==5 || tipop == 7)); 
    const char tipo = eff.get_tipo();

    TString16 valuta = eff.get(EFF_CODVAL);
      
    const bool valuta_ok = ::same_values(valuta, codval);
    const long numero = eff.get_long(EFF_NPROGTR); 

    if (to_select && valuta_ok && !effetto_aggiunto(numero) && tipo == tipod)
    {
      riga = " ";   // Campo selezione

      riga.add(numero);
      riga.add(eff.get(EFF_DATASCAD)); 
      
      TString16 codice;
      codice << tipo << '|' << eff.get(EFF_CODCF);
      riga.add(cache().get(LF_CLIFO, codice, CLI_RAGSOC));

      codice = eff.get(EFF_CODABI);
      TString desc(cache().get("%BAN", codice, "S0"));
      codice << eff.get(EFF_CODCAB);
      desc << " " << cache().get("%BAN", codice, "S0");
      desc.cut(50);
      riga.add(desc);

      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((TR("Varie")));
      }
      else// se l'effetto contiene pi� di una fattura 
      {   // non metto i riferimenti al documento ed al numero di rata
        riga.add((TR("Varie")));
        riga.add((TR("Varie")));
        riga.add((TR("Varie")));   
      }
      riga.add(valuta);

      const real soldi = eff.get_real(EFF_IMPORTO);
      riga.add(soldi.string());

      const real soldival = eff.get_real(EFF_IMPORTOVAL);
      if (!soldival.is_zero())
        riga.add(soldival.string());
        
      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 
    tipop =  eff.get_int(EFF_TIPOPAG);
  } 
}

// 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)
{ 
  if (k == K_SPACE)
  {         
    TMask &m = f.mask(); 
    const bool allo_sconto = f.get()[0] == 'S';
   
    m.enable(F_TIPOPAG, !allo_sconto);
    if (allo_sconto)
      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)
{ 
// 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 (k == K_SPACE)
  {
    aggiungi();
    TSheet_field& sf_riba = (TSheet_field&)f.mask().field(F_SHEET_RIBA);
    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_sel_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 (k == K_TAB && 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); 
    real res = m2.get_real(F_IMPSEL); 
    if (res > ZERO)
    { // se i due importi sono diversi da zero  
      TString16 val = m->get(F_CODVAL);
      int items = sf.items();                       
      // cerca se esiste un effetto con importo uguale a quello
      // da caricare
      int i;
      for (i = 0; i < items; i++)
      {
        TToken_string& row = sf.row(i);
        TString16 codval = row.get(sf.cid2index(F_VALUTA));
        codval.trim();
        // se la valuta non appare o � lire faccio in modo che vengano
        // presi gli effetti con valuta inesistente 
        const bool valuta = ::is_true_value(codval);
        const real imp(row.get(sf.cid2index(valuta ? F_IMPORTOVAL : F_IMPORTO)));        
        if (imp == res && ::same_values(codval, val)) 
        {  
          row.add('X', 0);
          res = ZERO;
        } 
      }
      // se non esiste un effetto con importo uguale a quello
      // da caricare carico l'importo sommando pi� effetti    
      for (i = 0; res > ZERO && i < items; i++)
      {
        TToken_string& row = sf.row(i);
        TString16 codval = row.get(sf.cid2index(F_VALUTA));
        codval.trim();
        const bool valuta = ::is_true_value(codval) ;
        const real imp(row.get(sf.cid2index(valuta ? F_IMPORTOVAL : F_IMPORTO)));        
        // 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 (::same_values(codval, val) && imp <= res)
        {  
          row.add('X',0);
          res -= imp;
        } 
      } 
      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)
{  
  if (k == K_ENTER)
  { 
    TMask * msk = app()._msk;
    TSheet_field & sf_riba = (TSheet_field&)msk->field(F_SHEET_RIBA);    
    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();  
    for (int i = 0; i < items; i++)
    {
       TToken_string& row = sf.row(i);   
       if (*row.get(0) == 'X')  // selected
       { 
         row.add(" ", 0);
         sf_riba.row(-1) = row;
       }  
    }                  
  }   
  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::data_handler(TMask_field& f, KEY k)
{
  if (f.to_check(k) && k == K_TAB)
  { 
    // Carica prima tutte le ri.ba e poi toglie quelle che non servono in base alla selzione
    int tipopag = app()._msk->get_int(F_TIPOPAG); 
    if (tipopag != 0)
    {
      TWait_cursor hourglass;
      carica_riba(tipopag, FALSE);     
    }

    TMask& m = f.mask();
    bool deleted = FALSE;    
    TDate datad = m.get_date(F_DADATA);
    TDate dataa = m.get_date(F_ADATA);
    
    if (!datad.ok())
      datad = botime;
    if (!dataa.ok())
      dataa = eotime;
    TDate data_sh;
    TSheet_field&  sf = (TSheet_field&)m.field(F_SHEET);
    TString_array& sa = sf.rows_array(); 
    const int field = m.get(F_TIPORD) == "F" ? 6 : 2;
    // tolgo dallo sheet gli effetti che hanno la data non compresa nel range
    for (int i = sa.items()-1; i >=0 ; i--)
    {
      TToken_string& row = sa.row(i);
      data_sh = (TDate)row.get(field);
      if (data_sh > dataa || data_sh < datad)
         sa.remove(i); 
    }
    sa.pack();
    sf.force_update();
  }
  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)
{
  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)
    return 0;
  else
   return (data1 > data2) ? +1 : -1; 
}

// Handler per gestire l'ordinamento per data degli effetti presenti 
// nello sheet, nella maschera di scelta delle riba (ef0300c) 
void TVariazione_distinte::ord_data()
{ 
  TWait_cursor hourglass;
  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();
  // faccio l'ordinamento degli elementi dell'array
  effetti.sort(confronta_data);
  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)
{ 
  TToken_string* s1 = (TToken_string*) *o1; 
  TToken_string* s2 = (TToken_string*) *o2;
  TDate data1 = s1->get(6);
  TDate data2 = s2->get(6);

  // ordinamento sulla data fattura  
  if (data1 == data2)
    return 0;
  else 
    return (data1 > data2) ? +1 : -1;
}
                     
// 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()
{
  TWait_cursor hourglass;
  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();
  effetti.sort(confronta_fatt);// ordino gli elementi dell'array
  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; 
}

bool TVariazione_distinte::uncontabilize_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {
    TMask& m = f.mask();
    const char tipodist = m.get(F_TIPODIST)[0];
    const long numdist = m.get_long(F_NUMBER);
    if (yesno_box(TR("Si desidera annullare la contabilizzazione della distinta %ld?"), numdist))
    {
      TRelation rel(LF_EFFETTI);
      TRectype& rec = rel.curr();
      rec.put(EFF_TIPODIST, tipodist);
      rec.put(EFF_NDIST,numdist);
      TCursor cur(&rel, "", 4, &rec, &rec);
      const TRecnotype items = cur.items();
      cur.freeze();
    
      TAssoc_array movs;
      for (cur = 0; cur.pos() < items; ++cur)
      {
        movs.add(rec.get(EFF_NUMREG));
        rec.zero(EFF_EFFCONT);
        rec.zero(EFF_NUMREG);
        rel.rewrite();
      }
    
      if (movs.items() > 0)
      { 
        TString msg;
        msg = TR("E' necessario cancellare i seguenti movimenti contabili:\n");
        FOR_EACH_ASSOC_OBJECT(movs, hash, key, obj)
          msg << key << ' ';
        warning_box(msg);
      }
      m.stop_run(K_ESC);
    }
  }
  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);
  const int items = sf.items();         
  real impdist;  
  const TString16 codval = m->get(F_CODVAL);
  const bool valuta = ::is_true_value(codval);
  
  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    

    if (row.get_char(0) != 'X') // valido (not to delete)
    {
      const real imp = row.get(sf.cid2index(valuta ? F_IMPORTOVAL : F_IMPORTO));
      impdist += imp;                                                           
    }
  }
  m->set(F_TOTIMP, impdist);
}

// Notify per il calcolo dei totali relativi alla selezione effetti 
bool TVariazione_distinte::dist_check_handler(TMask_field& f, KEY key)
{            
  if (key == K_SPACE) 
  {
    TSheet_field& s = app().righe_sheet();
    TToken_string& row = s.row(s.selected());
    const bool checked = f.get().not_empty();
    row.add(checked ? "X" : "", 0);
    app().calcola_totale();
  }
  return TRUE;
}
  

// 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;                   
  TSheet_field& sf = m2.sfield(F_SHEET);
  const bool valuta = ::is_true_value(m2.get(F_CODVALS));
  const int imp_col = sf.cid2index(valuta ? F_IMPORTOVAL : F_IMPORTO); // Colonna con importo
  real impsel;                  
  for (int i = 0; i < sf.items(); i++)
  {
     TToken_string& row = sf.row(i);     
     // se l'effetto � selezionato aggiungo il suo importo al totale importo selezionato     
     if (row.get_char(0) == 'X')
     {
       const real imp = row.get(imp_col);
       impsel += imp;
     }
  }
  m2.set(F_IMPSEL, impsel);

  const real imp_pres = app()._msk->get_real(F_TOTIMP);
  m2.set(F_TOTIMPDIST, real(imp_pres+impsel));  
}  

// Notify per il calcolo dei totali relativi alla selezione effetti 
// per la distinta nella maschera di scelta delle riba (ef0300c)
bool TVariazione_distinte::check_handler(TMask_field& f, KEY key)
{            
  if (key == K_SPACE) 
  {
    TSheet_field& s = app().righe_sel_sheet();
    TToken_string& row = s.row(s.selected());
    const bool checked = f.get().not_empty();
    row.add(checked ? "X" : "", 0);
    app().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);
  if (tipopag != 0)
  {
    TWait_cursor hourglass;
    carica_riba(tipopag);
  }
  m2->set(F_CODVALS, m->get(F_CODVAL));
  calcola();
  m2->run(); 
  calcola_totale();
}

// 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 (key == K_INS) 
  {
    aggiungi(); 
    s.force_update(); 
    return FALSE;
  }
  return TRUE;
}

bool TVariazione_distinte::imp_notify(TSheet_field& s, int r, KEY key)
{
  if (key == K_DEL || key == K_INS)
    return false;
  return true;
}

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