#include "resetfil.h"


///////////////////////////////////////////////////////////
// TResetfile
///////////////////////////////////////////////////////////

TResetfile::TResetfile(int logicnum, bool remove)
             : _file_num(logicnum), _removerec(remove),
               _validate_record_function(NULL),
               _validate_field_function(NULL),
               _before_reset_function(NULL), 
               _after_reset_function(NULL),
               _is_reseted(FALSE) 
{
  // oggetto file da azzerare
  _file = new TSystemisamfile(_file_num);
}

TResetfile::~TResetfile()
{                        
  // pack file se richiesto rimozione record 
  // e file azzerato
  if(_removerec && _is_reseted)
    _file->pack(FALSE);
    
  delete _file;
}

// @doc INTERNAL
// @mfunc ritorna se il campo <p fd> รจ un campo chiave
bool TResetfile::iskeyfield(const RecDes& recd, const int fd) const
{
  // inizializzo risultato da restituire
  bool found = FALSE;
  
  // loop di scansione delle chiavi del file
  for (int i = 0; i < recd.NKeys && !found; i++)
  {
    
    // Elenco dei campi della chiave
    const KeyDes& keyd = recd.Ky[i]; 
    
    // loop di scansione dei campi della chiave
    for (int j = 0; j < keyd.NkFields && !found; j++) 
      if (fd == keyd.FieldSeq[j] % MaxFields)
        found = TRUE;
  }                       
  
  return found;
}                                                            

// @doc INTERNAL
// @mfunc carica l'array <p resetable_fields> con i campi da azzerare
// @rfunc ritorna il numero di campi caricati
int TResetfile::load_resetable_fields(const RecDes& recd,
                                      TString_array& resetable_fields)
{
  // inizializzo numero campi da restituire
  int numfld = 0;
  
  for (int i = 0; i < recd.NFields; i++) 
  {                        
      // non azzero i campi chiave
      if (iskeyfield(recd, i))
        continue;                      
        
      // Descrittore campo
      RecFieldDes& fieldd = recd.Fd[i];
      
      // non azzero i campi indefiniti
      if (fieldd.TypeF == _nullfld)   
        continue;
       
      // aggiungo campo da azzerare all'array
      resetable_fields.add(fieldd.Name,numfld++);
  }
  
  return numfld;
}

// @doc EXTERNAL
// @mfunc esegue l'azzeramento del file
// @rfunc ritorna il codice errore relativo ad operazioni sul file
int TResetfile::run()
{ 
  // codice errore
  int err;               
  
  // numero campi da azzerare 
  int num_resetable_fields;
  
  // Apertura file con bloccaggio
  err = _file->open(_excllock); 
  if (err != NOERR)
    return err;
  
  // riferimento a record corrente
  TRectype& rec = _file->curr();            
  
  // Descrittore record 
  const RecDes* recd = rec.rec_des();
  
  // array dei campi da azzerare
  TString_array resetable_fields(recd->NFields);
  
  // riempimento array dei campi da azzerare
  if (!_removerec)
    num_resetable_fields = load_resetable_fields(*recd, resetable_fields);

  // reperimento nome file file
  const char* desfile = _file->description();
  
  // composizione testo per indicatore progressivo
  TString testo;
  testo.format("Azzeramento %s", desfile);
  
  // inizializzazione indice massimo e parziale per indicatore progressivo
  const long pmax = _file->items();
  long pi = 0L;
    
  // istanza indicatore progressivo per avanzamento azzeramento
  //TProgind p(pmax, testo, FALSE, TRUE);
  
  // loop di scansione file da azzerare
  for (err = _file->first(); err == NOERR; err = _file->next()) 
  {                                  
    // incremento indicatore progressivo
    //p.addstatus(1);
    pi++;
    
    // richiamo handler VALIDATE_RECORD 
    if (_validate_record_function)
      if (!_validate_record_function(rec))
        continue;
      
    // richiamo handler BEFORE_RESET 
    if (_before_reset_function)
      _before_reset_function(rec);
    
    // rimozione del record 
    if(_removerec)
      _file->remove();
    
    // azzeramento del record 
    else  
    {
      // loop di scansione campi da azzerare
      for (int i = 0; i < num_resetable_fields; i++) 
      {
        // richiamo handler VALIDATE_FIELD 
        if (_validate_field_function)
          if (!_validate_field_function(rec, resetable_fields.row(i)))
            continue;                      
          
        // azzeramento campi
        rec.zero(resetable_fields.row(i));
      }
    }
    
    // richiamo handler AFTER_RESET 
    if (_after_reset_function)
      _after_reset_function(rec);
      
    // registrazione record
    if(!_removerec)
      _file->rewrite();
  }
  
  // rabbocco indicatore progressivo
  //p.addstatus(pmax-pi);
  
  // chiusura file
  _file->close();
  
  // file azzerato
  _is_reseted = TRUE;
  
  return err;
}