#include <defmask.h>
#include <recarray.h>
#include <recset.h>
#include <relapp.h>
#include <sheet.h>
#include <utility.h>

#include "ce0.h"
#include "ce2101.h"
#include "celib.h"

#include "ce0500a.h"
#include "../cg/cglib01.h"

#include <multirel.h>
#include "cespi.h"
#include "salce.h"
#include "ammce.h"

//-------------------------------------------------------------------
//  MASCHERA VIRTUALE
//-------------------------------------------------------------------
class TBasic_cespi_mask : public TAutomask
{
protected:
  int create_fields(int x, int y, short key_id, const int page);
  TBasic_cespi_mask(const char* name) : TAutomask(name) {}

};

int TBasic_cespi_mask::create_fields(int x, int y, short key_id, const int page)
{
  TRectype rec_cespi(LF_CESPI);
  //cicla sui campi user (se ci sono) nel ditta.ini facendoli apparire sulla pagine Personalizz.
  TConfig config (CONFIG_DITTA, "ce");

  int i = 0;

  int maxprompt = 0;
  for (i = 0; config.exist("USER", i); i++)
  {
    TToken_string riga = config.get("USER", NULL, i);
    const TString80 prompt = riga.get(1);
    const int len = prompt.len();
    if (len > maxprompt)
      maxprompt = len;
  }
  maxprompt++;

  for (i = 0; config.exist("USER", i); i++)
  {
    TToken_string riga = config.get("USER", NULL, i);

    const bool search = riga.get_char(3) == 'X';
    //se e' in pagina di ricerca ed il campo non e' di ricerca lo salta!
    if (page == 0 && !search)
      continue;
    //tutto il resto lo fa comunque,settandondolo nella page corretta
    const short kid = key_id+i; //numero del campo come definito nel .h della maschera
    const TString16 name = riga.get(0); //nome campo
    TString80 prompt = riga.get(1); prompt.left_just(maxprompt);  //prompt sulla maschera    
    const TString80 picture = riga.get(2);  //picture del campo(se c'e')
    //se la lunghezza del campo non e' definita nella picture la prende dal tracciato
    const int len = picture.blank() ? rec_cespi.length(name) : picture.len();

    //chiede al record di che tipo e' il campo chiamato name...
    const TFieldtypes tipo_campo = rec_cespi.type(name);
    //..quanto e' lungo...(maniaca!)
    const int length_campo = rec_cespi.length(name);
    //...e quanti decimali ha nel caso sia un real
    int ndec_campo = 0;
    if (tipo_campo == _realfld)
      ndec_campo = rec_cespi.ndec(name);

    const bool btn = search && page == 0;

    //crea finalmente i nuovi campi sulla pagina 1 (Personalizzazioni)
    switch(tipo_campo)
    {
    case _wordfld:      add_number (kid, page, prompt, x, i+y, len, btn ? "BU" : "U");  break;

    case _intfld :
    case _longfld:      add_number (kid, page, prompt, x, i+y, len, btn ? "B" : "");  break;

    case _intzerofld:
    case _longzerofld:  add_number (kid, page, prompt, x, i+y, len, btn ? "BZ" : "Z");  break;

    case _realfld:      add_number (kid, page, prompt, x, i+y, len, "", ndec_campo);  break;

    case _datefld:      add_date (kid, page, prompt, x, i+y, btn ? "B" : "");  break;

    case _memofld:      add_zoom(kid, page, prompt, x, i+y, 50);  break;
      
    default      :      add_string (kid, page, prompt, x, i+y, len, btn ? "BU" : "");  break;
    }

    //deve poter salvare il contenuto nei campi!! (e' il FIELD delle maschere)
    TEdit_field& efld = efield(kid);
    efld.set_field(name); //la set_field lo fa
  }
  //deve accendere gli handler di questa maschera perche' funzionino
  set_handlers();
  
  return i;
}

//-------------------------------------------------------------------
//  MASCHERA RICERCA (ce0500a)
//-------------------------------------------------------------------
class TQuery_mask : public TBasic_cespi_mask
{      
  int _staat;
 
protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
  void on_search_event(TOperable_field& o);
  void on_user_search(TOperable_field& o);
  virtual void on_firm_change();

  int calcola_stato_attivita();
  bool cespite_ok() const;
  void set_cespi_filter();
  void crea_filtro(TString& filter) const;
 
public:
   int stato_attivita() const { return _staat; }

  TQuery_mask();
};

void TQuery_mask::on_user_search(TOperable_field& o)
{
  TToken_string order, header;
  const TFieldref* campo = o.field();
  const TString nome_campo = campo->name();
  //ordinare per campo personalizzato/idcespite/descrizione
  order.add(nome_campo);
  TString prompt = o.prompt();
  prompt << "@" << o.size();  //lunghezza del prompt del campo
  header.add(prompt);
  order.add(CESPI_IDCESPITE); header.add(TR("Cespite@10"));
  order.add(CESPI_DESC);      header.add(FR("Descrizione cespite@50"));

  TRelation rel(LF_CESPI);

  TSorted_cursor cur(&rel, order);
  TToken_string siblings;
  TBrowse_sheet sht(&cur, order, TR("Cespiti"), header, 0, (TEdit_field&)o, siblings);
  if (sht.run() == K_ENTER)
  { 
    TToken_string& row = sht.row();
    set(F_IDCESPITE, row.get(1), true);
    stop_run(K_AUTO_ENTER);
  }
}

//metodo per creare il filtro in base ai parametri maschera
void TQuery_mask::crea_filtro(TString& filter) const
{
  if (get(F_SELECT) == "I") // Filtro per impianto
  {
    const TString& imp = get(F_IMPIANTO);
    if (imp.full())
      filter << '(' << CESPI_CODIMP << "=\"" << imp << "\")";
  }
  else // Filtro per attivit�
  {
    filter << "(STR(" << CESPI_CODCGRA << "=" << get_int(F_GRUPPO) << ')';
    TString4 specie = get(F_SPECIE); specie.rtrim(); // Toglie spazi FINALI
    filter << "&&(" << CESPI_CODSPA << "=\"" << specie << "\"))";
  }

  const int cat = get_int(F_CATEGORIA);
  if (cat > 0)
  {
    if (filter.full())
      filter << "&&";
    filter << "(STR(CODCAT==" << cat << "))";
  }
}

void TQuery_mask::on_search_event(TOperable_field& o)
{
  TToken_string order, fields, header;
  if (o.dlg() >= F_SEARCH3)
  {
    order.add(CESPI_STABILIM); header.add(HR("Stabilimento"));
    order.add(CESPI_REPARTO); header.add(HR("Reparto@10"));
  }
  if (o.dlg() >= F_SEARCH2) 
  {
    order.add(CESPI_CODIMP); header.add(HR("Impianto@10"));
    order.add("CIM->S0"); header.add(HR("Descrizione impianto@40"));
  }
  if (o.dlg() >= F_SEARCH1)
  {
    order.add(CESPI_CODCAT); header.add(HR("Cat"));
    order.add(CESPI_DTCOMP); header.add(HR("Data Acq.@10"));
  }

  order.add(CESPI_IDCESPITE); header.add(HR("Codice@10"));
  
  fields = order;
  fields.add(CESPI_DESC); header.add(HR("Descrizione cespite@50"));
  
  TRelation rel(LF_CESPI);

  rel.add("CIM","CODTAB==CODIMP");
  
  TString filter;
  crea_filtro(filter);	
  
  TSorted_cursor cur(&rel, order, filter);
	TCursor_sheet sht(&cur, fields, TR("Cespiti"), header, 0, 1);

  if (sht.run() == K_ENTER)
  { 
    TToken_string& row = sht.row();
    const int cod_pos = row.items()-2;
    set(F_IDCESPITE, row.get(cod_pos), true);
    stop_run(K_AUTO_ENTER);
  }
}

int TQuery_mask::calcola_stato_attivita()
{
  const int ese = get_int(F_ESERCIZIO);
  const int gru = get_int(F_GRUPPO);
  const char* spe = get(F_SPECIE);

  TString16 str;  
  str.format("%04d%02d%-4s", ese, gru, spe);

  const TRectype& curr_ccb = cache().get("CCB", str);
  if (curr_ccb.get_bool("B1")) // Bollato stampato
    _staat = 3;
  else
  {  
    TEsercizi_contabili esc;
    str.format("%04d%02d%-4s", esc.pred(ese), gru, spe);
    const TRectype& prev_ccb = cache().get("CCB", str);
    _staat = prev_ccb.get_bool("B1") ? 2 : 1;
  }
  
  TDitta_cespiti& dc = ditta_cespiti();
  dc.set_attivita(ese, gru, spe);
  
  return _staat;
}

bool TQuery_mask::cespite_ok() const
{
  const TRectype & cespi = cache().get(LF_CESPI, get(F_IDCESPITE));
  const bool ok = !cespi.empty();
  return ok;
}

void TQuery_mask::set_cespi_filter()
{ 
  TString filter;
  crea_filtro(filter);

  efield(F_IDCESPITE).browse()->set_filter(filter);
  efield(F_DESC).browse()->set_filter(filter);
}

bool TQuery_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  switch (o.dlg())
  {         
  case F_ESERCIZIO:
    if (e == fe_init || e == fe_modify)
    { 
      int esercizio = get_int(F_ESERCIZIO);
      TString4 gruppo, specie;
      TDitta_cespiti& dc = ditta_cespiti();
      dc.set_attivita(esercizio, atoi(gruppo), specie);
      dc.get_attivita(esercizio, gruppo, specie);
      if (gruppo.full())
      {
        set(F_GRUPPO, gruppo);
        set(F_SPECIE, specie.rtrim(), 0x2); // Forza decodifica attivita'
      }
    }   //niente break!!!!! � fatto apposta per far scattare i successivi controlli su gruppo e specie
  case F_GRUPPO:
  case F_SPECIE:
    if (e == fe_init || e == fe_modify)
    { 
      const bool can_create = calcola_stato_attivita() != 3; // Bollato non stampato
      enable(DLG_NEWREC, can_create && !field(F_SPECIE).empty() && !field(F_CATEGORIA).empty());
      enable(DLG_DELREC, can_create);
      set_cespi_filter();
    }
    break;
  case F_SELECT:
  case F_IMPIANTO:  
    if (e == fe_modify)
      set_cespi_filter();
    break;
  case F_SEARCH1:
  case F_SEARCH2:
  case F_SEARCH3:
    if (e == fe_button)
      on_search_event(o);
    break;  
  case F_CATEGORIA:
  case F_DESC_CAT:
    {
      TDitta_cespiti& dc = ditta_cespiti();
      bool ok = dc.on_category_event(o, e, jolly);
      if (ok)
      { 
        if (e == fe_modify && !o.empty() && stato_attivita() == 2)
        {
          const TRectype& cac = dc.categoria(0, NULL, get_int(F_CATEGORIA));
          const int fine_validita = cac.get_date("D1").year();
          if (fine_validita > 0 && fine_validita < get_int(F_ESERCIZIO))
            return error_box(FR("Categoria scaduta nell'esercizio %d"), fine_validita);
        }
        if (e == fe_init || e == fe_modify || e == fe_button)
        {
          const bool bollati = stato_attivita() == 3;
          enable(DLG_NEWREC, !bollati && !o.empty() && !field(F_SPECIE).empty());
        }
        if (e == fe_close && o.empty() && !field(F_IDCESPITE).empty() && !cespite_ok())
          return error_box(TR("� necessario specificare la categoria del nuovo cespite"));
        set_cespi_filter();
      }
    }
    break;
  case F_IDCESPITE:
    if (e == fe_close)  
    { 
      if (stato_attivita() == 3 && !cespite_ok())
        return error_box(TR("E' stato stampato il bollato dell'anno:\nnon sono permessi inserimenti"));
    }
    if (e == fe_modify && !o.empty() && cespite_ok())
    {
			TString key;

			key =  get(F_IDCESPITE);
			key << '|' << get(F_ESERCIZIO) << "|1";

      const TRectype & salce = cache().get(LF_SALCE, key);
      if (salce.empty())
        return yesno_box(TR("Non esistono saldi per l'anno selezionato:\nSi desidera continuare ugualmente?"));
    }
    break;
  case F_USER:
  case F_USER+1:
  case F_USER+2:
  case F_USER+3:
  case F_USER+4:
  case F_USER+5:
    if (e == fe_button)
      on_user_search(o);
    break;
  default:
    break;
  }  
  return true;
}

void TQuery_mask::on_firm_change()
{
  TAutomask::on_firm_change();
  ditta_cespiti().init_mask(*this);
}

TQuery_mask::TQuery_mask() : TBasic_cespi_mask("ce0500a") 
{
  first_focus(F_IDCESPITE);
  create_fields(2, 13, F_USER, 0);
}


//-------------------------------------------------------------------
//  MASCHERA DI MODIFICA (ca0500b)
//-------------------------------------------------------------------
class TEdit_mask : public TBasic_cespi_mask
{ 
  TTipo_cespite _tipo;
  int _staat;

protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
  virtual bool on_key(KEY k);
  
  bool one_compiled(const short* f) const;
  TCurrency sum_fields(const short* f) const;
  bool test_ammissibilita_dati();
  bool test_ammissibilita_saldi();
  bool test_ammissibilita_fondi();

public:
  void set_stato_attivita(int sa) { _staat = sa; }
  int stato_attivita() const { return _staat; }

  void set_tipo_cespite(TTipo_cespite tc) { _tipo = tc; }
  TTipo_cespite tipo_cespite() const { return _tipo; }

  void protect_page(int page, TToken_string& enabling);

  TEdit_mask();
};

bool TEdit_mask::one_compiled(const short* f) const
{
	int i;
	
  for (i = 0; f[i]; i++)
  {
    if (!field(f[i]).empty())
      break;
  }
  return f[i] > 0;
}

TCurrency TEdit_mask::sum_fields(const short* f) const
{
  TCurrency sum, val;
  for (int i = 0; f[i] != 0; i++)
  {
    get_currency(abs(f[i]), val);
    if (f[i] > 0)
      sum += val;
    else
      sum -= val;  
  }
  return sum;
}

bool TEdit_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
  bool ok = true;
  switch (o.dlg())
  { 
  case F_CATEGORIA:
    if (e == fe_init)
    {
      TDitta_cespiti& dc = ditta_cespiti();
      dc.on_category_event(o, e, jolly);
    }
    break;
  case F_DTCOMP:
    if (e == fe_init && o.empty())
    {
      TConfig ini (CONFIG_DITTA, "ce");
      TString16 datamov = ini.get("DataMovimento");
      if (datamov.empty())
        datamov = TDate(TODAY).string();
      o.set(datamov);  
    }

    if (e == fe_modify || e == fe_close)
    {
      const TDate dtcomp(o.get());
      TDitta_cespiti& dc = ditta_cespiti();
      TDate iniz, fine; 
      dc.esercizio_corrente(iniz, fine);
      
      if (stato_attivita() == 2)
      {
        // if (m.dtcomp < iniz)  // Errore 0000820: test inutile
        //   return error_box(TR("La data appartiene ad un esercizio gi� stampato su bollato"));
        const TRectype& cac = dc.categoria(0, NULL, get_int(F_CATEGORIA));
        iniz = cac.get("D0");
        if (iniz.ok() && dtcomp < iniz)
          return error_box(TR("La data � precedente all'inizio della validit� della categoria"));
        fine = cac.get("D1");
        if (fine.ok() && dtcomp > fine)
          return error_box(TR("La data � succesiva alla fine della validit� della categoria"));
      }
      if (dc.esercizio_costituzione() && dtcomp < iniz)
        return error_box(TR("Non � possibile specificare una data antecedente all'esercizio di costituzione"));
      
      if (tipo_cespite() != tc_materiale && dtcomp.year() >= dc.anno_tuir())  
      {
        if (field(F_DTFUNZ).empty())
          set(F_DTFUNZ, o.get());
      }
    }
    break;
  case F_DTFUNZ:
    if (e == fe_modify || e == fe_close)
    {
      const TDate dtfunz(o.get());      
      if (dtfunz.ok())
      {
        const TDate dtcomp(field(F_DTCOMP).get());
        if (dtfunz < dtcomp)
          return error_box(FR("La data di entrata in funzione deve essere successiva a quella di aquisizione"));
        if (!dtcomp.ok())                                                                    
          return error_box(TR("La data di entrata in funzione non puo' essere inserita senza specificare quella di aquisizione"));      
        if (stato_attivita() == 2)  
        {
          const TDate iniz(get(F_INIZIO_ES)); 
          if (dtfunz < iniz)
            return error_box(TR("La data di entrata in funzione deve essere successiva a quella di inizio esercizio"));
        }

        TDitta_cespiti& dc = ditta_cespiti();
        if (_tipo != tc_materiale && dtfunz != dtcomp)  
        {
          if (dtcomp.year() >= dc.anno_tuir())
            return error_box(TR("In base alla normativa del TUIR, le date di acquisizione e di entrata in funzione devono coincidere"));
        }
        const TRectype& cac = dc.categoria(0, NULL, get_int(F_CATEGORIA));
        const TDate iniz = cac.get_date("D0");
        if (iniz.ok() && dtfunz < iniz)
          return error_box(TR("La data � precedente all'inizio validit� della categoria"));
        const TDate fine = cac.get_date("D1");
        if (fine.ok() && dtfunz > fine)
          return error_box(TR("La data � successiva alla fine validit� della categoria"));
        if (dtfunz.year() >= dc.anno_tuir())
          set(F_TUIR, "X");

        else
          reset(F_TUIR);

      }
    }
    break;
  case F_QUADRATURA:
    if (e == fe_button)
    {
      set(F_NORMALE2, get(F_NORMALE));
      set(F_NORMALE3, get(F_NORMALE));
      set(F_ACCELERATO2, get(F_ACCELERATO));
      set(F_ACCELERATO3, get(F_ACCELERATO));
      set(F_ANTICIPATO2, get(F_ANTICIPATO));
      set(F_ANTICIPATO3, get(F_ANTICIPATO));
    }
    break;
  case F_VNONAMM:
    if (e == fe_modify || e == fe_close)
    {
      if (o.empty() && get_bool(F_LEASING))
        return error_box(TR("Indicare il valore del riscatto per beni in leasing"));
      test_ammissibilita_saldi();
    }
    break;
  case F_PLUSREIN:
    if ((e == fe_modify || e == fe_close) && !o.empty())
    {
      TCurrency costo; get_currency(F_COSTO, costo);
      TCurrency noamm; get_currency(F_VNONAMM, noamm);
      TCurrency plusr; get_currency(F_PLUSREIN, plusr);
      const TCurrency minim = costo - noamm;
      if (plusr > minim)
        return error_box(FR("La plusvalenza reinvestita non puo' superare %s"), minim.string(true));
    }
    break;  
  case F_ELEMENTI:
    if ((e == fe_modify || e == fe_close) && o.empty())
    {
      const TDate dtcomp(field(F_DTCOMP).get());
      const TDate dtiniz(field(F_INIZIO_ES).get());
      if (dtcomp.ok() && dtcomp < dtiniz)
        return error_box(TR("E' necessario specificare il numero di elementi per cespiti acquisiti negli esercizi precedenti"));
      const short fields[] = { F_COSTO, F_VNONAMM, F_RIV75, F_RIV83, F_RIV90, F_RIV91, F_RIVGF, F_RIVGC, 0 };
      if (one_compiled(fields))
        return error_box(TR("E' necessario inserire il numero degli elementi"));
    }
    break;
  case F_RIV90:  
  case F_RIV91:  
    if ((e == fe_init || e == fe_modify) && o.active())
    {
      TEdit_field& anni = efield(o.dlg()+1);
      if (o.empty())
      {
        anni.reset();
        anni.disable();
      }
      else
        anni.enable();
    }
    break;
  case F_ANNIAMM:
    if (e == fe_init || e == fe_modify)
      enable_page(3, !o.empty());
    break;
  case F_NORMALE:
    if (e == fe_close)
    { 
      const short fv[] = { F_COSTO, -F_VNONAMM, F_RIV75, F_RIV83, F_RIV90, F_RIV91, F_RIVGF, 0 };
      const short fa[] = { F_NORMALE, F_ACCELERATO, F_ANTICIPATO, F_QPERSE, F_FPRIVATO, F_QPERSEPRIV, 0 };
      const TCurrency val_amm = sum_fields(fv);
      const TCurrency fon_amm = sum_fields(fa);
      if (fon_amm > val_amm)
      {
        TString msg;
        msg << TR("Il fondo ammortamento fiscale (") << fon_amm.string(true) << ')';
        msg << TR("non puo' superare il valore da ammortizzare (") << val_amm.string(true) << ')';
        return error_box(msg);
      }
    }
    break;  
  case F_FPRIVATO:
    if (e == fe_close)
    {
      if (get_int(F_USOPROM) > 1 && !field(F_ANNIAMM).empty())
      {
        if (field(F_FPRIVATO).empty() && field(F_QPERSEPRIV).empty())
          return error_box(TR("E' necessario inserire un fondo di ammortamento privato o delle quote perse private"));
      }
    }
    break;
  case F_NORMALE2:
    if (e == fe_close)
    { 
      const short fv[] = { F_COSTO, F_RIV75, F_RIV83, F_RIV90, F_RIV91, F_RIVGC, 0 };
      const short fa[] = { F_NORMALE2, F_ACCELERATO2, F_ANTICIPATO2, 0 };
      const TCurrency val_amm = sum_fields(fv);
      const TCurrency fon_amm = sum_fields(fa);
      if (fon_amm > val_amm)
      {
        TString msg;
        msg << TR("Il fondo ammortamento civilistico (") << fon_amm.string(true) << ')';
        msg << TR("non puo' superare il valore da ammortizzare (") << val_amm.string(true) << ')';
        return error_box(msg);
      }
    }
    break;
	case F_VEIDIP:
	case F_VEICOLO:
		//testa se e' un veicolo promiscuo in uso a dipendente
		if (e == fe_init || e == fe_modify)
		{
			const bool veicolodipendente = get_bool(F_VEIDIP);
			//navi,aerei,astronavi etc. non possono godere del fringe benefit
			const int tipoveicolo = get_int(F_VEICOLO);
			enable(F_FRINGEBEN, veicolodipendente && tipoveicolo > 1 && tipoveicolo < 5);
		}
		break;
	case F_MATRICOLE:
		if (e == se_notify_modify)
		{
			TSheet_field& sf = sfield(F_MATRICOLE);
			const TString80 matricola = sf.cell(jolly, 0);
			if (matricola.blank())
				return error_box(TR("Matricola nulla!"));

			TISAM_recordset multirel("USE MULTIREL KEY 2\nSELECT FIRST!=#IDCESPITE\nFROM COD=CEMAT SECOND=#MATRICOLA\nTO COD=CEMAT SECOND=#MATRICOLA");
			multirel.set_var("#MATRICOLA", TVariant(matricola));
			multirel.set_var("#IDCESPITE", TVariant(get(F_IDCESPITE)));

			const TRecnotype items = multirel.items();
			if (items > 0)
			{
				TString msg;
				msg << TR("Matricola gia' utilizzata nel cespite ") << multirel.get(MULTI_FIRST);
				return error_box(msg);
			}

			FOR_EACH_SHEET_ROW(sf, i, row) if(i != jolly)
			{
				if (matricola == row->get(0))
				{
					TString msg;
					msg << TR("Matricola gia' utilizzata alla riga ") << (i+1);
					return error_box(msg);
				}
			}
		}
		break;
  default: 
    break;
  }
  return ok;
}

// Disabilita tutti i campi della pagina "page" (1 based) tranne quelli nella lista "enabling"
void TEdit_mask::protect_page(int page, TToken_string& enabling)
{               
  // Determina l'id del primo campo della pagina
  short cid = 0;
  switch (page)
  {
  case  2: cid = F_ELEMENTI; break;    // Pagina 2 (Saldi)
  case  3: cid = F_NORMALE; break;     // Pagina 3 (Fondi)
  default: cid = F_IDCESPITE; break;   // Pagina 0 (Cespite)
  } 
  // Determina l'handle della pagina selezionata
  WINDOW parent = field(cid).parent();

  for (int f = fields()-1; f >= 0; f--)
  {
    TMask_field& c = fld(f);
    if (c.parent() == parent) // Il campo appartiene alla pagina voluta?
    {
      const short id = c.dlg();
      if (id > 100 && id < 1000 && c.is_operable() && c.enabled_default())
      {
        const bool on = enabling.empty() || enabling.get_pos(c.dlg()) >= 0;
        c.enable(on);
        if (cid == id) // Ho raggiunto il capo pagina?
          break;
      }
    }
  }
}

bool TEdit_mask::test_ammissibilita_dati()
{
  const char* msg = insert_mode() ? TR("Inserimento") : TR("Modifica");
  xvtil_statbar_set(msg, true);
  return false;
}

bool TEdit_mask::test_ammissibilita_saldi()
{
  bool protez = false;
  const char* msg = "";
  switch (_staat)
  {
  case 1:
  case 2:
    {
      const TDate iniz(get(F_INIZIO_ES));
      const TDate dtacq(get(F_DTCOMP));
      const TDate dtfunz(get(F_DTFUNZ));
      if (!dtacq.ok() || !dtfunz.ok())
        protez = true;
      else
        protez = dtacq >= iniz || dtfunz >= iniz;
      if (protez)
        msg = TR("Inserire gli importi nel movimento d'acquisto");
    }
    break;
  case 3: 
    protez = true; 
    msg = TR("Bollato stampato: non sono ammesse modifiche");
    break;
  default: 
    break;
  }

  TToken_string enabling;
  if (protez)   
    enabling = "883";  // Disabilita tutto!
  protect_page(2, enabling);
  
  if (*msg)
    beep(1);
  else
    msg = insert_mode() ? TR("Inserimento") : TR("Modifica");
  xvtil_statbar_set(msg, true);
                                 
  return protez;
}

bool TEdit_mask::test_ammissibilita_fondi()
{
  bool protez = false;
  const char* msg = "";
  switch (_staat)
  {
  case 1:
  case 2:
    {
      const TDate dtacq(get(F_DTCOMP));
      const TDate dtfunz(get(F_DTFUNZ));
      if (!dtacq.ok() || !dtfunz.ok())
        protez = true;
      else
      {  
        const TDate iniz(get(F_INIZIO_ES));
        protez = dtacq >= iniz;
      }    
      if (protez)
        msg = TR("Inserire gli importi nel movimento d'acquisto");
    }
    break;
  case 3: 
    protez = true; 
    msg = TR("Bollato stampato: non sono ammesse modifiche");
    break;
  default: protez = false; break;
  }

  TToken_string enabling;
  if (protez)   
    enabling = "883";  // Disabilita tutto!
  protect_page(3, enabling);

  if (!protez)
  {
    const TDate dtfunz(get(F_DTFUNZ));
    const TDate iniz(get(F_INIZIO_ES));
    bool prot9 = false;
    if (!dtfunz.ok() || dtfunz >= iniz)
    {
      msg = TR("Cespite non ancora entrato in funzione a inizio esercizio");
      prot9 = true;
    }
    else
    {
      const TRectype& cac = ditta_cespiti().categoria(0, NULL, get_int(F_CATEGORIA));
      if (cac.get_bool("B0"))
      {
        msg = TR("Categoria non ammortizzabile");
        prot9 = true;
      }
    }
    enable(-9, !prot9);
		//testa se e' un veicolo promiscuo in uso a dipendente
		if (!prot9)
		{
			const bool veicolodipendente = get_bool(F_VEIDIP);
			//navi,aerei,astronavi etc. non possono godere del fringe benefit
			const int tipoveicolo = get_int(F_VEICOLO);
			enable(F_FRINGEBEN, veicolodipendente && tipoveicolo > 1 && tipoveicolo < 5);
		}
  }
  if (*msg)
    beep(1);
  else
    msg = insert_mode() ? TR("Inserimento") : TR("Modifica");
  xvtil_statbar_set(msg, true);

  return protez;
}

bool TEdit_mask::on_key(KEY k)
{   
  // Try to predict next page!
  const int old_page = curr_page()+1;
  int new_page = old_page;
  switch (k)
  {
  case K_CTRL+K_F1: new_page = 1; break;
  case K_CTRL+K_F2: new_page = 2; break;
  case K_CTRL+K_F3: new_page = 3; break;
  case K_CTRL+K_F4: new_page = 4; break;
  case K_PREV     : new_page--; break;
  case K_NEXT     : new_page++; break;
  default: break;
  }
  
  // If page will change ...
  if (old_page != new_page) switch(new_page)
  {
  case  1: test_ammissibilita_dati(); break;
  case  3: test_ammissibilita_saldi(); break;
  case  4: test_ammissibilita_fondi(); break;
  default: break;
  }

  return TAutomask::on_key(k);
}

TEdit_mask::TEdit_mask() : TBasic_cespi_mask("ce0500b")
{
  create_fields(1, 13, F_USER, 1);
}
//--------------------------------------------------------------
//  APPLICAZIONE
//--------------------------------------------------------------
class TAnacespi : public TRelation_application
{
  TRelation* _cespiti;
  int _rel_year;
  TAssoc_array _matricole_iniziali;

  TQuery_mask* _qmask;
  TEdit_mask* _emask;
  
private:  
  void init_mask(TMask& m);
  bool kill_cespite(const TString& idcespite, int lfile, int key = 1);

protected:
  // @cmember Inizializzazione dei dati dell'utente
  virtual bool user_create();
  // @cmember Distruzione dei dati dell'utente
  virtual bool user_destroy();
  virtual bool changing_mask(int mode);
  // @cmember Richiede la maschera da usare
  virtual TMask* get_mask(int mode);
  // @cmember Ritorna la relazione da modificare
  virtual TRelation* get_relation() const;

  virtual const char* get_next_key();
  virtual bool protected_record(TRectype& rec);
  virtual void init_query_mode(TMask& m);
  virtual void init_insert_mode(TMask& m);
  virtual void init_modify_mode(TMask& m);
  
  virtual void ini2mask(TConfig& ini, TMask& m, bool query);

	void leggi_matricole(TMask& m);
	void aggiorna_matricole(const TMask& m);
  virtual int read(TMask& m);
	virtual int rewrite(const TMask& m);
  virtual int write(const TMask& m);
  virtual bool remove();
};

bool TAnacespi::changing_mask(int)
{
  return true;
}

TMask* TAnacespi::get_mask(int mode)
{
  return mode == MODE_QUERY ? (TMask*)_qmask : (TMask*)_emask;
}

// get_relation pi� complessa della storia di campo
TRelation* TAnacespi::get_relation() const
{                    
  const int year = _qmask->get_int(F_ESERCIZIO);
  TRelation*& csp = ((TAnacespi*)this)->_cespiti;
  if (year != _rel_year && csp != NULL)
  {
    delete csp;
    csp = NULL;
  }
  if (csp == NULL)
  { 
    // Crea nuova relazione su cespi
    csp = new TRelation(LF_CESPI);
    ((TAnacespi*)this)->_rel_year = year; // Memorizza anno utilizzato
    
    // Collega salce
    TString80 expr1;
    expr1 << SALCE_IDCESPITE << "==" << CESPI_IDCESPITE;
    expr1 << '|' << SALCE_CODES << "==" << year;
    expr1 << '|' << SALCE_TPSALDO << "==1";
    csp->add(LF_SALCE, expr1);    
    
    // Collega i tre tipi di ammce
    for (int a = 1; a <= 3; a++) 
    {
      TString80 expr2 = expr1;
      expr2 << '|' << AMMCE_TPAMM << "==" << a;
      csp->add(LF_AMMCE, expr2, 1, 0, a-1); 
    }
    
    // Attiva il salvataggio anche di salce e ammce
    csp->write_enable(); 
  }
  
  return _cespiti;
}

void TAnacespi::init_query_mode(TMask& m)
{
  ditta_cespiti().init_mask(m);
  set_search_field(F_IDCESPITE);
}

bool TAnacespi::protected_record(TRectype& rec)
{
  const TDate dtalien = rec.get_date(CESPI_DTALIEN);
  return dtalien.ok();
}

void TAnacespi::init_mask(TMask& m)
{
  TDitta_cespiti& dc = ditta_cespiti();
  dc.init_mask(m);
  const bool can_edit = !dc.bollato_stampato() && m.field(F_DTALIEN).empty();
  m.enable(DLG_SAVEREC, can_edit);
  m.enable(DLG_DELREC, can_edit && m.edit_mode());
  m.disable(DLG_NEWREC);
  
  _emask->set_stato_attivita(_qmask->stato_attivita());
  
  const TRectype& cac = dc.categoria(0, NULL, _qmask->get_int(F_CATEGORIA));
  const int tc = cac.get_int("I0");
  _emask->set_tipo_cespite(tc==0 ? tc_materiale : (tc==1 ? tc_immateriale : tc_pluriennale));
  
  const bool mat_only = _emask->tipo_cespite() == tc_materiale;
  m.show(F_LEASING, mat_only);
  m.show(F_ANNIRIC, true); // m.show(F_ANNIRIC, mat_only);  // Sempre visibile
  m.show(F_USATO, mat_only);
  m.show(F_AMMPROP, dc.ammortamento_proporzionale());
}

void TAnacespi::init_insert_mode(TMask& m)
{                
  init_mask(m);
  m.set(F_TUIR, "X");
  if (_emask->tipo_cespite() == tc_materiale)
    m.set(F_SPEMAN, 2);
  else
  {
    m.set(F_SPEMAN, 1);
    m.disable(F_SPEMAN);

    TDitta_cespiti& dc = ditta_cespiti();
    const TRectype& cac = dc.categoria(0, NULL, m.get_int(F_CATEGORIA));
    m.set(F_ANNIRIC, cac.get("I3"));
  }
  m.set(F_ESCLPR, _emask->tipo_cespite() != tc_pluriennale ? "X" : "");
  
  // Extra: non richiesti da analisi, ma obbligatori
  m.set(F_VEICOLO, 1); 
  m.set(F_USOPROM, 1);

	//svuota l'assoc_array delle matricole antiche
	_matricole_iniziali.destroy();
}

void TAnacespi::init_modify_mode(TMask& m)
{                
  init_mask(m);
  
  const int staat = _qmask->stato_attivita();
  
  TToken_string enabling;
  if (staat == 2 || staat == 3)
  {
    TDitta_cespiti& dc = ditta_cespiti();
    TDate iniz, fine;
    dc.esercizio_corrente(iniz, fine);
    const TDate dtacq  = m.get(F_DTCOMP);
    const TDate dtfunz = m.get(F_DTFUNZ);

    if (staat == 2)
    {
      if (dtacq < iniz) 
      {
        if (!dtfunz.ok() || dtfunz >= iniz)
          enabling.add(F_DTFUNZ);
        if (_emask->tipo_cespite() == tc_materiale)
        {
          enabling.add(F_USOPROM);
          enabling.add(F_VEIDIP);
          enabling.add(F_VEICOLO);
          enabling.add(F_SPEMAN);
          enabling.add(F_FABBR06);
        }
      }
    } 
    else  // == 3
    {
      if (!dtfunz.ok() || dtfunz >= iniz)
        enabling.add(F_DTFUNZ);
    }
  }
  
  _emask->protect_page(1, enabling);

  if (staat == 2 || staat == 3)
  {
    enabling.cut(0);
    _emask->protect_page(2, enabling);
  }

  if (!m.field(F_DTALIEN).empty())
    xvtil_statbar_set(TR("Cespite alienato: non � possibile apportare modifiche"), true);
}

const char* TAnacespi::get_next_key()
{
  real num = 1;
  TLocalisamfile cespi(LF_CESPI);
  if (cespi.last() == NOERR)
    num = cespi.get_real(CESPI_IDCESPITE) + 1;
  return format("%d|%s", F_IDCESPITE, num.string());
}

void TAnacespi::ini2mask(TConfig& ini, TMask& m, bool query)
{
	TRelation_application::ini2mask(ini, m, query);

  if (query)
	{
		const TString16 defpar = ini.get_paragraph();
		TString tmp;

    tmp = ini.get(CESPI_CODCGR, defpar);
		if (tmp.full())
			m.set(F_GRUPPO, tmp);

    tmp = ini.get(CESPI_CODSP, defpar);
		if (tmp.full())
			m.set(F_SPECIE, tmp);

    tmp = ini.get(CESPI_CODCAT, defpar);
		if (tmp.full())
			m.set(F_CATEGORIA, tmp);
	}
}

void TAnacespi::leggi_matricole(TMask& m)
{
	TSheet_field& sf = m.sfield(F_MATRICOLE);
	sf.destroy();

	//svuota l'assoc_array delle matricole antiche
	_matricole_iniziali.destroy();

	TISAM_recordset cemat("USE MULTIREL\nFROM COD=CEMAT FIRST=#IDCESPITE\nTO COD=CEMAT FIRST=#IDCESPITE");
	cemat.set_var("#IDCESPITE", TVariant(m.get(F_IDCESPITE)));

	for (bool ok = cemat.move_first(); ok; ok = cemat.move_next())
	{
		TToken_string& riga = sf.row(-1);
		riga = cemat.get(MULTI_SECOND).as_string();
		_matricole_iniziali.add(riga);								//aggiorna le matricole iniziali
		riga.add(cemat.get(MULTI_DATA).as_string());
		
	}

	sf.force_update();
}

int TAnacespi::read(TMask& m)
{
  int err = TRelation_application::read(m);

	//gestione matricole
	if (err == NOERR)
		leggi_matricole(m);

  return err;
}

void TAnacespi::aggiorna_matricole(const TMask& m)
{
	//aggiorna le matricole confrontando quelle iniziali con quelle rilevate
	TAssoc_array matricole_attuali;

	TSheet_field& sf = m.sfield(F_MATRICOLE);
	FOR_EACH_SHEET_ROW(sf, i, row)
		matricole_attuali.add(row->get(0));

	TLocalisamfile multirel(LF_MULTIREL);

	FOR_EACH_ASSOC_OBJECT(_matricole_iniziali, h, key, obj)
	{
		if (!matricole_attuali.is_key(key))
		{
			multirel.put(MULTI_COD, "CEMAT");
			multirel.put(MULTI_FIRST, m.get(F_IDCESPITE));
			multirel.put(MULTI_SECOND, key);
			multirel.remove();
		}
	}

	FOR_EACH_SHEET_ROW(sf, j, riga)
	{
		const TString80 matricola = riga->get(0);
		if (matricola.full())
		{
			multirel.put(MULTI_COD, "CEMAT");
			multirel.put(MULTI_FIRST, m.get(F_IDCESPITE));
			multirel.put(MULTI_SECOND, matricola);
			multirel.put(MULTI_DATA, riga->get(1));

			if (_matricole_iniziali.is_key(matricola))
				multirel.rewrite();
			else
				multirel.write();
		}
	}
}

int TAnacespi::rewrite(const TMask& m)
{
  int err = TRelation_application::rewrite(m);

	if (err == NOERR)
		aggiorna_matricole(m);

  return err;
}

int TAnacespi::write(const TMask& m)
{    
  const TDitta_cespiti& dc = ditta_cespiti();
  const TRectype& cac = dc.categoria(0, NULL, m.get_int(F_CATEGORIA));
  TRectype& curr = get_relation()->curr();
  switch (_emask->tipo_cespite())
  {
  case tc_immateriale:
    if (cac.get_int("I1") == 2) // Percentuali
    {
      curr.put(CESPI_PIMM, cac.get("R13")); 
      curr.put(CESPI_VINCOLO, 1);
    }
    else  // Anni
    {
      const int anni = cac.get_int("I3");
      ((TMask&)m).set(F_ANNIRIC, anni); 
      curr.zero(CESPI_PIMM); 
      curr.put(CESPI_ANNIRIC, anni);
      curr.put(CESPI_VINCOLO, 2);
    }
    break;
  case tc_pluriennale:
    {
      const int anni = cac.get_int("I3");
      ((TMask&)m).set(F_ANNIRIC, anni);
      curr.put(CESPI_VINCOLO, cac.get("I2"));
      curr.put(CESPI_PMINP, cac.get("R14"));
      curr.put(CESPI_PMAXP, cac.get("R15"));
      curr.put(CESPI_ANNIRIC, anni);
    }
    break;
  default: 
    {
      TDate dt(m.get(F_DTFUNZ));
      if (!dt.ok())
        dt = m.get_date(F_INIZIO_ES);         
      // % beni mat D.M. 29/10/74 oppure D.M. 31/12/88
      const TString& pmat = cac.get(dt.year() < 1989 ? "R12" : "R11");
      curr.put(CESPI_PMAT, pmat);
    }
    break;
  }

  const int cat = m.get_int(F_CATEGORIA);
  if (cat > 40)
  {
    curr.zero(CESPI_CODCGR);
    curr.zero(CESPI_CODSP);
  }
  else
  {
    curr.put(CESPI_CODCGR, m.get(F_GRUPPO));
    curr.put(CESPI_CODSP, m.get(F_SPECIE));
  }

  int err = TRelation_application::write(m);

	//gestione matricole
	if (err == NOERR)
		aggiorna_matricole(m);

  return err;
}

bool TAnacespi::kill_cespite(const TString& idcespite, int lfile, int key)
{
  TRelation rel(lfile);
  TRectype& filter = rel.curr();
	if (lfile == LF_MULTIREL)
	{
		filter.put(MULTI_COD, "CEMAT");
		filter.put(MULTI_FIRST, idcespite);
	}
	else
		filter.put("IDCESPITE", idcespite);
  
	TCursor cur(&rel, "", key, &filter, &filter);
  const TRecnotype items = cur.items();
  if (items > 0)
  {
    cur.freeze();
    const TRectype& curr = rel.curr();
    for (cur = 0L; cur.pos() < items; ++cur)
    {
      int err = curr.remove(rel.lfile());
      if (err != NOERR)
        return error_box(FR("Errore %d di cancellazione sul file %d"), err, lfile);
    }
  }
	return true;
}

bool TAnacespi::remove()
{
  const int staat = _qmask->stato_attivita();
  bool yes = false;
  if (staat == 3)
    yes = yesno_box(TR("ATTENZIONE: il cespite � gi� stato stampato su bollato.\n"
                    "Si desidera confermare l'elimininazione?"));
  else                  
    yes = yesno_box(TR("ATTENZIONE: verranno eliminati anche i valori relativi agli esercizi precedenti.\n"
                    "Si desidera confermare l'elimininazione?"));
    
  if (yes)  
	{
    TRelation* rel = get_relation();
    const TString16 idcespite = rel->curr().get(CESPI_IDCESPITE);

    if (kill_cespite(idcespite, LF_SALCE) && kill_cespite(idcespite, LF_MOVCE, 2) &&
				kill_cespite(idcespite, LF_MOVAM) && kill_cespite(idcespite, LF_AMMMV) &&
				kill_cespite(idcespite, LF_AMMCE) && kill_cespite(idcespite, LF_MULTIREL))
    {
      rel->write_enable(0, false); // Disabilito la cancellazione dei saldi (gia' cancellati prima)
			yes = TRelation_application::remove();
      rel->write_enable(0, true);
    }
	}
  return yes;
}

bool TAnacespi::user_create()
{             
  open_files(LF_TABCOM, LF_TAB, LF_CESPI, LF_SALCE, LF_AMMCE, LF_MOVCE, LF_MOVAM, LF_AMMMV, 0);
  _cespiti = NULL;
  _rel_year = 0;

  _qmask = new TQuery_mask;
  _emask = new TEdit_mask;
  return true;
}

bool TAnacespi::user_destroy()
{             
  delete _cespiti;
  delete _emask;
  delete _qmask;
  return true;
}

int ce0500(int argc, char* argv[])
{
  TAnacespi a;
  a.run(argc, argv, TR("Anagrafica cespiti"));
  return 0;
}