#include <defmask.h>
#include "velib.h"
#include "vepriv.h"

#include <tabutil.h>

#ifndef __VERIG_H
#include "verig.h"
#endif

#ifndef __VEUML1_H
#include "veuml1.h"
#endif

#ifndef __VEINI_H
#include "veini.h"
#endif

#ifndef __SCONTI_H
#include "sconti.h"             
#endif

#include "../mg/anamag.h"             
#include "../mg/codcorr.h"             
#include "../mg/deslin.h"             
#include "../mg/umart.h"             

bool ora_hndl( TMask_field& field, KEY key )

{
  if (field.to_check(key))
  {
    TFixed_string ora( field.get( ), 6 );
    
    ora.trim( );
    if (ora.not_empty() || field.required() )
    {
      if ( isdigit( ora[ 0 ] ) )
      {
        if ( ora[ 2 ] != ':')
        {
          if ( ora.len( ) > 4 )
            ora.overwrite( ":", 2 );
          else
            ora.insert( ":", 2 );            
        }
      }
      const bool ok = ((isdigit(ora[0]))&&(isdigit(ora[1]))&&(isdigit(ora[3]))&&(isdigit(ora[4]))) &&
                      ((atoi(&(ora[0]))<24)&&(atoi(&(ora[3]))<60));
      if (ok )
        field.set((ora));          
      else  
        return error_box("Ora errata o formato non valido");
    }
  }
  return TRUE;
}

bool dummy_hndl(TMask_field& field, KEY key)
{
  warning_box( "Al campo %d � arrivato un KEY %d", field.dlg( ), key );
  return TRUE;
}

// Handler per il calcolo delle date di pagamento
bool condpag_hndl( TMask_field& field, KEY key )
{                
  TDocumento_mask& m = (TDocumento_mask &) field.mask( );
  
  if ( field.to_check(key) || (key == K_TAB && !m.is_running()))
  {
    const TString16 condpag(m.get(F_CODPAG));
    TString16 data(m.get(F_DATAINSC));      
    
    if (data.empty())     
      data = m.get(F_DATADOC);      
    if ( condpag.not_empty())
    {
      TPagamento pag(condpag, data); 
      
      pag.set_total( 100, 10, 10 );
      pag.set_rate_auto( );      
      int numrate = pag.n_rate( );
      if (numrate > 5)
        numrate = 5;
      for( int i = 0; i < numrate; i ++ )
      {
        m.show( F_DATASCAD1 + i );
        m.set( F_DATASCAD1 + i, pag.data_rata(i).string());
      }
      for( ; i < 5; i ++ )
        m.hide( F_DATASCAD1 + i );
    }
  }
  return TRUE;
}

bool note_hndl( TMask_field& f, KEY key )
{             
  TDocumento_mask & m = (TDocumento_mask &) f.mask();

  if (key == K_TAB && (f.focusdirty() || !m.is_running()))
  {                         
    TTable & note = (TTable &) ((TEdit_field &) f).browse()->cursor()->file();
    note.setkey(1);
    const TString16 cod(f.get());
    
    if (cod != note.get("CODTAB"))
    {
      note.zero();
      note.put("CODTAB", cod);
      if (note.read() != NOERR)
        note.zero();
    }            
    if (m.doc().modificabile() || m.field(DLG_SAVEREC).enabled())
    {
	    const bool reg_disabled = note.get_bool("B0");
	    
	    if (reg_disabled)
	      message_box("Registrazione disbilitata : %s", (const char *) note.get("S0"));
	    m.enable(DLG_SAVEREC, !reg_disabled);
	  }
  }
  return TRUE;
}

// Handler per il calcolo delle date di pagamento
bool data_hndl( TMask_field& field, KEY key )
{                
  TDocumento_mask& m = (TDocumento_mask &) field.mask( );
  if (field.to_check(key))
  {                
    if (m.id2pos(F_DATAINSC) >= 0)
    {
      TEdit_field & e = m.efield(F_DATAINSC);
      e.set_dirty();
      e.on_hit();
    }

    if (m.id2pos(F_DATACAMBIO1) >= 0)
      m.set(F_DATACAMBIO1, field.get(), TRUE);
  }
  if (field.to_check(key,TRUE))
  {                
    TLocalisamfile doc(LF_DOC);           
    TDate datadoc(m.get(F_DATADOC));
    
    doc.curr() = m.doc().head(); 
    const TString16 codnum(doc.get(DOC_CODNUM));
    const int anno = doc.get_int(DOC_ANNO);
    const char tipo_num = doc.get_char(DOC_PROVV);
      
    doc.read();
    if (doc.prev() == NOERR)
    {                       
      const TDate dataprev = doc.get_date(DOC_DATADOC);
      if (!datadoc.ok())
      {
        datadoc = dataprev;
        field.set(dataprev.string());
      }
      if (codnum == doc.get(DOC_CODNUM) &&
          anno == doc.get_int(DOC_ANNO) &&
          tipo_num == doc.get_char(DOC_PROVV) &&
          datadoc < dataprev)
        return field.error_box("Data documento inferiore alla data del documento precedente");
    }
    
    doc.curr() = m.doc().head(); 
    if (doc.read(_isgreat) == NOERR &&
        codnum == doc.get(DOC_CODNUM) &&
        anno == doc.get_int(DOC_ANNO) &&
        tipo_num == doc.get_char(DOC_PROVV) &&
        datadoc > doc.get_date(DOC_DATADOC))
      return field.error_box("Data documento superiore alla data del documento successivo");
    
  }
  return TRUE;
}
  
// handler delle righe

void row_set_handler( TMask& m, const int field, const int index )
{
  switch ( index )
  {
    case 1:
      m.set_handler( field, dummy_hndl );
      break;
    default:
      yesnofatal_box( FALSE, "Funzione di handler sulla riga non definita( %d ).", index );
  }
}
                                     
HIDDEN TString16 curr_um;                                                     
HIDDEN real curr_fc(1.0);

bool iva_handler( TMask_field& f, KEY key )
{   
  if (key == 0 || (key == K_ENTER && f.get().empty()))
  {
    TDocumento_mask & mask = (TDocumento_mask &) f.mask().get_sheet()->mask();
    const TString16 codiva = mask.condv().clifo().vendite().get(CFV_ASSFIS);

    if (codiva.not_empty())
      f.set(codiva);
    f.check();
  }
  return TRUE;
}
                                       
bool codmag_handler( TMask_field& f, KEY key )
{
  if (f.to_check(key, TRUE))
  {        
    TMask& row_mask = f.mask();    
    
    if (row_mask.get_sheet()->column_enabled( ((TSheet_field &)f).cid2index(FR_CODDEP)))
    {  
      const int pos = row_mask.id2pos(FR_CODDEP);
      const TString & val = f.get();
                                                                                  
      if (pos >= 0 && val.not_empty())                                                               
      {
        TTable & mag = (TTable &)((TEdit_field &) f).browse()->cursor()->file();
        const TString &codmag = mag.get("CODTAB");
        if (codmag != val)
        {
          mag.put("CODTAB", val);
          if (mag.read() != NOERR)
            mag.zero();
        }
        const bool active = mag.get_bool("B0");
        row_mask.fld(pos).enable(active);                              
        if (!active)
          row_mask.fld(pos).reset();                              
      }
    }
  }
  return TRUE;
}             

bool codmag_coll_handler( TMask_field& f, KEY key )
{
  if (f.to_check(key, TRUE))
  {        
    TMask& row_mask = f.mask();    
    
    if (row_mask.get_sheet()->column_enabled( ((TSheet_field &)f).cid2index(FR_CODDEPC)))
    {  
      const int pos = row_mask.id2pos(FR_CODDEPC);
      const TString & val = f.get();
                                                                                  
      if (pos >= 0 && val.not_empty())                                                               
      {
        TTable & mag = (TTable &)((TEdit_field &) f).browse()->cursor()->file();
        const TString &codmag = mag.get("CODTAB");
        if (codmag != val)
        {
          mag.put("CODTAB", val);
          if (mag.read() != NOERR)
            mag.zero();
        }
        const bool active = mag.get_bool("B0");
        row_mask.fld(pos).enable(active);                              
        if (!active)
          row_mask.fld(pos).reset();                              
      }
    }
  }
  return TRUE;
}             

bool codart_handler( TMask_field& f, KEY key )
{
  TMask& row_mask = f.mask();   
              
  if (f.to_check(key, TRUE))
  { 
    if (f.get().not_empty())
        row_mask.enable(FR_LIV1);
    else
    {
      row_mask.reset(FR_LIV1);
      row_mask.disable(FR_LIV1);
    }    
    row_mask.field(FR_LIV1).on_hit();
  }
  if (key == K_TAB && (f.focusdirty() || row_mask.get(FR_CHECKED).empty()))
  {            
    TDocumento_mask & mask = (TDocumento_mask &) row_mask.get_sheet()->mask();
    TCond_vendita & condv = mask.condv();
    
    condv.set_testa(&mask);
    condv.set_riga(&row_mask);

    TLocalisamfile & anamag = ((TEdit_field &) f).browse()->cursor()->file();
    TLocalisamfile & umart  = ((TEdit_field &) row_mask.field(FR_UMQTA)).browse()->cursor()->file();
    
//    condv.set_anamag(anamag);
//    condv.set_umart(umart);
    
    TString80 codart(f.get());   
    anamag.setkey(1);
    anamag.put(ANAMAG_CODART, codart);
    bool found = anamag.read() == NOERR;
    if (found)
      row_mask.set(FR_CODARTMAG, codart, TRUE);
    else
    {
      TLocalisamfile codalt(LF_CODCORR);
      
      codalt.setkey(2);
      codalt.put(CODCORR_CODARTALT, codart);
      if (codalt.read() == NOERR)
      {                              
        codart = codalt.get(CODCORR_CODART);
        anamag.zero();
        anamag.put(ANAMAG_CODART, codart);
        found = anamag.read() == NOERR;
        if (found)
          row_mask.set(FR_CODARTMAG, codart, TRUE);
      }
    }     
    row_mask.set(FR_CHECKED, "X");
    if (!found)
        row_mask.set(FR_CODARTMAG, "", TRUE);
    else
    {
      const TString16 lingua = mask.get(F_CODLIN);                              
      const TString codart(row_mask.get(FR_CODARTMAG));
      TString desc(anamag.get("DESCR"));
      
      if (lingua.not_empty())
      {
        if (mask.doc()[((TSheet_field &)mask.field(F_SHEET)).selected() + 1].is_omaggio())  
          desc << " (OMAGGIO)";
        TLocalisamfile deslin(LF_DESLIN);
        
        deslin.setkey(2);
        deslin.put(DESLIN_CODART, codart);
        deslin.put(DESLIN_CODLIN, lingua);
        if (deslin.read() == NOERR)
          desc << '\n' << deslin.get(DESLIN_DESCR);
      }                        
      row_mask.set(FR_DESCR, desc);
                                     
      umart.setkey(1);              
      umart.zero(); 
      umart.put(UMART_CODART, codart);
      if (umart.read(_isgteq) == NOERR && codart == umart.get(UMART_CODART))
      {
        curr_um = umart.get(UMART_UM);       
        curr_fc = umart.get_real(UMART_FC);
      }
      else
      {
        curr_um.cut(0);                  
        curr_fc = 1.0;
      }
      row_mask.set(FR_UMQTA, curr_um);
    }

    condv.ricerca();
    const int pos = row_mask.id2pos(FR_CODIVA);

    if (pos >= 0)
      iva_handler(row_mask.fld(pos), 0);
  }
  return TRUE;
}                           

bool codartmag_handler( TMask_field& f, KEY key )
{                  
  bool to_check = key == K_TAB && f.focusdirty();
  TMask & m = f.mask(); 

  if (!to_check)
  {
    TSheet_field * s = m.get_sheet();
    
    if (s)
      to_check = !s->mask().is_running();
  }
  if (to_check)
  {                            
    const bool artmag = f.get().not_empty();
    
    m.show(FR_UMQTA, artmag);
    m.show(FR_UMQTA2, !artmag);
  }
  return TRUE;
}

bool liv_handler( TMask_field& f, KEY key )
{
  if (f.to_check(key, TRUE))
  {
    TMask& row_mask = f.mask();   
    TMask_field & next = row_mask.field(f.dlg() + 1);
    if (f.get().not_empty())
      next.enable();
    else
    {
      next.reset();
      next.disable();
    }                    
    next.on_hit();
  }
  return TRUE;
}  

void set_curr_um(const TMask & m)
{                
  curr_um = m.get(FR_UMQTA);
  curr_fc = -1.0;
}

bool umart_handler( TMask_field& f, KEY key )
{
  // Se qualcuno cerca di modificare la maschera
  if ( key == K_TAB && f.focusdirty())
  { 
    TMask& row_mask = f.mask( );               
    TDocumento_mask & mask = (TDocumento_mask &) row_mask.get_sheet()->mask();
    TLocalisamfile & anamag = ((TEdit_field &) row_mask.field(FR_CODART)).browse()->cursor()->file();
    TLocalisamfile & umart  = ((TEdit_field &) f).browse()->cursor()->file();
    TCond_vendita & condv = mask.condv();
    
//    condv.set_testa(&mask);
    condv.set_riga(&row_mask);
//    condv.set_anamag(anamag);
//    condv.set_umart(umart);

    const TString16 um(f.get());
    real fc(1.0);
    
    if (um.not_empty() && curr_um.not_empty() && um != curr_um)
    {           
      umart.setkey(2);                               
      umart.put(UMART_CODART, row_mask.get(FR_CODARTMAG));
      umart.put(UMART_UM, um);
      if (umart.read() == NOERR)
      {
        real qta(row_mask.get_real(FR_QTA));
        fc = umart.get_real(UMART_FC);
        if (curr_fc < ZERO)
        {
          umart.put(UMART_CODART, row_mask.get(FR_CODARTMAG));
          umart.put(UMART_UM, curr_um);
          if (umart.read() == NOERR)
            curr_fc = umart.get_real(UMART_FC);
          else
            curr_fc = 1.0;
        }
        qta *= curr_fc;          
        qta /= fc;
        qta.round(5);
        row_mask.set(FR_QTA, qta);
      }
        
    }
    curr_um = um;
    curr_fc = fc;
    condv.ricerca(TRUE);
  }   
  return TRUE;
}

bool descr_handler( TMask_field& f, KEY key )
{
  if (key == K_TAB && f.focusdirty())
  {            
    const TString s(f.get());
    if (s.find('\n') < 0)
    {
      TLocalisamfile & anamag = ((TEdit_field &) f).browse()->cursor()->file();
      
      anamag.zero();
      anamag.setkey(2);
      anamag.put(ANAMAG_DESCR, ((TZoom_field &) f).get_first_line());
      if (anamag.read() == NOERR)
      {                         
        f.mask().set(FR_CODART, anamag.get(ANAMAG_CODART));
        f.mask().field(FR_CODART).set_dirty();
        f.mask().check_field(FR_CODART);
      }
    }
  }       
  return TRUE;
}

bool qta_handler( TMask_field& f, KEY key )
{                   
  // Se qualcuno cerca di modificare la maschera
  if ( key == K_TAB && f.focusdirty())
  { 
    TMask& row_mask = f.mask( );               
    TDocumento_mask & mask = (TDocumento_mask &) row_mask.get_sheet()->mask();
//    TLocalisamfile & anamag = ((TEdit_field &) row_mask.field(FR_CODART)).browse()->cursor()->file();
//    TLocalisamfile & umart  = ((TEdit_field &) row_mask.field(FR_UMQTA)).browse()->cursor()->file();
    TCond_vendita & condv = mask.condv();
    
//    condv.set_testa(&mask);
    condv.set_riga(&row_mask);
//    condv.set_anamag(anamag);
//    condv.set_umart(umart);
    condv.ricerca(FALSE, TRUE);
    return qta_handler(f, key);
  } 
  return TRUE;
}
  
bool qta_handler( TMask_field& f, KEY key )
{                   
  // Se qualcuno cerca di modificare la maschera
  if ( key == K_TAB && f.focusdirty())
  { 
    TMask& row_mask = f.mask( );               
    const real qta_evasa = row_mask.get_real(FR_QTAEVASA);
    const real qta(f.get());

    if (qta_evasa > 0 && qta_evasa >= qta)
    {
      row_mask.set(FR_RIGAEVASA, "X");
      row_mask.disable(FR_RIGAEVASA);
    }
    else
      row_mask.enable(FR_RIGAEVASA);
  } 
  return TRUE;
}
  
bool qta_evasa_handler( TMask_field& f, KEY key )
{                   
  if (f.to_check(key))
  {
    TMask& row_mask = f.mask( );               
    const real qta_evasa(f.get());
    const real qta = row_mask.get_real(FR_QTA);

    if (qta_evasa > 0 && qta_evasa >= qta)
    {
      row_mask.set(FR_RIGAEVASA, "X");
      row_mask.disable(FR_RIGAEVASA);
    }
    else
      row_mask.enable(FR_RIGAEVASA);
  } 
  return TRUE;
}
  
// calcola il prezzo per le spese
void sppr_calc(TRectype & rec, const TString & valuta_doc, const real & cambio, real & prezzo)
{     
  const TString16 sppr_valuta(rec.get("S4"));
        
  if (sppr_valuta != valuta_doc && cambio != 0.0)
  {                           
    TTable val("%VAL");
          
    val.put("CODTAB", sppr_valuta);
    if (val.read() == NOERR)
    {
      const real sppr_cambio = val.get_real("R10");
      if (sppr_cambio != ZERO)
        prezzo *= sppr_cambio;
    }
    prezzo /= cambio;
  }
}
  
bool sppr_handler( TMask_field& f, KEY key )
{ 
  TMask& row_mask = f.mask();               
  
  if (key == K_TAB && (f.focusdirty() || row_mask.get(FR_DESCR).empty()))
  {                  
    const int pos = row_mask.id2pos(FR_PREZZO);
    
    if (pos >= 0)
    {
      TMask & mask = row_mask.get_sheet()->mask();
      TRectype & spprrec = ((TEdit_field &) row_mask.field(FR_CODART)).browse()->cursor()->file().curr();
      
      if (spprrec.get("CODTAB") == row_mask.get(FR_CODART))
      {                
        const char  tipo = spprrec.get_char("S6");         
        const bool qta_val_fl = tipo == 'Q';
        const bool perc_fl = tipo == 'P';

        short pos = row_mask.id2pos(FR_UMQTASP);
        if (pos >= 0)
          row_mask.fld(pos).enable(!perc_fl);
        pos = row_mask.id2pos(FR_PREZZO);
        if (pos >= 0)
          row_mask.fld(pos).enable(!perc_fl);
        pos = row_mask.id2pos(FR_SCONTO);
        if (pos >= 0)
          row_mask.fld(pos).enable(!perc_fl);
        pos = row_mask.id2pos(FR_QTA);
        if (pos >= 0)
        {                                    
          row_mask.fld(pos).show(!perc_fl);
          row_mask.fld(pos).enable(qta_val_fl);
        }  
        pos = row_mask.id2pos(FR_PERCSP);
        if (pos >= 0)
        {                                    
          row_mask.fld(pos).show(perc_fl);
          row_mask.fld(pos).enable(perc_fl);
        }  
        
        if (!perc_fl)
        {
          const real cambio = mask.get(F_CAMBIO);
          real prezzo = row_mask.get(FR_PREZZO);
          const TString16 doc_valuta(mask.get(F_CODVAL));
          sppr_calc(spprrec, doc_valuta, cambio, prezzo);
          row_mask.set(FR_PREZZO, prezzo);          
          
        }
        const int posiva = row_mask.id2pos(FR_CODIVA);
        
        if (posiva >= 0)
          iva_handler(row_mask.fld(posiva), 0);
      }
    }
  } 
  return TRUE;
}

///////////////////////////////////////////////////////////
// Formula generica
///////////////////////////////////////////////////////////
                
TExpr_documento::TExpr_documento(const char* expression, TTypeexp type,
                                 TDocumento * doc, TRiga_documento * row)
              : TExpression(type), _doc(doc), _row(row)
{
  if (!set(expression, type))
    error_box("Wrong expression : %s", expression);
}         

int TExpr_documento::parse_user_func(const char * name, int nparms) const
{    
  if (strcmp(name, "SOMMA") == 0)
    return nparms > 0 || nparms < 3 ? _somma : -1;
  else
    if (strcmp(name, "BOLLI") == 0)
      return nparms > 0 || nparms < 4 ? _bolli : -1;
    else
      if (strcmp(name, "_BOLLI") == 0)
        return nparms > 0 || nparms < 3 ? _bolli_int : -1;
      else
        if (strcmp(name, "SPESEINC") == 0)
          return nparms > 0 || nparms < 4 ? _spinc : -1;
        else
          if (strcmp(name, "PREZZO") == 0)
            return  nparms < 4 ? _prezzo : -1;
          else
            if (strcmp(name, "IMPORTO") == 0)
              return  nparms < 4 ? _importo : -1;
            else
              if (strcmp(name, "SCONTO") == 0)
                return nparms < 2 ? _sconto : -1;
              else
                if (strcmp(name, "IMPONIBILE") == 0)
                  return nparms == 0 ? _imponibile : -1;
                else
                  if (strcmp(name, "IVA") == 0)
                    return nparms == 0 ? _iva : -1;
                  else
                    if (strcmp(name, "PROVV") == 0)
                      return nparms < 2 ? _provv : -1;
                    else
                      if (strcmp(name, "QTARES") == 0)
                        return nparms < 2 ? _qtares : -1;
                      else
                        if (strcmp(name, "VALDOC") == 0)
                          return nparms < 3 ? _valdoc : -1;
                        else
                          if (strcmp(name, "TIPO") == 0)
                            return nparms == 0 ? _tipo : -1;
                          else 
                            if (strcmp(name, "IMPONIBILI") == 0)
                              return nparms < 3 ? _imponibili : -1;
                            else 
                              if (strcmp(name, "IMPOSTE") == 0)
                                return nparms < 3 ? _imposte : -1;
                              else 
                                if (strcmp(name, "TOTPROVV") == 0)
                                  return nparms < 3 ? _totprovv : -1;
                                else
                                  return -1;
}    

void TExpr_documento::evaluate_user_func(int index, int nparms, TEval_stack & stack, TTypeexp type) const
{                 
  switch (index)
  { 
    case _somma:
      {    
        const TString cond(nparms == 2 ? stack.pop_string() : "STR(1)");
        const TString & field = stack.pop_string();
        real somma;
          
        if (_doc != NULL)
        {                    
          TExpr_documento cond_expr(cond, _strexpr, _doc);
          const int cond_nvars = cond_expr.numvar();
          TExpr_documento expr(field, _numexpr, _doc);
          const int nvars = expr.numvar();
          const int nrows = _doc->rows();
            
          for (int i = nrows; i > 0; i--)
          {
            TRiga_documento & riga = (TRiga_documento &) (*_doc)[i];
              
            for (int j = cond_nvars - 1; j >= 0; j--)
            {
              const char* s = cond_expr.varname(j);
              TFieldref f(s,0);
              cond_expr.setvar(j, f.read(riga));
            }                       
            cond_expr.set_row(&riga);
            if ((bool)cond_expr)
            {
              for (j = nvars - 1; j >= 0; j--)
              {
                const char* s = expr.varname(j);
                TFieldref f(s,0);
                expr.setvar(j, f.read(riga));
              }                       
              expr.set_row(&riga);
              somma += expr.as_real();
            }
          }
        }
        stack.push(somma);
      }      
      break;
    case _spinc:
      {
        int ndec = AUTO_DECIMALS;
        bool netto = FALSE;
        
        if (nparms > 2)
          ndec = (int) stack.pop_real().integer();
        if (nparms > 1)
          netto = !stack.pop_real().is_zero();
          
        real & r = stack.peek_real();
                  
        if (_doc)          
          r = _doc->spese_incasso(r, ndec, netto ? _netto : _lordo);
        else
          r = ZERO;
      }    
      break;
    case _bolli:
      {
        int ndec = AUTO_DECIMALS;
        bool netto = FALSE;
        
        if (nparms > 2)
          ndec = (int) stack.pop_real().integer();
        if (nparms > 1)
          netto = !stack.pop_real().is_zero();
          
        real & r = stack.peek_real();
          
        if (_doc)
        {
          r += _doc->spese_incasso(r, ndec);
          r = _doc->bolli(r, ndec, netto ? _netto : _lordo);
        }
        else
          r = ZERO;
      } 
      break;
    case _bolli_int:
      {
        int ndec = AUTO_DECIMALS;
        
        if (nparms > 2)
          ndec = (int) stack.pop_real().integer();
          
        real & r = stack.peek_real();
        
        if (_doc)
        {
          real r1 = _doc->spese_incasso(r, ndec);
          r += r1;
          r1 += _doc->bolli(r, ndec);
          r = r1;
        }
        else
          r = ZERO;
      } 
      break;
    case _prezzo:
      {  
        int ndec = AUTO_DECIMALS;
        bool lordo = FALSE;
        bool scontato = FALSE;
  
        if (nparms > 2)
          ndec = (int) stack.pop_real().integer();
        if (nparms > 1)
          lordo = !stack.pop_real().is_zero();
        if (nparms > 0)
          scontato = !stack.peek_real().is_zero();
        else  
          stack.push(ZERO);
          
        real & val = stack.peek_real();
        if (_row)
          val = _row->prezzo(scontato, lordo, ndec);
        else
          val = ZERO;

      }
      break;
    case _importo:
      {  
        int ndec = AUTO_DECIMALS;
        bool lordo = FALSE;
        bool scontato = FALSE;
  
        if (nparms > 2)
          ndec = (int) stack.pop_real().integer();
        if (nparms > 1)
          lordo = !stack.pop_real().is_zero();
        if (nparms > 0)
          scontato = !stack.peek_real().is_zero();
        else  
          stack.push(ZERO);

        real & val = stack.peek_real();   
        if (_row)
          val = _row->importo(scontato, lordo, ndec);
        else
          val = ZERO;
      }
      break;
    case _imponibile:
      {
        real r;
                      
        if (_row)              
          r = _row->imponibile();
        stack.push(r);
      }
      break;
    case _sconto:
      {                                       
        int ndec = AUTO_DECIMALS;

        if (nparms > 0)
          ndec = (int) stack.peek_real().integer();
        else
          stack.push(ZERO);

        real & val = stack.peek_real();
        if (_row)
        {
          if (_row->is_sconto())
            val = -_row->importo(FALSE, FALSE, ndec);
          else
            val = _row->importo(FALSE, FALSE, ndec) - _row->importo(TRUE, FALSE, ndec);
        } 
        else
          val = ZERO;
      }
      break;
    case _iva:
      {  
        real r;
                      
        if (_row)              
          r = _row->imposta();
        stack.push(r);
      }
      break;
    case _provv:
      {  
        int ndec = AUTO_DECIMALS;

        if (nparms > 0)
          ndec = (int) stack.peek_real().integer();
        else
          stack.push(ZERO);

        real & val = stack.peek_real();

        if (_row)
          val = _row->provvigione(ndec); 
        else
          val = ZERO;
      }
      break;
    case _qtares:
      {  
        int ndec = AUTO_DECIMALS;

        if (nparms > 0)
          ndec = (int) stack.peek_real().integer();
        else
          stack.push(ZERO);
        real & val = stack.peek_real();

        if (_row)
          val = _row->qtaresidua(); 
        else
          val = ZERO;
      }
      break;
    case _valdoc:
      {  
        int ndec = AUTO_DECIMALS;
        bool totale = TRUE; // Totale o residuo per documento
        
        if (nparms > 1)
          ndec = (int)stack.pop_real().integer();
        if (nparms > 0)
          totale = !stack.peek_real().is_zero();
        else
          stack.push(ZERO);
          
        real & r = stack.peek_real();
                  
        if (_doc)          
          r = _doc->valore(totale, ndec); 
        else
          r = ZERO;
      }
      break;
    case _tipo:
      {
        TString s; 
        if (_row)
          s << _row->tipo().tipo();
        stack.push(s);
      }
      break;  
    case _imponibili:
      {
        int ndec = AUTO_DECIMALS;
        bool spese = FALSE;
    
        if (nparms > 1)
          ndec = (int) stack.pop_real().integer();
        if (nparms > 0)
          spese = !stack.peek_real().is_zero();
        else  
          stack.push(ZERO);
        real & val = stack.peek_real();
        val = _doc->imponibile(spese, ndec);
      }
      break;
    case _imposte:
      {
        int ndec = AUTO_DECIMALS;
        bool spese = FALSE;
    
        if (nparms > 1)
          ndec = (int) stack.pop_real().integer();
        if (nparms > 0)
          spese = !stack.peek_real().is_zero();
        else  
          stack.push(ZERO);
        real & val = stack.peek_real();
        val = _doc->imposta(spese, ndec);
      }
      break;
    case _totprovv: 
      {
        int ndec = AUTO_DECIMALS;

        if (nparms > 0)
          ndec = (int) stack.peek_real().integer();
        else  
          stack.push(ZERO);
        real & val = stack.peek_real();
        
        val = _doc->provvigione(ndec);
      }
      break;
    default:
      TExpression::evaluate_user_func(index, nparms, stack, type);
      break;
  }
}    

TObject* TExpr_documento::dup() const
{
  TExpr_documento* o = new TExpr_documento(*this);
  return o;
}    

///////////////////////////////////////////////////////////
// Formula generica
///////////////////////////////////////////////////////////

TFormula_documento::TFormula_documento(TTipo_formula tipo, const char* codice, const char * expr, bool numexpr)
               : TRectype(LF_TABCOM), _expr(NULL)
{               
  _tab = tipo == _documento ? "FRD" : "FRR";
  settab(_tab);
  _tab.insert("%");
  if (codice && *codice)
    read(codice, expr, numexpr);
}

TFormula_documento::TFormula_documento(const TRectype& rec)
               : TRectype(rec), _expr(NULL)
{
  _tab = "%";
  _tab << rec.get("COD");
  _expr = new TExpr_documento(expr_string(), expr_type());
}

TFormula_documento::~TFormula_documento()
{
  if (_expr) delete _expr;
}

int TFormula_documento::read(const char* codice, const char * expr, bool numexpr)
{           
  if (_expr != NULL)
  {
    delete _expr;
    _expr = NULL;
  }

  put("CODTAB", codice);
  
  int err = NOERR;
  
  if (expr && *expr)
  {
    put("S1", expr);
    put("B0", numexpr ? "X" : "");
  }  
  else           
  {
    TTable t(_tab);

    err = TRectype::read(t);
  }
  
  if (err == NOERR)             
  {
    const TString e(expr_string());
    
    _expr = new TExpr_documento(e, expr_type());
  }
  else
  {
    zero();
    put("CODTAB", codice);
  }
  return err;  
}