#ifndef __RIGHEDOC_H
#include "righedoc.h"
#endif

#ifndef __VE0100_H
#include "ve0100.h"
#endif

#ifndef __VE0100C_H
#include "ve0100c.h"
#endif

#ifndef __VEUML2_H
#include "veuml2.h"
#endif

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

static 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 );
  }
}

static bool riga_des_handler( TMask_field& f, KEY key )
{
  TMask& m = f.mask( );
  // Se qualcuno cerca di modificare la maschera
  if ( key == K_SPACE && m.is_running( ) )
  { 
    TString val( f.get( ) ); 
    if ( val.len( ) >= 49 )
    {
      TMask m1( "VE1000C" );
      m1.set( 101, f.get( ) );
      KEY k = m1.run( );
      if ( k == K_SAVE )
        f.set( m1.get( 101 ) );
    }
  } 
  return TRUE;
}

static bool riga_art_handler( TMask_field& f, KEY key )
{
  TMask& m = f.mask( );
  // Se qualcuno cerca di modificare la maschera
  if ( key == K_TAB ) // && m.is_running( ) )
  { 
    TSconto_riga r( app( ).clifo( ), &( app( ).edit_mask( ) ), &( f.mask( ) ) );
    r.calcola( );
    f.mask( ).set( FS_SCONTO, r.get( ) );
  } 
  return TRUE;
}


void TRiga::load( TToken_string& row )
{  
  _data.put( "CODNUM", row.get( FS_CODNUM - 101 ) );
  _data.put( "ANNO", row.get( FS_ANNO - 101 ) );
  _data.put( "PROVV", row.get( FS_PROVV - 101 ) );
  _data.put( "NDOC", row.get( FS_NDOC - 101 ) );
  _data.put( "STATORIGA", row.get( FS_STATORIGA - 101 ) );
  _data.put( "TIPORIGA", row.get( FS_TIPORIGA - 101 ) );
  _data.put( "PROFRIGA", row.get( FS_PROFRIGA - 101 ) );
  _data.put( "CODMAG", row.get( FS_CODMAG - 101 ) );
  _data.put( "CODART", row.get( FS_CODART - 101 ) );
  _data.put( "DESCR", row.get( FS_DESCR - 101 ) );
  _data.put( "DESCLUNGA", row.get( FS_DESCLUNGA - 101 ) );
  _data.put( "PREZZO", row.get( FS_PREZZO - 101 ) );
  _data.put( "UMQTA", row.get( FS_UMQTA - 101 ) );
  _data.put( "QTA", row.get( FS_QTA - 101 ) );
  _data.put( "QTAEVASA", row.get( FS_QTAEVASA - 101 ) );
  _data.put( "RIGAEVASA", row.get( FS_RIGAEVASA - 101 ) );
  _data.put( "TARA", row.get( FS_TARA - 101 ) );
  _data.put( "PNETTO", row.get( FS_PNETTO - 101 ) );
  _data.put( "NCOLLI", row.get( FS_NCOLLI - 101 ) );
  _data.put( "DAEVADERE", row.get( FS_DAEVADERE - 101 ) );  
  _data.put( "SCONTO", row.get( FS_SCONTO - 101 ) );
  _data.put( "PERCPROV", row.get( FS_PERCPROV - 101 ) );
  _data.put( "IMPFISSO", row.get( FS_IMPFISSO - 101 ) );
  _data.put( "CODIVA", row.get( FS_CODIVA - 101 ) );
  _data.put( "ADDIVA", row.get( FS_ADDIVA - 101 ) );
  _data.put( "ASPBENI", row.get( FS_ASPBENI - 101 ) );  
  carica_profilo( );
  _piede.destroy( );
  somma( _piede );  
}
    
void TRiga::save( TToken_string& row )
{
  row.add( _data.get( "CODNUM" ), FS_CODNUM - 101 );
  row.add( _data.get( "ANNO" ), FS_ANNO - 101 );
  row.add( _data.get( "PROVV" ), FS_PROVV - 101 );
  row.add( _data.get( "NDOC" ), FS_NDOC - 101 );
  row.add( _data.get( "STATORIGA" ), FS_STATORIGA - 101 );
  row.add( _data.get( "TIPORIGA" ), FS_TIPORIGA - 101 );
  row.add( _data.get( "PROFRIGA" ), FS_PROFRIGA - 101 );
  row.add( _data.get( "CODMAG" ), FS_CODMAG - 101 );
  row.add( _data.get( "CODART" ), FS_CODART - 101 );
  row.add( _data.get( "DESCR" ), FS_DESCR - 101 );
  row.add( _data.get( "DESCLUNGA" ), FS_DESCLUNGA - 101 );
  row.add( _data.get( "PREZZO" ), FS_PREZZO - 101 );
  row.add( _data.get( "UMQTA" ), FS_UMQTA - 101 );
  row.add( _data.get( "QTA" ), FS_QTA - 101 );
  row.add( _data.get( "QTAEVASA" ), FS_QTAEVASA - 101 );
  row.add( _data.get( "RIGAEVASA" ), FS_RIGAEVASA - 101 );
  row.add( _data.get( "TARA" ), FS_TARA - 101 );
  row.add( _data.get( "PNETTO" ), FS_PNETTO - 101 );
  row.add( _data.get( "NCOLLI" ), FS_NCOLLI - 101 );
  row.add( _data.get( "DAEVADERE" ), FS_DAEVADERE - 101 );
  row.add( _data.get( "SCONTO" ), FS_SCONTO - 101 );
  row.add( _data.get( "PERCPROV" ), FS_PERCPROV - 101 );
  row.add( _data.get( "IMPFISSO" ), FS_IMPFISSO - 101 );
  row.add( _data.get( "CODIVA" ), FS_CODIVA - 101 );
  row.add( _data.get( "ADDIVA" ), FS_ADDIVA - 101 );
  row.add( _data.get( "ASPBENI" ), FS_ASPBENI - 101 );
  row.add( _piede.string( ), FS_G1 - 101 );  
}

void TRiga::carica_maschera( )
{
  _mask = new TMask( _pro->get( "MSK", "MAIN" ) );
  int numhandler = _pro->get_int( "NHANDLER", "HANDLERS" );
  for( int i = 1; i <= numhandler; i ++ )
  {
    TString chiave;
    chiave.format( "%d", i );
    TToken_string riga = _pro->get( chiave, "HANDLERS" );
    row_set_handler( *_mask, riga.get_int( 0 ), riga.get_int( 1 ) );
  }
  _mask->set_handler( FS_CODART, riga_art_handler );
}

void TRiga::load( const TRectype& rec )
{
  _data = rec;
  carica_profilo( );
}

void TRiga::save( TRectype& rec )
{
  rec = _data;
  rec.put( "G1", _piede.string( ) );
}

void TRiga::carica_profilo( )
{
  if( _pro )
     delete _pro;
  TFilename proname( _data.get( "PROFRIGA" ) );
  proname.ext( "ini" );  
  _pro = new TConfig( proname );
}

void TRiga::configura_sheet( TSheet_field& f, int numriga )
{
  int ncols = _pro->get_int( "NCOLS", "COLUMNS" );
  // Disabilita tutte le colonne
  f.disable_cell ( numriga, -1 );
  // Abilita le colonne indicate nel profilo della riga  
  for( int i = 1; i <= ncols; i ++ )
  {
    TString16 chiave;
    chiave.format( "%d", i );
    int coltoenable = _pro->get_int( chiave, "COLUMNS" );
    f.enable_cell ( numriga, coltoenable - 1 );
  }
}

void TRiga::somma( TPiede_documento& piede )
{
  // Metti solo i campi numerici poichè sono gli unici che si calcolano
  //static const TString tabella_campi( "#STATORIGA#TIPORIGA#PROFRIGA#CODMAG#CODART#DESCR#DESCLUNGA#PREZZO#UMQTA#QTA#QTAEVASA#RIGAEVASA#TARA#PNETTO#NCOLLI#DAEVADERE#SCONTO#PERCPROV#IMPFISSO#IMPFISUN#CODIVA#ADDIVA#ASPBENI#" );
  static const TString tabella_campi( "#PREZZO#QTA#QTAEVASA#TARA#PNETTO#NCOLLI#PERCPROV#" );
  
  TToken_string s( _pro->get( "PROGPIEDE", "MAIN" ) );
  TString16 progpiede( s.get( ) );
  TTable ppd( "PPD" );
  while( !progpiede.blank( ) )
  {
    TString formula = s.get( );
    if( formula.blank( ) )
    { 
      // Se non è indicata alcuna formula, la prendo dalla tabella piedi
      ppd.zero( );
      ppd.put( "CODTAB", progpiede );
      if( ppd.read( ) == NOERR )
        formula = ppd.get( "S0" );
      else
        yesnofatal_box( "Progressivo piede non definito( %s ).", ( const char * ) progpiede );
    }
    // Calcolo la espressione
    TExpression espr( ""  );
    if ( espr.set( formula ) )
    {
      int last = espr.numvar( );
      for( int i = 0; i < last; i ++ )
      {
        TString varname( espr.varname( i ) );
        TString cerca;
        cerca.format( "#%s#", ( const char *)varname );
        if ( tabella_campi.find( cerca ) != -1 )
        {
          real value ( _data.get_real( varname ) );
          espr.setvar( varname, value );
        }
        else
        {
          if ( varname[ 0 ] == 'F' || varname[ 0 ] == 'f' )
          {
            TString16 nfunz ( varname );
            nfunz.rtrim( 1 );
            espr.setvar( varname, atoi( nfunz ) );
          }
          else
          {
            yesnofatal_box( "Variabile non definita nella funzione di calcolo della riga ( %s ).", ( const char * ) varname );
            break;
          }
        }      
      }
      piede.somma( progpiede, espr );
    }
    else
      yesnofatal_box( "Espressione non valida( %s )", ( const char * )formula );
    progpiede = s.get( );
  }    
}

void TRiga::sottrai( TPiede_documento& piede )
{
  
  TPiede_documento temp_piede;
  
  somma( temp_piede );
  piede.sottrai( temp_piede );
}

TMask& TRiga::getmask( )
{ 
  if( !_mask) 
    carica_maschera( ); 
  _mask->set_handler( FS_DESCR, riga_des_handler );
  return *_mask;
}


void TRiga::edit_keys( const KEY key, TPiede_documento& nuovo )
{
  static TPiede_documento vecchio;
  
  switch( key )
  {
    // Inizio modifica
    case K_SPACE:
      vecchio.destroy( );
      somma( vecchio );
      break;
      
    // Cancellazione  
    case K_DEL:
      // Toglie i vecchi valori
      nuovo.sottrai( vecchio );
      break;
      
    // Modifica
    case K_ENTER:
      // Toglie i vecchi valori
      nuovo.sottrai( vecchio );
      // Aggiunge i nuovi all
      somma( nuovo );
      break;
  }
}

TRiga::~TRiga( )
{ 
  if( _pro )
    delete _pro;
  if( _mask )
    delete _mask;
}


void TPiede_documento::somma( TPiede_documento& tosum, bool add  )
{                        
  tosum.restart( );
  THash_object* curr = tosum.get_hashobj( );
  while( curr )
  {
    TString16 key( curr->key( ) );
    if( add )
      somma( key, ( real& )curr->obj( ) );
    else
      sottrai( key, ( real& )curr->obj( ) );
    curr = tosum.get_hashobj( );
  }
}
    
void TPiede_documento::somma( TString16& piede, const real& importo )
{
  if( is_key( piede ) )
  {
    real& attuale = ( real& ) operator []( piede );
    attuale += importo;
  }
  else
    add( piede, importo );
}

TToken_string& TPiede_documento::string( )
{
  TToken_string ret;
  
  ret.separator( '~' );
  restart( );
  THash_object* curr = get_hashobj( );
  while( curr )
  {
    ret.add( curr->key( ) );
    ret.add( (( real& ) curr->obj( )).string( ) );
    curr = get_hashobj( );
  }
  return ret;  
}

void TPiede_documento::load( TToken_string& s )
{
  s.separator( '~' );
  for( int i = 0; i < s.items( ); i+=2 )
  {
    TString16 piede = s.get( i );
    TString num = s.get( i + 1 );
    real valore( num );
    add( piede, valore );
  }
}
    
real& TPiede_documento::get( TString16& piede )
{
  static real zero( "0.0" );
  
  if( is_key( piede ) )
  {
  	return ( real& ) find( piede );
  }
  else
  	return zero;
}