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

TMotore_application& app( ) { return ( TMotore_application&  ) main_app( ); }

void TMotore_application::init_insert_mode( TMask& m )
{
  TString tipocf( "A" );
  tipocf[ 0 ] = app( ).tipocf( );
  // m.reset( );
  m.set( F_DATAINSC, m.get( F_DATADOC ) );
  m.set( F_TIPOCF, tipocf );
  clifo( ).occas_mask( ).reset( );
  int ndefaults = pro( ).get_int( "NDEFAULTS", "DEFAULT" );
  for( int i = 1; i <= ndefaults; i++ )
  {
     TString16 chiave;
     chiave.format( "%d", i );
     TToken_string valore( pro( ).get( chiave, "DEFAULT" ) );
     int campo( valore.get_int( 0 ) );
     TString default_val( valore.get( 1 ) );
     edit_mask( ).set( campo, default_val, TRUE );
  }
}

int TMotore_application::user_function( int index )
{
  switch( index )
  {  
  case 1:
    break;
  default:
    yesnofatal_box( "Chiamata ad una procedura utente non definita: %d", index );
    return NOERR;
    break;
  }
  return NOERR;      
}

// Funzione che dato il profilo di riga ottiene la maschera
// Serve per ottenere una maschera diversa per ogni riga
TMask *TMotore_application::ss_getmask( int numriga, TMask& fullmask, bool destroy )
{
  static TRiga* r = NULL;
  static TMask* m = NULL;
  
  if ( destroy )
  {
    delete r;
    r = NULL;
    return( NULL ); 
  }
  else  
  { 
    TSheet_field* ss = fullmask.get_sheet( );  
    TToken_string& riga = ss->row( numriga );
    TString16 profilo( riga.get( FS_PROFRIGA - 101 ) );
    if ( profilo.blank( ) ) return &fullmask;
    if( r && ( r->profilo( ) == profilo ) )
    {    
      return( m );
    }
    if ( !r )
      r = new TRiga;
    r->load( riga );
    m  = &(r->getmask( ));
    m->set_sheet( ss );
    return( m );
  }
}

void TMotore_application::azzera_piedi( )
{
  _piede.destroy( );
}

void TMotore_application::user_set_handler( int fieldid, int index, TMask* m )
{
  if ( !m )
    m = &edit_mask( );
  switch( index )
  { 
  case 1:
    m->set_handler( fieldid, ora_hndl );
    break;
  case 3:
    m->set_handler( fieldid, dummy_hndl );
    break;
  default:
    CHECK( FALSE, "Tentativo di installare un handler non definito" );
    break;
  }
}

bool TMotore_application::ss_handler( TSheet_field& ss, int r, KEY key )
{ 
  static TRiga* riga;
  
  if ( key == K_SPACE ) // Inizio modifica
  {
    TPiede_documento& piede = app( ).piede( );
    riga->edit_keys( key, piede );
  }
  if ( key == K_TAB ) // Mi posiziono su di una riga nello sheet
  {
    if ( riga )
      delete riga;
    riga = new TRiga;
    riga->load( ss.row( r ) );
  }
  if ( key == K_CTRL + K_TAB ) // Lascio una riga nello sheet
  {
    // TRelation rdoc( LF_RIGHEDOC );
    // TToken_string riga( ss.row( r ) );
    // rdoc.curr( ).zero( );
    // rdoc.curr( ).put( "CODNUM", app( ).edit_mask( ).get( F_CODNUM ) );
    // rdoc.curr( ).put( "ANNO", app( ).edit_mask( ).get( F_ANNO ) );    
    // rdoc.curr( ).put( "PROVV", app( ).edit_mask( ).get( F_PROVV ) );
    // rdoc.curr( ).put( "NDOC", app( ).edit_mask( ).get( F_NDOC ) );
    // rdoc.curr( ).put( "NRIGA", riga.get( 1 ) );
    // rdoc.read( );
    // app( ).edit_mask( ).field( F_MEMORIGA ).autosave( &rdoc );
    // rdoc.write( );
  }  
  if ( key == K_INS ) // Inserimento
  {
    TTable tabtr( "%TRI" );
    tabtr.zero( );
    tabtr.put( "CODTAB", app( ).edit_mask( ).get( F_LBTIPORIGA ) );
    tabtr.read( );
    TToken_string& tsr = ss.row( r );
    tsr.add( app( ).edit_mask( ).get( F_ANNO ), FS_ANNO - 101 );
    tsr.add( app( ).edit_mask( ).get( F_PROVV ), FS_PROVV - 101 );
    tsr.add( app( ).edit_mask( ).get( F_NDOC ), FS_NDOC - 101 );
    tsr.add( app( ).edit_mask( ).get( F_CODNUM ), FS_CODNUM - 101 );
    tsr.add( app( ).edit_mask( ).get( F_LBTIPORIGA ), FS_TIPORIGA - 101 );
    // tsr.add( app( ).edit_mask( ).get( F_PROFILO ), FS_PROFRIGA - 101 );
    tsr.add( tabtr.get( "S4" ), FS_PROFRIGA - 101 );
    if ( riga )     
      delete riga;
    riga = new TRiga;
    riga->load( tsr );    
    return TRUE;    
  }
  if ( key == K_CTRL + K_INS ) // Dopo inserimento
  {
    riga->configura_sheet( ss, r );
    app( ).curr_mask( ).send_key( K_ROWEDIT, F_SHEET );
    return TRUE;
  }
  if ( key == K_DEL ) // Cancellazione
  { 
    TPiede_documento& piede = app( ).piede( );
    riga->edit_keys( key, piede );
    return TRUE;
  }
  if ( key == K_ENTER ) // Modifica
  {
    TPiede_documento& piede = app( ).piede( );
    riga->edit_keys( key, piede );
    return TRUE;
  }
  return TRUE;
}

bool TMotore_application::num_handler( TMask_field& f, KEY key )
{                       
  // Ottengo la maschera
  TMask& m = f.mask( );
  
  if ( key == K_TAB && m.is_running( ) )
  {                          
    // Se la numerazione non è specificata, 
    const TString16 value( m.get( F_CODNUM ) );
    if ( value.blank( ) )
    {
      // Pulisce la descrizione
      m.set( F_DESNUM, "" );
      // Pulisce i tipi di documento consentiti
      m.set( F_TIPIDOCS, "" );
      // Pulisce il tipo di documento
      m.set( F_TIPODOC, "" );
      return TRUE;
    }    
    // Apro la tabella numerazioni
    TTable tabnum( "NUM" );
    tabnum.zero( );
    tabnum.put( "CODTAB", value );    
    if ( tabnum.read( ) == NOERR ) 
    {
      // Copio la descrizione della numerazione
      m.set( F_DESNUM, tabnum.get( "S0" ) );
      // Copio i tipi di documento validi per la numerazione
      const TString tipidocs( tabnum.get( "S2" ) );
      m.set( F_TIPIDOCS, tipidocs );
      TString16 curtipo( m.get( F_TIPODOC ) );
      if ( curtipo.blank( ) )
      {
        // Propone il primo tipo di documento come default
        m.set( F_TIPODOC, tipidocs.left( 4 ) );
        // m.field( F_TIPODOC ).check( );      
        m.send_key( K_TAB, F_TIPODOC );
      }      
      // Se per questa numerazione è abilitata le numerazione provvisoria
      if ( tabnum.get_bool ( "B0" ) )
      {
        // Setta di default la numerazione provvisoria
        m.set( F_PROVV, "P" );
        // Abilita il campo per la selezione della numerazione
        m.enable( F_PROVV );
      }
      else // Altrimenti ...
      {
        // Setta la numerazione a definitiva
        m.set( F_PROVV, "D" );
        // Disabilita il campo per la selezione della numerazione
        m.disable( F_PROVV );
      }
      return TRUE;
    }
    message_box( "Numerazione non valida!" );
    return FALSE;   
  }
  if ( key == K_ENTER && m.is_running( ) )
  {  // Se la numerazione non è specificata, 
    const TString16 value( m.get( F_CODNUM ) );
    if ( value.blank( ) )
    {
      message_box( "Occorre una numerazione per inserire un documento!" );
      m.first_focus( F_NDOC );
      return FALSE; 
    }
  }
  return TRUE;
}

bool TMotore_application::val_handler( TMask_field& f, KEY key )
{                       
  // Ottengo la maschera
  TMask& m = f.mask( );
  
  // m.set( F_CAMBIO, "" );
  // m.set( F_DATACAMBIO, "" );
  app( ).clifo( ).imposta_valuta( ( TMask_vendite&  ) m );
  return TRUE;
}


bool TMotore_application::occas_handler( TMask_field& f, KEY key )
{
  if ( key == K_SPACE && f.mask( ).is_running( ) )
  {
    TMask& om = app( ).clifo( ). occas_mask( );
    om.run( );     
    f.set_focus( );
  }  
  return TRUE;
}


bool TMotore_application::tip_handler( TMask_field& f, KEY key )
{                       
  TMask& m = f.mask( );
  if ( key == K_TAB && m.is_running( ) )
  {                          
    const TString16 value( m.get( F_TIPODOC ) );
    if ( value.blank( ) )
    {
      // Pulisce il profilo
      m.set( F_PROFILO, "" );
      return TRUE;
    }    
    TString tipi_consentiti( m.get( F_TIPIDOCS ) );
    TString16 tipo( f.get( ) );
    tipo.trim( );
    bool tipo_valido = FALSE;
    for ( int i = 0; i < 10; i ++ )
    {
      TString16 curtipo( tipi_consentiti.mid( i * 4, 4 ) );
      curtipo.trim( );
      if ( curtipo == tipo )
      {
        tipo_valido = TRUE;
        break;
      }
    }
    if ( ! tipo_valido )
    { 
      message_box( "Tipo non valido per la numerazione selezionata!" );
      f.set( "" );
      return FALSE;
    }   
    TTable tabtip( "%TIP" );
    tabtip.zero( );
    tabtip.put( "CODTAB", tipo  );
    tabtip.read( );
    m.set( F_DESTIPODOC, tabtip.get( "S0" ) );
    m.set( F_PROFILO, tabtip.get( "S4" ) );
  }
  if ( key == K_ENTER && m.is_running( ) )
  { TString tipo( f.get( ) );
    if ( ! tipo.blank( ) )
    { 
      TTable tabtip( "%TIP" );
      tabtip.read( );
      m.set( F_PROFILO, tabtip.get( "S4" ) );
    }
    else
    { 
      message_box( "Occorre un tipo documento per inserire un documento!" );
      m.first_focus( F_TIPODOC );
      return FALSE;
    }
  }             
  return TRUE;
}

bool TMotore_application::ndoc_handler( TMask_field& f, KEY key )
{                       
  TMask& m = f.mask( );
  if ( key == K_TAB && m.is_running( ) )
  { 
    TLocalisamfile& doc = app( ).rel( ).lfile( );
    doc.zero( );
    doc.put( "CODNUM", m.get( F_CODNUM ) );
    doc.put( "PROVV", m.get( F_PROVV ) );
    doc.put( "ANNO", m.get( F_ANNO ) );
    doc.put( "NDOC", f.get( ) );
    if ( doc.read( ) == NOERR )
    { 
      m.set( F_TIPODOC, doc.get( "TIPODOC" ) );
      m.set( F_STATO, doc.get( "STATO" ) );
      TTable tabtip( "%TIP" );
      tabtip.put( "CODTAB", doc.get( "TIPODOC" ) );
      tabtip.read( );
      m.set( F_PROFILO, tabtip.get( "S4" ) );        
      m.stop_run( K_AUTO_ENTER );
    }
  }         
  return TRUE;
}

bool TMotore_application::clifo_handler( TMask_field& f, KEY key )
{
  if ( key == K_TAB && f.active( ) )
  {
    TMask& m = f.mask( );

    const char cf = app( ).tipocf( );
    TLocalisamfile& clifo = ( ( TEdit_field& )f ).browse( )->cursor( )->file( );            
    
    if ( clifo.get_char( "TIPOCF" ) != cf || clifo.get( "CODCF" ) != f.get( ) )
    {       
      clifo.setkey( 1 );
      clifo.put( "TIPOCF", cf );   
      clifo.put( "CODCF", f.get( ) );   
      clifo.read( );
      CHECK( clifo.good( ), "Impossibile ritrovare il clifo" );
    }
    CHECKD( f.is_edit( ), "Can't check suspension of a non edit-field ", f.dlg( ) );
    const TEdit_field& c = ( const TEdit_field& )f;
    const TBrowse* b = c.browse( );
    CHECKD( b, "Can't check suspension of a edit-field without a USE ", f.dlg( ) );
    const TLocalisamfile& i = b->cursor( )->file( );
    //                        Tabella    File
    const char* sf = i.tab( ) ? "B2" : "SOSPESO";  
    const bool suspended = i.get_bool( sf );
    if ( suspended )
    {                                                                    
      sf = f.get( );
      return f.error_box( "Il codice '%s' e' sospeso e non puo' essere utilizzato", sf );  
    }
    /*
       if ( !m.is_running( ) || f.dirty( ) )
       {
       // Equichecazzociva? 
       
       }  
       */
    // Disabilitazioni varie, ma le demando all'oggetto cliente
    if ( f.focusdirty( ) )
    {
      app( ).clifo( ).load( cf, atol( f.get( ) ), "" );
      app( ).clifo( ).update_mask( ( TMask_vendite& ) m );
      if( f.mask( ).id2pos( F_OCCASEDIT ) > 0 )
      {
        if ( app( ).clifo( ).occasionale( ) && app( ).clifo( ).occas_mask( ).get( O_CODICE ).empty( ) )
          m.send_key( K_SPACE, F_OCCASEDIT );   // Lancia maschera occasionali        
      }
    }      
  }  
  return TRUE;
}

void TMotore_application::carica_piedi( )
{               
  TToken_string s( pro( ).get( "PROGPIEDE", "MAIN" ) );
  TString s1 = s.get( );
  TTable ppd( "PPD" );
  while( !s1.blank( ) )
  {
    ppd.zero( );
    ppd.put( "CODTAB", s1 );
    if( ppd.read( ) == NOERR )
    {
      real valpiede( "0.0" );
      if ( _piede.is_key( s1 ) )
        valpiede = ( real & )( _piede[ s1 ] );
      edit_mask( ).set( BASE_PIEDE + ppd.get_int( "I0" ), valpiede.stringa( 15 ) );
    }
    else
      message_box( "Piede non trovato( %s )", ( const char * )s1 );
    s1 = s.get( );
  }
}

void TMotore_application::somma_piedi( )
{ 
  /*for ( int i = 0; i < NPIEDI; i++ )
    _piedi[ i ] += _piedi_temp[ i ];*/
}

void TMotore_application::sottrai_piedi( )
{ 
  /*for ( int i = 0; i < NPIEDI; i++ )
    _piedi[ i ] -= _piedi_temp[ i ];*/
}

bool TMotore_application::changing_mask( int mode )
{ 
  static int lastmode = NO_MODE;
  
  const bool change = ( mode != lastmode );
  lastmode = mode;
  return change;  
}

void TMotore_application::configura_sheet( TSheet_field& sheet, TConfig& config )
{
  int ncols = config.get_int( "NCOLS", "SHEET" );
  for ( int i = 1; i <= ncols; i ++ )
  {
    TString col;
    col.format( "%d", i );
    TToken_string sheet_col( config.get( col, "SHEET" ) );
    const TString descr( sheet_col.get( 1 ) );
    if ( ! descr.blank( ) )
      sheet.set_column_header( i, descr );
    TString size( sheet_col.get( 2 ) );
    if ( ! size.blank( ) )
      sheet.set_column_width( i, sheet_col.get_int( 2 ) );
    int coltomove = sheet_col.get_int( 0 ) - 1;
    sheet.move_column( coltomove, i  );
  }
  for ( int j = MAX_COLUMNS; j >= i - 1; j -- )
    sheet.delete_column( j );
}

void TMotore_application::get_edit_mask( const char * profilo )
{
  TFilename fn( profilo );
  
  // query_mask( ).enable( DLG_NEWREC );
  fn.ext( "ini" );
  fn.upper( );
  if ( _pro ) 
  { 
    if ( ( *_proname ) == fn )
      return;
    delete _pro;    
  }  
  _pro =  new TConfig( fn );
  _proname = new TFilename( fn );
  _proname->upper( );
  if ( _msk1 ) delete _msk1;
  _msk1 = new TMask_vendite( pro( ).get( "MSKFILE", "MAIN" ) );
  // edit_mask( ).set( F_PROFILO, query_mask( ).get( F_PROFILO ) );
  // edit_mask( ).set( F_DESNUM, query_mask( ).get( F_DESNUM ) );
  _sheet = &( TSheet_field& )edit_mask( ).field( F_SHEET );
  sheet( ).set_notify( ss_handler );
  TString tipocf( app( ).pro( ).get( "TIPOCF", "MAIN" ) );
  app( ).tipocf( tipocf[ 0 ] );
  configura_sheet( *_sheet, *_pro );
  TList_field& listbox = ( TList_field& ) _msk1->field( F_LBTIPORIGA );
  const int numtr = app( ).pro( ).get_int( "NTIPIRIGA", "RIGHE" );
  TTable tabtr( "%TRI" );
  TToken_string keys( "" ), descrs( "" );
  for ( int i = 1; i <= numtr; i ++ )
  { 
    TString chiave;
    TToken_string item;
    chiave.format( "%d", i );
    tabtr.zero( );
    TString tiporiga( app( ).pro( ).get( chiave, "RIGHE" ) );
    tabtr.put( "CODTAB", tiporiga );
    if ( tabtr.read( ) == NOERR )
    { 
      keys.add( tabtr.get( "CODTAB" ) );
      descrs.add( tabtr.get( "S0" ) );
    }
    else
    {
      yesnofatal_box( "Inserito un tipo di riga non valido ( %s )", ( const char * )tiporiga );
    }
  }
  listbox.replace_items( keys, descrs );    
  sheet( ).set_getmask( ss_getmask );
  int numhandler = pro( ).get_int( "NHANDLER", "HANDLERS" );
  for ( i = 1; i <= numhandler; i ++ )
  { 
    TString chiave;
    chiave.format( "%d", i );
    TToken_string riga = pro( ).get( chiave, "HANDLERS" );
    user_set_handler( riga.get_int( 0 ), riga.get_int( 1 ) );
  }
  // _msk1->set( F_MEMORIGA, "Riga1" );  
}

TMask* TMotore_application::get_mask( int mode )
{
  TString profilo( query_mask( ).get( F_PROFILO ) );
  switch ( mode )
  {
    case MODE_INS: 
    case MODE_MOD: 
      if( !_msk )
         delete _msk;
      get_edit_mask( profilo );
      if ( edit_mask( ).id2pos( F_OCCASEDIT ) > 0 ) 
        edit_mask( ).set_handler( F_OCCASEDIT, occas_handler );
      if ( edit_mask( ).id2pos( F_CODVAL ) > 0 ) 
        edit_mask( ).set_handler( F_CODVAL, val_handler );
      edit_mask( ).set_handler( F_CODCF, clifo_handler );
      edit_mask( ).set_handler( F_CODPAG, condpag_hndl );
      edit_mask( ).set_handler( F_DATAINSC, condpag_hndl );
      return( _msk1 );
      break;
    default:
      if( !_msk )
      {
        _msk = new TMask( "ve1000a" );
      }
      if( !_msk1 )
      {
        delete _msk1;
      }
      return _msk;
      break;
  }
}

void TMotore_application::set_descr( int i, const char * dfi )
{
  TToken_string& r = ss( ).row( i );
  r.add( dfi, 0 );
}

void TMotore_application::carica_righe_libere( int from )
{
  if ( from < 0 ) from = ss( ).items( );
  for ( int i = from; i < 20; i++ )
    set_descr( i, "" );
  ss( ).force_update( );  
}

const char* TMotore_application::get_next_key( )
{ 
  TToken_string key;
  TMask& m = curr_mask( );
  
  TString value = m.get( F_CODNUM );
  if ( value.blank( ) )
    return NULL;
  TTable tabnum( "NUM" );
  tabnum.zero( );
  tabnum.put( "CODTAB", value );    
  if ( tabnum.read( ) == NOERR ) 
  {
    // Se per questa numerazione è abilitata le numerazione automatica
    if ( tabnum.get_bool ( "B1" ) )
    {
      TLocalisamfile doc( LF_DOC );
      doc.zero( );
      doc.put( "CODNUM", value );
      doc.put( "ANNO", m.get( F_ANNO ) );
      doc.put( "NDOC", 9999999L );
      // Se per questa numerazione è abilitata le numerazione provvisoria
      if ( tabnum.get_bool ( "B0" ) )
      {
        doc.put( "PROVV", "P" );
      }
      else // Altrimenti ...
      {
        doc.put( "PROVV", "D" );
      }
      if ( doc.read( _isgteq ) == NOERR ) 
      {
        doc.prev( );
      }
      long num = ( value == doc.get( "CODNUM" ) ) ? doc.get_long( "NDOC" ) : 0;
      key.format( "%d|%d", F_NDOC, num + 1 );          
      return key;
    }
  }
  return NULL;
}

int TMotore_application::read( TMask& m )
{  
  azzera_piedi( );
  int err = TRelation_application::read( m );
  if ( err == NOERR )
  { 
    edit_mask( ).set( F_DESNUM, query_mask( ).get( F_DESNUM ) );
    edit_mask( ).set( F_DESTIPODOC, query_mask( ).get( F_DESTIPODOC ) );
    const char tipocf = m.get( F_TIPOCF )[ 0 ];
    clifo( ).load( tipocf, m.get_int( F_CODCF ), rel( ).curr( ).get( "OCFPI" ) );
    clifo( ).update_mask( ( TMask_vendite& ) m, TRUE );
    TLocalisamfile& rdoc = rel( ).lfile( LF_RIGHEDOC );
    TRectype r = rdoc.curr( );
    TRectype& trec = get_relation( )->curr( );
    r.zero( );
    r.put( "CODNUM", trec.get( "CODNUM" ) );
    r.put( "PROVV", trec.get( "PROVV" ) );
    r.put( "ANNO", trec.get( "ANNO" ) );
    r.put( "NDOC", trec.get_long( "NDOC" ) );
    _righe_rec->read( r );
    TSheet_field& f = ( TSheet_field& ) m.field( F_SHEET );
    f.destroy( ); 
    int last = _righe_rec->last_row( );
    TRiga currentrow;
    for ( int i = 1; i <= last; i ++ )
    { 
      TToken_string& srow = f.row( i - 1 );
      TRectype& rec = _righe_rec->row( i, FALSE );
      currentrow.load( rec );
      currentrow.save( srow );
      currentrow.configura_sheet( f, i -  1 );
      currentrow.somma( _piede );      
    } 
    carica_piedi( );
  }
  return err;
}

bool TMotore_application::check_key( TLocalisamfile& rdoc, TString16 codnum, bool provv, TString16 anno, TString16 ndoc )
{
  return ( ( rdoc.get( "CODNUM" ) == codnum ) && 
          ( rdoc.get( "NDOC" ) == ndoc ) && 
          ( rdoc.get( "ANNO" ) == anno ) && 
          ( rdoc.get_bool( "PROVV" ) == provv ) );
}

int TMotore_application::write( const TMask& m )
{ 
  int err;
  if ( esegui_procedura( OP_NUOVO ) != NOERR )
    return FALSE;
  m.field( F_STATO ).set( _pro->get( "STATOFINALE", "INSERIMENTO" ) );
  err = NOERR; // avanza_numero( m.get_bool( F_PROVV ) );
  if ( err == NOERR )
  {
    if ( m.id2pos( F_OCCASEDIT) > 0 )
      err = app( ).clifo( ).write_occas( );
  }
  if ( err == NOERR )
  {  
    err = TRelation_application::write( m );
    if ( err == NOERR )
    { 
      TSheet_field& f = ss( );
      _righe_rec->destroy_rows( );
      if ( m.insert_mode( ) )
        _righe_rec->renum_key( "NRIGA", 1 );
      for ( int i = 0; i < f.items( ); i ++ )
      {
        TToken_string& t = f.row( i );
        TRectype& rec = _righe_rec->row( i + 1, TRUE ); 
        store_riga( f, i, rec );
      } 
      err = _righe_rec->write( );      
    }
  }
  return err;
}

int TMotore_application::rewrite( const TMask& m )
{
  int err = NOERR;
  if ( ! valida_operazione( OP_MODIFICA ) )
    return FALSE;
  if ( err == NOERR )
  {
    err = app( ).clifo( ).write_occas( );
  }
  if ( err == NOERR )
  {  
    err = TRelation_application::rewrite( m );
    if ( err == NOERR )
    { 
      TSheet_field& f = ss( );
      _righe_rec->destroy_rows( );
      if ( m.insert_mode( ) )
        _righe_rec->renum_key( "NRIGA", 1 );
      for ( int i = 0; i < f.items( ); i ++ )
      {
        TToken_string& t = f.row( i );
        TRectype& rec = _righe_rec->row( i + 1, TRUE ); 
        store_riga( f, i, rec );
      } 
      err = _righe_rec->rewrite( );      
    }
  }
  return err;
}


// La funzione si trova in ve0100b

long TMotore_application::prossimo_numero( bool provv )
{
  long ret;
  TTable tabnum( "NUM" );
  
  tabnum.read( );
  if ( provv )
    ret = tabnum.get_long( "I0" ) + 1;
  else 
    ret = tabnum.get_long( "I1" ) + 1;
  return ( ret );
}

int TMotore_application::avanza_numero( bool provv )
{
  TTable tabnum( "NUM" );
  
  int err = tabnum.read( );
  if ( err == NOERR )
  {  
    if ( provv )
      tabnum.put( "I0", tabnum.get_long( "I0" ) + 1 );
    else 
      tabnum.put( "I1", tabnum.get_long( "I1" ) + 1 );
    err = tabnum.rewrite( );
  }
  return err;
} 

bool TMotore_application::remove( void )
{                                           
  if ( ! valida_operazione( OP_CANCELLA ) )
    return FALSE;
  return TRelation_application::remove && ( _righe_rec->remove( ) == NOERR );
}

void TMotore_application::load_riga( TSheet_field& f, int numrig, TRectype& r )
{
  TToken_string& riga = f.row( numrig );
  riga = r.get( "STATORIGA" );
  riga.add( r.get( "TIPORIGA" ) );
  TFilename proname( r.get( "PROFRIGA" ) );
  riga.add( proname );
  riga.add( r.get( "CODMAG" ) );
  riga.add( r.get( "CODART" ) );
  riga.add( r.get( "DESCR" ) ); 
  riga.add( r.get( "DESCLUNGA" ) );
  riga.add( r.get( "PREZZO" ) );
  riga.add( r.get( "UMQTA" ) ); 
  riga.add( r.get_real( "QTA" ).string( 11 ) );
  riga.add( r.get( "QTAEVASA" ) );
  riga.add( r.get( "RIGAEVASA" ) );
  riga.add( r.get( "TARA" ) );
  riga.add( r.get( "PNETTO" ) );
  riga.add( r.get( "NCOLLI" ) );
  riga.add( r.get( "DAEVADERE" ) );
  riga.add( r.get( "SCONTO" ) );
  riga.add( r.get( "PERCPROV" ) );
  riga.add( r.get( "IMPFISSO" ) );
  riga.add( r.get( "IMPFISUN" ) );
  riga.add( r.get( "CODIVA" ) );
  riga.add( r.get( "ADDIVA" ) );
  riga.add( r.get( "ASPBENI" ) );
  proname.ext( "ini" );
  TConfig pro( proname ); 
  int ncols = pro.get_int( "NCOLS", "COLUMNS" );
  // Disabilita tutte le colonne
  for ( int i = 1; i <= MAX_COLUMNS; i ++ )
    f.disable_cell ( f.items( ) - 1, i );
  // Abilita le colonne indicate nel profilo della riga  
  for ( i = 1; i <= ncols; i ++ )
  {
    TString16 chiave;
    chiave.format( "%d", i );
    int coltoenable = pro.get_int( chiave, "COLUMNS" );
    f.enable_cell ( numrig - 1, coltoenable - 1 );
  }
}                                           

void TMotore_application::store_riga( TSheet_field& f, int numrig, TRectype& r )
{
  TToken_string& rigastr = f.row( numrig );
  TRiga riga;
  riga.load( rigastr );
  riga.set_numero( numrig + 1 );
  riga.save( r );
}

bool TMotore_application::user_create( )
{  
  TConfig ditta( CONFIG_DITTA );
  
  // Controllo se sono cambiate le impostazioni delle vendite.
  if ( ditta.get_bool( "CHANGED", "ve" ) )
  { // Se sono cambiate, rigenero tutte le maschere
    if ( !yesno_box( CHANGE_MESSAGE ) )
      return FALSE;
    TExternal_app motore2( "VE0 -3 -all" );
    motore2.run( );
    ditta.set( "CHANGED", "", "ve" );  
  }  
  _clifor = new TCliForVendite( );
  azzera_piedi( );
  _msk = new TMask( "VE1000A" );
  query_mask( ).set_handler( F_NDOC, ndoc_handler );
  query_mask( ).set_handler( F_CODNUM, num_handler );
  query_mask( ).set_handler( F_TIPODOC, tip_handler );
  TConfig utente( CONFIG_USER );
  TString16 codnum( utente.get( "CODNUM", "ve" ) );
  if ( !codnum.blank( ) )
  {
    query_mask( ).set( F_CODNUM, codnum );
    query_mask( ).set( F_DESNUM, utente.get( "DESNUM", "ve" ) );
  }
  TString16 tipodoc( utente.get( "TIPODOC", "ve" ) );
  if ( !tipodoc.blank( ) ) 
  {
    query_mask( ).set( F_TIPODOC, tipodoc );
    query_mask( ).set( F_DESTIPODOC, utente.get( "DESTIPODOC", "ve" ) );
  }
  // La maschera di inserimento/modifica per ora non la so!
  // Viene letta dal profilo non appena trovato il record
  _msk1 = NULL;

  // Metto in relazione testata e righe
  _rel = new TRelation( LF_DOC );
  rel( ).add( LF_RIGHEDOC,"CODNUM=CODNUM|ANNO=ANNO|PROVV=PROVV|NDOC=NDOC" );

  // Inizializzo il Record_array
  _righe_rec = new TRecord_array( LF_RIGHEDOC, "NRIGA", 1 );
  
  return TRUE;
}

bool TMotore_application::user_destroy( )
{              
  // Registro l'ultimo tipo documento e l'ultima numerazione
  TConfig utente( CONFIG_USER );
  utente.set( "CODNUM", query_mask( ).get( F_CODNUM ), "ve" );
  utente.set( "TIPODOC", query_mask( ).get( F_TIPODOC ), "ve" );
  utente.set( "DESNUM", query_mask( ).get( F_DESNUM ), "ve" );
  utente.set( "DESTIPODOC", query_mask( ).get( F_DESTIPODOC ), "ve" );  
  // Se è ancora allocata, distruggo la maschera di modifica
  if ( _msk1 ) delete _msk1;

  // Distruggo la maschera di modifica
  delete _msk;
  
  // Distruggo la relazione
  delete _rel;

  // Distruggo il Record_array
  delete _righe_rec;

  return TRUE;
}    

int TMotore_application::esegui_procedura( int operazione )
{
  // Accesso unico alla chiamata di procedure tramite operazione
  int index = ( int )pro( ).get_long( nome_sezione( operazione ), "MAIN" );
  if ( index )
    return ( user_function( index ) );
  return ( NOERR );   
}

bool TMotore_application::valida_operazione( int operazione )
{
  if ( operazione != OP_NUOVO )
  { 
    if ( !stato_valido( stato_corrente( ), operazione ) )
    {  
      segnala_stato_non_valido( operazione );
      return FALSE;
    }
  }
  if ( esegui_procedura( operazione ) != NOERR )
    return FALSE;
  return TRUE;   
}

const char * TMotore_application::nome_sezione( int op )
{ 
  switch( op )
  {  
  case OP_NUOVO:
    return "INSERIMENTO";
    break;
  case OP_MODIFICA:
    return "MODIFICA";
    break;
  case OP_CANCELLA:
    return "CANCELLAZIONE";
    break;
  case OP_STAMPA:
    return "STAMPA";
    break;            
  case OP_RAGGRUPPA:
    return "RAGGRUPPA";
    break;
  case OP_USER:
    return "SPECIALE";
    break;
  default:
    CHECK( FALSE, "tentativo di ottenere il nome di una operazione inesistente!" );
    // Per evitare la warning
    return "";
    break;
  }
}

int TMotore_application::stato_finale( int operazione )
{ 
  TString s( pro( ).get( "STATOFINALE", nome_sezione( operazione ) ) );
  if ( strcmp( s, "N" ) == 0 ) return NO_CHANGE_STATUS;
  return ( atoi( s ) ); 
}

bool TMotore_application::stato_valido( int stato, int operazione )
{                        
#ifdef _DEBUG
  warning_box( "Controllo stati validi!\nStato corrente %d.\nStati validi %s.", stato_corrente( ), ( const char * )stati_validi( operazione ) );
#endif
  char p[2] = "0";   
  TToken_string ret ( stati_validi( operazione ), ',' );
  p[0] += ( char )stato;
  return ( ret.get_pos( p ) != -1 );
}

/*void TMotore_application::setta_stato_corrente( int nuovostato )    
  {
  // warning_box( "Settaggio stati validi!\nStato corrente %s.\nStati validi %s.\nStato finale %s.", stato_corrente( ), stati_validi( operazione ), stato_finale( operazione ) );
  TString p;
  p.format( "%d", nuovostato );
  
  TLocalisamfile& doc = rel( ).lfile( LF_DOC );
  
  p[ 0 ] += ( char ) nuovostato;                  
  doc.put( "STATO", p );
  doc.rewrite( );   
  query_mask( ).set( F_STATO, p );
  // warning_box( "Settaggio stati validi!\nStato corrente %s.\nStati validi %s.\nStato finale %s.", stato_corrente( ), stati_validi( operazione ), stato_finale( operazione ) );
  }   */

int TMotore_application::stato_corrente( )
{                                   
  int i = query_mask( ).get_int( F_STATO );
  return ( i == 0 ? NO_DOC_STATUS : i );
}

void TMotore_application::segnala_stato_non_valido( int operazione )
{
  TString messaggio;
  
  switch( operazione )
  {
  case OP_NUOVO:
    // Sempre valido
    break;
  case OP_MODIFICA:
    messaggio = "Il documento non si trova in uno stato valido per poter essere modificato!";
    break;
  case OP_CANCELLA:
    messaggio = "Il documento non si trova in uno stato valido per poter essere cancellato!";
    break;
  case OP_STAMPA:
    messaggio = "Il documento non si trova in uno stato valido per poter essere stampato!";
    break;
  case OP_RAGGRUPPA:
    messaggio = "Il documento non si trova in uno stato valido per poter essere raggruppato!";
    break;
  case OP_USER:
    messaggio = "Il documento non si trova in uno stato valido per effettuare la operazione richiesta!";
    break;
  default:
    CHECK( FALSE, "Tentativo di segnalare stato non valido di una operazione non esistente!" ); 
    break;
  }
  messaggio << "\nStato corrente :%d.\nStati validi   :%s.";
  warning_box( messaggio, stato_corrente( ), ( const char * )stati_validi( operazione ) );
}    

int ve0100( int argc, char** argv )
{
  TMotore_application a;
  
  a.run( argc, argv, "Gestione documenti" );
  return 0;
}
