#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();
		
	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;
}