corretta la gestione dei link git-svn-id: svn://10.65.10.50/trunk@6000 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1503 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1503 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
#include "ablib01.h"
 | 
						||
/**************************************************************************************************/
 | 
						||
//  TAlbero_AB
 | 
						||
/**************************************************************************************************/
 | 
						||
 | 
						||
TAlbero_AB::TAlbero_AB(int filenum)
 | 
						||
             :TRectype(filenum)
 | 
						||
{
 | 
						||
}
 | 
						||
 | 
						||
int TAlbero_AB::write(TBaseisamfile &analisi) const
 | 
						||
{                      
 | 
						||
  int err = TRectype::write(analisi);
 | 
						||
  if (err==NOERR)
 | 
						||
  {
 | 
						||
    commit_body();
 | 
						||
  }
 | 
						||
  else
 | 
						||
  {
 | 
						||
    err = rewrite(analisi);
 | 
						||
  }
 | 
						||
  if (err)
 | 
						||
    CHECK (FALSE,"Errore di scrittura del record sull'isamfile");
 | 
						||
  return err;
 | 
						||
}
 | 
						||
 | 
						||
int TAlbero_AB::rewrite(TBaseisamfile &analisi) const
 | 
						||
{                      
 | 
						||
  int err = TRectype::rewrite(analisi);
 | 
						||
  if (err==NOERR)
 | 
						||
  {
 | 
						||
    commit_body();
 | 
						||
  }
 | 
						||
  if (err)
 | 
						||
    CHECK (FALSE,"Errore di scrittura del record sull'isamfile");
 | 
						||
  return err;
 | 
						||
}
 | 
						||
 | 
						||
//Leggo la "testata" del record
 | 
						||
int TAlbero_AB::read(TBaseisamfile& saldi, word isop, word lockop)
 | 
						||
{         
 | 
						||
  int err=TRectype::read(saldi, isop, lockop);
 | 
						||
  if (err==NOERR)
 | 
						||
    read_body(FALSE);
 | 
						||
  return err;
 | 
						||
}
 | 
						||
 | 
						||
//Leggo la testata del record basandomi sulla posizione
 | 
						||
int TAlbero_AB::readat(TBaseisamfile& analisi, TRecnotype nrec, word lockop)
 | 
						||
{
 | 
						||
  int err=TRectype::readat(analisi, nrec, lockop);
 | 
						||
  if (err==NOERR)
 | 
						||
    read_body(FALSE);
 | 
						||
  return err;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
int TAlbero_AB::remove(TBaseisamfile& f) const
 | 
						||
{
 | 
						||
/*Abilitare questa parte solo per effettuare un debug della delete_node
 | 
						||
//  anche se messa in questa posizione, la chiamata non ha senso
 | 
						||
 // TLocalisamfile lf(LF_RELANA);
 | 
						||
  TNumeric_id id;
 | 
						||
  id = 4;
 | 
						||
  _inter_tree->delete_node(id);
 | 
						||
  int errc = commit_body();
 | 
						||
  if (errc != NOERR)
 | 
						||
  {             
 | 
						||
    message_box("Errore nell'aggiornameno del file dati");
 | 
						||
    //return errc;
 | 
						||
  }
 | 
						||
  return 0;
 | 
						||
*/  
 | 
						||
 | 
						||
 | 
						||
//*Abilitare solo questa parte per il test della remove_tree  
 | 
						||
  _inter_tree->delete_tree();
 | 
						||
  int errc = commit_body();
 | 
						||
  if (errc != NOERR)
 | 
						||
  {             
 | 
						||
    message_box("Errore nell'aggiornameno del file dati");
 | 
						||
    //return errc;
 | 
						||
  }
 | 
						||
  int err = TRectype::remove(f);
 | 
						||
  return err;
 | 
						||
} 
 | 
						||
 | 
						||
void TAlbero_AB::zero() 
 | 
						||
{
 | 
						||
  _inter_tree->zero();
 | 
						||
  TRectype::zero() ;
 | 
						||
} 
 | 
						||
  
 | 
						||
 | 
						||
/**************************************************************************************************/
 | 
						||
//  TABsaldo
 | 
						||
/**************************************************************************************************/
 | 
						||
TABsaldo::TABsaldo()
 | 
						||
             :TAlbero_AB(LF_ABSALDI)
 | 
						||
{
 | 
						||
  _saldi   = new TLocalisamfile(LF_ABSALDI);
 | 
						||
  _movdett = new TLocalisamfile(LF_MOVDETT);
 | 
						||
//  _relaz  = NULL;
 | 
						||
//  _ana    = NULL;
 | 
						||
  _inter_tree = new TLocal_balance3();
 | 
						||
  _newrec = new TRectype(LF_MOVDETT);
 | 
						||
}
 | 
						||
 | 
						||
TABsaldo::~TABsaldo()
 | 
						||
{
 | 
						||
  delete _saldi;
 | 
						||
  delete _movdett;
 | 
						||
  delete _inter_tree;
 | 
						||
  delete _newrec;
 | 
						||
}
 | 
						||
 | 
						||
void TABsaldo::put_headkey(TRectype &rec) const
 | 
						||
{
 | 
						||
  rec.put(ABMD_CODDITTA, get(ABS_CODDITTA));
 | 
						||
  rec.put(ABMD_ANNO, get(ABS_ANNO));
 | 
						||
  rec.put(ABMD_CODPDB, get(ABS_CODPDB));
 | 
						||
  rec.put(ABMD_TIPOBIL, get(ABS_TIPOBIL));
 | 
						||
  rec.put(ABMD_CODCBL, get(ABS_CODCBL));
 | 
						||
}
 | 
						||
 | 
						||
//Leggo il "corpo" del record
 | 
						||
int TABsaldo::read_body(bool lockstruct)
 | 
						||
{                      
 | 
						||
  TString codditta = get(ABS_CODDITTA);
 | 
						||
  TToken_string key = codditta.right_just(5,'0');
 | 
						||
  key.add(get(ABS_ANNO));
 | 
						||
  key.add(get(ABS_CODPDB));
 | 
						||
  key.add(get(ABS_TIPOBIL));
 | 
						||
  key.add(get(ABS_CODCBL));
 | 
						||
  _mov = new TAlbero_movdett(key);
 | 
						||
  
 | 
						||
  if (_mov->goto_root())
 | 
						||
  {
 | 
						||
    naviga_movdett();
 | 
						||
  }
 | 
						||
  //_inter_tree->write_cache(); //solo per debug
 | 
						||
  //prova_inserimento(); //Solo debug per inserimento diretto di un nodo
 | 
						||
  return 0;
 | 
						||
}
 | 
						||
 | 
						||
//Naviga l'albero dei movimenti-dettagli
 | 
						||
void TABsaldo::naviga_movdett()
 | 
						||
{
 | 
						||
  TNodeId key_rel;
 | 
						||
  _mov->curr_id(key_rel);
 | 
						||
  TNumeric_id lbrother_id, pather_id, my_id;
 | 
						||
   
 | 
						||
  my_id = _mov->curr().get_real(ABMD_ID);
 | 
						||
  pather_id = _mov->curr().get_real(ABMD_IDPADRE);
 | 
						||
  lbrother_id = _mov->curr().get_real(ABMD_IDPREC);
 | 
						||
  *_newrec = _mov->curr(); 
 | 
						||
  _inter_tree->insert_node(*_newrec,lbrother_id,pather_id,my_id);
 | 
						||
  
 | 
						||
  if (_mov->has_rbrother())
 | 
						||
  {
 | 
						||
    if (_mov->goto_rbrother())
 | 
						||
    { //Fratello di movdett trovato
 | 
						||
      naviga_movdett();
 | 
						||
      _mov->goto_node(key_rel);
 | 
						||
    }
 | 
						||
  }
 | 
						||
  
 | 
						||
  if (_mov->has_son())
 | 
						||
  {
 | 
						||
    if (_mov->goto_firstson())
 | 
						||
    { //Fratello di movdett trovato
 | 
						||
      naviga_movdett();
 | 
						||
      _mov->goto_node(key_rel);
 | 
						||
    }
 | 
						||
  }
 | 
						||
}           
 | 
						||
 | 
						||
 | 
						||
// Questa rudimentale funzione serve solo per il debug: richiama direttamente
 | 
						||
//la insert_node di un saldo IMMETTENDO un nuovo nodo nella struttura.
 | 
						||
// Cambiando i parametri id posiziona il nodo in posizione diverse
 | 
						||
void TABsaldo::prova_inserimento()
 | 
						||
{ 
 | 
						||
  TRectype prova(LF_MOVDETT);
 | 
						||
  TNumeric_id lbrother_id,pather_id,my_id;
 | 
						||
  lbrother_id = 13;
 | 
						||
  pather_id = 0;
 | 
						||
  prova.put(ABMD_CODDITTA,"00001");
 | 
						||
  prova.put(ABMD_ANNO,"1996");
 | 
						||
  prova.put(ABMD_CODPDB,"001");
 | 
						||
  prova.put(ABMD_TIPOBIL,"E2");
 | 
						||
  prova.put(ABMD_CODCBL,"000000000200");
 | 
						||
  _inter_tree->insert_node(prova,lbrother_id,pather_id,my_id,IMMESSO);
 | 
						||
}
 | 
						||
 | 
						||
/**************************************************************************************************/
 | 
						||
//  TAnalisi_bil
 | 
						||
/**************************************************************************************************/
 | 
						||
 | 
						||
 | 
						||
TAnalisi_bil::TAnalisi_bil()
 | 
						||
             :TAlbero_AB(LF_ANALISI)
 | 
						||
{
 | 
						||
  _voci   = new TLocalisamfile(LF_VOCI);
 | 
						||
  _analisi= new TLocalisamfile(LF_ANALISI);
 | 
						||
  _relaz  = NULL;
 | 
						||
  _ana    = NULL;
 | 
						||
  _inter_tree = new TLocal_relana3();
 | 
						||
  _newrec = new TRectype(LF_RELANA);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
TAnalisi_bil::~TAnalisi_bil() 
 | 
						||
{
 | 
						||
  delete _voci;
 | 
						||
  delete _ana;
 | 
						||
  delete _relaz;
 | 
						||
  delete _analisi;
 | 
						||
  delete _newrec;
 | 
						||
}
 | 
						||
 | 
						||
void TAnalisi_bil::put_headkey(TRectype &rec) const
 | 
						||
{
 | 
						||
    rec.put(ABAN_CODAN, get(ABAN_CODAN));
 | 
						||
}
 | 
						||
//Scrive tutto il contenuto della cache sull'isamfile, aggiungendo, modificando
 | 
						||
//o rimuovendo i nodi necessari
 | 
						||
 | 
						||
int TAlbero_AB::commit_body() const
 | 
						||
{                         
 | 
						||
  TRectype rec(_inter_tree->current().num());
 | 
						||
  TLocalisamfile filebody(rec.num());
 | 
						||
  TString status;
 | 
						||
  //Estraggo un nodo per volta basandomi sull'assoc_array degli status  
 | 
						||
  while (_inter_tree->dirty_nodes() > 0)                                              
 | 
						||
  {
 | 
						||
    TNumeric_id id;
 | 
						||
//    int prova = _inter_tree->dirty_nodes(); //solo debug
 | 
						||
    
 | 
						||
    id=ID_NULLO;
 | 
						||
    rec= _inter_tree->extract_dirtynode(id, status);
 | 
						||
    put_headkey(rec);
 | 
						||
    
 | 
						||
    //Ho un rectype e uno status node
 | 
						||
    if (status == NODO_AGGIUNTO)
 | 
						||
    { 
 | 
						||
      if (filebody.curr().empty())
 | 
						||
      { //Se il cursor di relana <20> posizionato in modo errato:
 | 
						||
        //lo sistemo sull'ultimo record del file
 | 
						||
        //DOMANDA: - Perch<63> ???
 | 
						||
        //TENATATIVO DI RISPOSTA: - Quando l'ultima azione effettuata (prima di questa "aggiunta") <20> la rimozione 
 | 
						||
        //  dell'ultimo record probabilmente (ma non sono sicuro) il cursore non <20> posizionato (o forse
 | 
						||
        //  <20> posizionato in modo errato come ad es. dopo l'EOF, visto che l'EOF era sull'ultimo record rimosso)
 | 
						||
        //  e quando eseguo un tentativo di scrittura da un errore di chiave duplicata (anche se questa non esiste);
 | 
						||
        //  In tutti gli altri casi (quando l'ultima azione <20> stata una write o una rewrite o una remove di un record
 | 
						||
        //  che non sia l'ultimo) questo problema non esiste.
 | 
						||
        //RISPOSTA ESATTA: - Bho !!!
 | 
						||
        filebody.last();
 | 
						||
      }      
 | 
						||
      int err = filebody.write(rec);
 | 
						||
      if (err != NOERR)
 | 
						||
        return err;
 | 
						||
    }
 | 
						||
    if (status == NODO_MODIFICATO)
 | 
						||
    {            
 | 
						||
      int err = filebody.rewrite(rec);
 | 
						||
      if (err != NOERR)
 | 
						||
        return err;
 | 
						||
    }
 | 
						||
    if (status == NODO_RIMOSSO)
 | 
						||
    {
 | 
						||
      filebody.read(rec); //Devo leggere sul file per posizionare il cursore: stesso motivo di prima
 | 
						||
      int err = filebody.remove(rec);
 | 
						||
      if (err != NOERR)
 | 
						||
        return err;
 | 
						||
    }
 | 
						||
    // In tutti gli altri casi il nodo non viene modificato
 | 
						||
  }
 | 
						||
  return NOERR;
 | 
						||
}
 | 
						||
 | 
						||
//Leggo il "corpo" del record
 | 
						||
int TAnalisi_bil::read_body(bool lock_struct )
 | 
						||
{
 | 
						||
  if (_relaz) 
 | 
						||
  {
 | 
						||
    if (_relaz->codtab() != get(ABAN_CODAN))
 | 
						||
    {
 | 
						||
      delete _relaz;
 | 
						||
      delete _ana;
 | 
						||
      _relaz=NULL;
 | 
						||
      _ana=NULL;
 | 
						||
    }
 | 
						||
  }
 | 
						||
  if (!_relaz) 
 | 
						||
  {
 | 
						||
    _relaz  = new TAlbero_relvoci(get(ABAN_CODAN));
 | 
						||
    _ana    = new TAlbero_relana(get(ABAN_CODAN));
 | 
						||
  }
 | 
						||
  // carica la copia locale
 | 
						||
  TNumeric_id id_relana; 
 | 
						||
  if (lock_struct)
 | 
						||
    _relaz->lock();
 | 
						||
 | 
						||
  if (_relaz->goto_root())
 | 
						||
  {
 | 
						||
    if (_ana->goto_root())
 | 
						||
      id_relana=_ana->curr().get_real(ABRA_ID);
 | 
						||
    naviga_relazioni(id_relana,ID_NULLO,ID_NULLO);
 | 
						||
  }
 | 
						||
  //_inter_tree->write_cache(); //solo per debug
 | 
						||
  //prova_inserimento();  //Solo debug per inserimento diretto di un nodo
 | 
						||
  return 0;
 | 
						||
}
 | 
						||
 | 
						||
//Naviga l'albero delle relazioni
 | 
						||
void TAnalisi_bil::naviga_relazioni(const TNumeric_id & begin_relana, const TNumeric_id & id_prec,const TNumeric_id & id_padre)
 | 
						||
{
 | 
						||
  TNumeric_id id_relana, currid;
 | 
						||
  TNodeId key_rel;
 | 
						||
  _relaz->curr_id(key_rel);
 | 
						||
  _newrec = sincronizza_relana(begin_relana, id_relana);
 | 
						||
  currid=_newrec->get_real(ABRA_ID);
 | 
						||
  _inter_tree->insert_node(*_newrec,id_prec,id_padre,currid);
 | 
						||
  
 | 
						||
  //Controllo se c'<27> un fratello di rel_voci
 | 
						||
  if (_relaz->has_rbrother())
 | 
						||
  {
 | 
						||
    if (_relaz->goto_rbrother())
 | 
						||
    { //Fratello di rel_voci trovato
 | 
						||
      //Cerco un fratello anche su rel_ana: se non si trova c'<27> una inconsistenza nei dati
 | 
						||
      //fra relvoci e relana
 | 
						||
      TNumeric_id frat_relana;
 | 
						||
      naviga_relazioni(frat_relana,currid , id_padre);
 | 
						||
      _relaz->goto_node(key_rel);
 | 
						||
    }
 | 
						||
    else
 | 
						||
    {//Fratello di rel_voci non  trovato
 | 
						||
      error_box ("Errore di consistenza nei dati di relvoci: <20> previsto un fratello ma non <20> stato trovato");
 | 
						||
    }  
 | 
						||
  } // Il record di _relaz non ha un fratello destro
 | 
						||
  
 | 
						||
  _inter_tree->link_succ_zero(currid);  //Azzera link fratello
 | 
						||
  
 | 
						||
  
 | 
						||
  if (_relaz->goto_firstson())
 | 
						||
  { //Figlio di rel_voci trovato
 | 
						||
    //Cerco il figlio di rel_ana: se non si trova c'<27> una inconsistenza nei dati
 | 
						||
    //fra relvoci e relana
 | 
						||
    if (id_relana!=ID_NULLO)
 | 
						||
    { 
 | 
						||
      _ana->goto_id(id_relana);
 | 
						||
      if (_ana->goto_firstson())
 | 
						||
        id_relana=_ana->curr().get_real(ABRA_ID);
 | 
						||
    } 
 | 
						||
    naviga_relazioni(id_relana, ID_NULLO , currid);
 | 
						||
  }//Se non trovo il figlio di una relazione, potrebbe essere una foglia di un ramo dell'albero
 | 
						||
  _relaz->goto_node(key_rel); //Per risalire al nodo che mi ha chiamato in relvoci
 | 
						||
  
 | 
						||
  _inter_tree->link_son_zero(currid); //azzera link filgio
 | 
						||
}
 | 
						||
                       
 | 
						||
//Sincronizza relana con quello che trovo in relaz: relaz <20> navigato da naviga_relazioni
 | 
						||
TRectype *TAnalisi_bil::sincronizza_relana(const TNumeric_id &begin_relana,TNumeric_id &id_relana)
 | 
						||
{
 | 
						||
  id_relana=begin_relana;
 | 
						||
  TToken_string key;
 | 
						||
  // ****** caricamento array dei nodi di questo livello dall'isam file LF_RELANA ....
 | 
						||
  if (!_relaz->has_lbrother())
 | 
						||
  {                                                  
 | 
						||
    key = _relaz->curr().get(ABRL_CODVC);
 | 
						||
    if (id_relana != ID_NULLO)
 | 
						||
    { //carica l'array con i nodi componenti di questa voce (analisi)
 | 
						||
      _ana->goto_id(id_relana);
 | 
						||
      _nodifratelli.destroy();
 | 
						||
      do
 | 
						||
      {
 | 
						||
        TString codvc =_ana->curr().get(ABRA_CODVC);
 | 
						||
        TString idcomp =_ana->curr().get(ABRA_NCOMP);
 | 
						||
        _nodifratelli.setkey(codvc,idcomp,key);
 | 
						||
        _nodifratelli.add(key,_ana->curr());
 | 
						||
      } while (_ana->has_rbrother() && _ana->goto_rbrother());
 | 
						||
    }
 | 
						||
  }
 | 
						||
  
 | 
						||
  // ****** ... ricerca il nodo letto da LF_RELVOCI sull'array del livello ...
 | 
						||
  // rintraccia il record di relana sull'array 
 | 
						||
  TString codvc = _relaz->curr().get(ABRL_CODVC);
 | 
						||
  TString idcomp = _relaz->curr().get(ABRL_IDCOMP);
 | 
						||
  if (_nodifratelli.find1stkey(codvc,idcomp, key))
 | 
						||
  {
 | 
						||
    *_newrec = ((TRectype &)_nodifratelli[key]);
 | 
						||
    _nodifratelli.mark_used(key); //segna il record nell'array come utilizzato
 | 
						||
    id_relana=_newrec->get_real(ABRA_ID);
 | 
						||
  }
 | 
						||
  else
 | 
						||
  {//Il record viene rigenerato con i dati minimi per ripristinare l'integrit<69> degli archivi
 | 
						||
    _newrec->zero(); //Azzero l'archivio
 | 
						||
    //Lo riempio con i dati basilari
 | 
						||
    _newrec->put(ABRA_CODAN,get(ABAN_CODAN));
 | 
						||
    _newrec->put(ABRA_ID,ID_NULLO);                 
 | 
						||
    _newrec->put(ABRA_TIPOCOD,_relaz->curr().get(ABRL_TIPOCOD));
 | 
						||
    _newrec->put(ABRA_CODVC,_relaz->curr().get(ABRL_CODCOMP));
 | 
						||
    _newrec->put(ABRA_NCOMP,_relaz->curr().get(ABRL_IDCOMP));
 | 
						||
    id_relana = ID_NULLO; // Serve per eseguire correttamente la new_id
 | 
						||
    _newrec->put(ABRA_ID,_ana->new_id(id_relana)); //Questa <20> stata spostata alla insert_node
 | 
						||
    _inter_tree->set_status_node(_newrec->get_real(ABRA_ID),NODO_AGGIUNTO);
 | 
						||
  }
 | 
						||
  
 | 
						||
  // ******** ...scarica l'array
 | 
						||
  if (!_relaz->has_rbrother()) // ultimo figlio
 | 
						||
  {
 | 
						||
    TObject *o;
 | 
						||
    _nodifratelli.restart();
 | 
						||
    while ((o = _nodifratelli.get()) != NULL)
 | 
						||
    {
 | 
						||
      if (!_nodifratelli.used(o))  //Marca il record in pi<70> su relana come da cancellare
 | 
						||
        _inter_tree->set_status_node(((TRectype *)o)->get_real(ABRA_ID),NODO_RIMOSSO);
 | 
						||
    }
 | 
						||
  }
 | 
						||
  return _newrec;
 | 
						||
}
 | 
						||
 | 
						||
// ************
 | 
						||
// array interno
 | 
						||
 | 
						||
void TAnalisi_bil::TArray_fratelli::setkey(const char *tipocod, const char *codvc, TToken_string &key) const
 | 
						||
{           
 | 
						||
  key.cut(0);
 | 
						||
  key.add(tipocod);
 | 
						||
  key.add(codvc);
 | 
						||
}
 | 
						||
 | 
						||
bool TAnalisi_bil::TArray_fratelli::find1stkey(const char *tipocod, const char *codvc, TToken_string &key)
 | 
						||
{
 | 
						||
  TObject *o;
 | 
						||
  setkey(tipocod,codvc,key);
 | 
						||
  o = objptr((const char *)key);
 | 
						||
  return ((o != NULL) && (!((TRectype *)o)->empty()));
 | 
						||
}
 | 
						||
 | 
						||
void TAnalisi_bil::TArray_fratelli::mark_used(const char *key)
 | 
						||
{ 
 | 
						||
  ((TRectype *)objptr(key))->zero();  // segna il record nell'array come utilizzato
 | 
						||
}
 | 
						||
 | 
						||
bool TAnalisi_bil::TArray_fratelli::used(TObject *o)
 | 
						||
{ 
 | 
						||
  return ((TRectype *)o)->empty();
 | 
						||
}
 | 
						||
 | 
						||
// Questa rudimentale funzione serve solo per il debug: richiama direttamente
 | 
						||
//la insert_node di un saldo IMMETTENDO un nuovo nodo nella struttura.
 | 
						||
// Cambiando i parametri id posiziona il nodo in posizione diverse
 | 
						||
void TAnalisi_bil::prova_inserimento()
 | 
						||
{ 
 | 
						||
  TRectype prova(LF_RELANA);
 | 
						||
  TNumeric_id lbrother_id,pather_id,my_id;
 | 
						||
  lbrother_id = 0;
 | 
						||
  pather_id = 14;
 | 
						||
  prova.put(ABRA_CODAN,"A1");
 | 
						||
  _inter_tree->insert_node(prova,lbrother_id,pather_id,my_id,IMMESSO);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**************************************************************************************************/
 | 
						||
// TLocal_relana3 & TLocal_balance3
 | 
						||
/**************************************************************************************************/
 | 
						||
 | 
						||
TLocal_relana3::TLocal_relana3() :
 | 
						||
  TAlbero_locale(LF_RELANA)
 | 
						||
{
 | 
						||
}                       
 | 
						||
 | 
						||
TLocal_relana3::~TLocal_relana3()
 | 
						||
{}
 | 
						||
 | 
						||
TLocal_balance3::TLocal_balance3() :
 | 
						||
  TAlbero_locale(LF_MOVDETT)
 | 
						||
{
 | 
						||
}                       
 | 
						||
 | 
						||
TLocal_balance3::~TLocal_balance3()
 | 
						||
{}                       
 | 
						||
 | 
						||
void TLocal_balance3::put_headkey(TRectype & node) 
 | 
						||
{
 | 
						||
  TToken_string s(get_headkey());
 | 
						||
  node.put(ABMD_CODDITTA,s.get());
 | 
						||
  node.put(ABMD_ANNO,s.get());
 | 
						||
  node.put(ABMD_CODPDB,s.get());
 | 
						||
  node.put(ABMD_TIPOBIL,s.get());
 | 
						||
  node.put(ABMD_CODCBL,s.get());
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**************************************************************************************************/
 | 
						||
// TAlbero_locale
 | 
						||
/**************************************************************************************************/
 | 
						||
TAlbero_locale::TAlbero_locale(int filenum)
 | 
						||
{
 | 
						||
// versione definitiva:
 | 
						||
//  _currnode = new TRectype(filenum);
 | 
						||
//  _local_cache = new TRWrecord_cache(new TIsamtempfile(filenum,"",TRUE,TRUE));
 | 
						||
 | 
						||
// debug mods:
 | 
						||
  _currnode = new TRectype(filenum);
 | 
						||
  if (filenum==LF_RELANA)
 | 
						||
    _f= new TIsamtempfile(filenum,"/com/relana",FALSE,FALSE);
 | 
						||
  else
 | 
						||
    _f= new TIsamtempfile(filenum,"/com/movdett",FALSE,FALSE);
 | 
						||
  _local_cache = new TRWrecord_cache(_f);
 | 
						||
 | 
						||
  //zero(); // resetta l'albero locale
 | 
						||
}                       
 | 
						||
 | 
						||
TAlbero_locale::~TAlbero_locale()
 | 
						||
{                    
 | 
						||
  delete _local_cache;
 | 
						||
  delete _f;
 | 
						||
}                       
 | 
						||
 | 
						||
 | 
						||
//Estraggo un nodo: se specifico l'id in ingresso estrae il nodo con quell'id;
 | 
						||
//altrimenti ne sceglie uno a caso tra quelli "dirty" 
 | 
						||
//in output ho il record e le informazioni per sapere cosa fare di quel record
 | 
						||
TRectype TAlbero_locale::extract_dirtynode(TNumeric_id &id, TString &status)
 | 
						||
{ 
 | 
						||
  TToken_string key = get_headkey();
 | 
						||
  TRectype rec(current());
 | 
						||
  THash_object *row_status;
 | 
						||
  
 | 
						||
  if (id == ID_NULLO)
 | 
						||
  { //Gestione interna
 | 
						||
    _status_node.restart();
 | 
						||
    row_status = _status_node.get_hashobj();
 | 
						||
    status = (TString&)row_status->obj();
 | 
						||
    id = (TNumeric_id)row_status->key();
 | 
						||
  }
 | 
						||
  else
 | 
						||
  {
 | 
						||
    status = *(TString*)_status_node.objptr(id.string());
 | 
						||
  }
 | 
						||
  
 | 
						||
  //Posso accedere alla cache (con la get) solo se il nodo non
 | 
						||
  //<2F> stato rimosso: se il nodo <20> stato rimosso, non sar<61> presente
 | 
						||
  //nella cache, e quindi la get di un nodo che non esiste <20> un record
 | 
						||
  //vuoto; questo record vuoto causer<65> errori nel momento in cui chiamer<65>
 | 
						||
  //la flush per il distruttore; devo quindi evitare questo 
 | 
						||
  //caso l'utilizzo della get
 | 
						||
  if (status != NODO_RIMOSSO)  
 | 
						||
  {
 | 
						||
    key.add(id.string()); //La chiave <20> completamente ricostruita per la ricerca sulla cache
 | 
						||
    rec = _local_cache->get(key); //passo la chiave (formata da codtab e id) e ritorna il rectype
 | 
						||
  }
 | 
						||
  else
 | 
						||
  { //Riempio manualmente il record che deve essere rimosso: inserisco solo la chiave
 | 
						||
    //rec.put(ABRA_CODAN, ??? );
 | 
						||
    rec.put(id_fieldname(),id.string());
 | 
						||
  }
 | 
						||
  //A questo punto il record <20> completo e so gi<67> quale operazione devo compierci sopra
 | 
						||
  
 | 
						||
  //Questa parte serve per gestire l'assoc_array degli status
 | 
						||
  if ((rec.empty()) && (status != NODO_RIMOSSO))
 | 
						||
  { //Chiave non trovata: la chiave ricercata non <20> presente nella cache
 | 
						||
    fatal_box("Errore nella lettura della cache o nella costruzione del record.");
 | 
						||
  }
 | 
						||
  _status_node.remove(id.string());
 | 
						||
  return rec; //Ritorno un Trectype e passo la stauts node
 | 
						||
}
 | 
						||
 | 
						||
//Setta lo stato del nodo: cio<69> decide che cosa dovr<76> fare con questo nodo
 | 
						||
void TAlbero_locale::set_status_node(const TNumeric_id &id, const char *status)
 | 
						||
{
 | 
						||
  // STATUS A priorit<69> assoluta e rimane sempre A
 | 
						||
  // STATUS M priorit<69> su R ma non su A
 | 
						||
  // STATUS R priorit<69> sul vuoto ma non su M o A
 | 
						||
  // STATUS vuoto: nessuna priorit<69>
 | 
						||
 | 
						||
  // In TInser_albero::insert_node  posso capire solo A o M ma non R
 | 
						||
  // In TAlbero_relana::sincronizza posso capire solo R ma non A e M
 | 
						||
  TString key = id.string();
 | 
						||
  const TString *prec_status = (const TString *)_status_node.objptr(key);
 | 
						||
  
 | 
						||
  if (!prec_status)
 | 
						||
  { //Elemento ancora non presente nell'array
 | 
						||
    _status_node.add(key,TString (status));
 | 
						||
  }
 | 
						||
  else
 | 
						||
  { //Elemento gi<67> inserito
 | 
						||
    if (stricmp(status,NODO_AGGIUNTO)==0 && (*prec_status != NODO_AGGIUNTO))
 | 
						||
      _status_node.add(key,TString (status),TRUE); //Forzo la sovrascrittura in ogni caso
 | 
						||
    
 | 
						||
    if (stricmp(status,NODO_MODIFICATO)== 0 && (*prec_status != NODO_AGGIUNTO))
 | 
						||
    {
 | 
						||
      //Se il nodo era gi<67> inserito e il suo flag <20> diverso da NODO_AGGIUNTO
 | 
						||
      //allora devo settare che questo nodo <20> modificato (se non lo <20> ancora)
 | 
						||
      if (*prec_status != NODO_MODIFICATO)
 | 
						||
      {
 | 
						||
        _status_node.add(key,TString (status),TRUE); //Forzo la sovrascrittura in ogni caso
 | 
						||
      } 
 | 
						||
      // Arriva qui se il nodo <20> inserito e il flag era gi<67> stato settato da una
 | 
						||
      //operazione precedente a NODO_MODIFICATO
 | 
						||
    }
 | 
						||
    
 | 
						||
    if (stricmp(status,NODO_RIMOSSO)==0 && *prec_status != NODO_RIMOSSO)
 | 
						||
    { //Sto rimuovento un nodo che prima era stato modificato
 | 
						||
      CHECK(FALSE,"Sto rimuovendo un nodo che probabilmente non <20> da rimuovere");
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
//Restituisce un nuovo id
 | 
						||
TNumeric_id &TAlbero_locale::new_id(TNumeric_id id)
 | 
						||
{
 | 
						||
  if (id == ID_NULLO)
 | 
						||
    _last_insert_id=_last_insert_id+1;
 | 
						||
  else
 | 
						||
    _last_insert_id = max(_last_insert_id,id);
 | 
						||
  return _last_insert_id;
 | 
						||
}
 | 
						||
 | 
						||
//Inserisce il nodo (che ho in ingresso) nella struttura ad albero doppiamente linkata
 | 
						||
//di relana aggiornando tutti i link
 | 
						||
bool TAlbero_locale::insert_node(TRectype & node,const TNumeric_id id_prec, const TNumeric_id id_padre, TNumeric_id id, const char flag_it)
 | 
						||
{
 | 
						||
  const char* dirty_value=NODO_MODIFICATO;
 | 
						||
  TNumeric_id id_succ;
 | 
						||
  if (id == ID_NULLO) 
 | 
						||
  {
 | 
						||
    id = new_id(id); 
 | 
						||
    set_status_node(id,NODO_AGGIUNTO);
 | 
						||
  } 
 | 
						||
  else
 | 
						||
    new_id(id);
 | 
						||
 | 
						||
  //Cerco il mio fratello precedente 
 | 
						||
  if (id_prec != ID_NULLO)
 | 
						||
  { //Aggiorno il successivo del mio precedente dicendogli che il suo successivo sono io
 | 
						||
    goto_node(id_prec);
 | 
						||
    if (_currnode->get_real(idsucc_fieldname()) != id)
 | 
						||
    {// Il nodo <20> effettivamente modificato: apporto le modifiche e setto lo status
 | 
						||
     // Se il nodo <20> IMMESSO devo mantenere il link con il successivo per mantenere integra la struttutra
 | 
						||
      if (flag_it == IMMESSO)
 | 
						||
      {
 | 
						||
        id_succ = _currnode->get_real(idsucc_fieldname());
 | 
						||
      }
 | 
						||
       _currnode->put(idsucc_fieldname(),id.string());
 | 
						||
      _local_cache->put(*_currnode);
 | 
						||
      set_status_node(id_prec,dirty_value); //Setto l'eventuale flag di array modificato per il fratello
 | 
						||
    }
 | 
						||
  }
 | 
						||
  else
 | 
						||
  { //Se non ho il mio precedente, allora o sono una radice principale o divento il primo figlio:
 | 
						||
    if (id_padre != ID_NULLO)
 | 
						||
    { //Sono un primo figlio: rintraccio mio padre e gli dico che il suo primo figlio ora, sono io
 | 
						||
      goto_node(id_padre);
 | 
						||
      if(_currnode->get_real(idson_fieldname()) != id)
 | 
						||
      {// Il nodo <20> effettivamente modificato: apporto le modifiche e setto lo status
 | 
						||
        if (flag_it == IMMESSO)
 | 
						||
        {
 | 
						||
          id_succ = _currnode->get_real(idson_fieldname());
 | 
						||
        }
 | 
						||
        _currnode->put(idson_fieldname(),id.string());
 | 
						||
        _local_cache->put(*_currnode);
 | 
						||
        set_status_node(id_padre,dirty_value); //Setto l'eventuale flag di array modificato per il padre
 | 
						||
      }
 | 
						||
    } // Sono una radice principale e quindi sono orfana di padre: posso essere solo un nuovo nodo  IMMESSO direttamente
 | 
						||
    else
 | 
						||
    {
 | 
						||
      if (flag_it == IMMESSO)
 | 
						||
      {
 | 
						||
        goto_root();
 | 
						||
        id_succ = _currnode->get_real(id_fieldname());
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
  
 | 
						||
  // Se il nodo <20> immesso controllo che ci sia un link al successivo da ripristinare
 | 
						||
  if (flag_it == IMMESSO)
 | 
						||
  {
 | 
						||
    if (id_succ != ID_NULLO)
 | 
						||
    { //Esiste un nodo che prima era il successivo dell'attuale mio precedente: devo modificarlo per
 | 
						||
      //dirgli che ora il suo precedente sono io
 | 
						||
      goto_node(id_succ);
 | 
						||
      // Il mio successivo deve essere effettivamente modificato
 | 
						||
      if (_currnode->get_real(idprec_fieldname()) != id)
 | 
						||
      {
 | 
						||
        _currnode->put(idprec_fieldname(),id.string());
 | 
						||
        _local_cache->put(*_currnode);
 | 
						||
        set_status_node(id_succ,dirty_value); //Setto l'eventuale flag di array modificato per il fratello
 | 
						||
      }// Altrimenti il nodo non <20> da modificare
 | 
						||
      
 | 
						||
      //Aggiorno me stesso
 | 
						||
      node.put(idsucc_fieldname(),id_succ.string());
 | 
						||
      node.put(idson_fieldname(),ID_NULLO);
 | 
						||
      //set_current(node);
 | 
						||
    }
 | 
						||
  }
 | 
						||
  //Ora aggiorno me stesso: solo quella parte che rimane da aggiornare
 | 
						||
  put_headkey(node);
 | 
						||
  node.put(id_fieldname(),id.string());
 | 
						||
  if ((node.get_real(idprec_fieldname()) != id_prec) ||
 | 
						||
      (node.get_real(idfather_fieldname()) != id_padre))
 | 
						||
  {// Il nodo <20> effettivamente modificato: apporto le modifiche e setto lo status
 | 
						||
    node.put(idprec_fieldname(),id_prec.string());
 | 
						||
    node.put(idfather_fieldname(),id_padre.string());
 | 
						||
    set_status_node(id,dirty_value);
 | 
						||
  }
 | 
						||
  _local_cache->put(node);
 | 
						||
  goto_node(node);
 | 
						||
  return TRUE;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
//Questa funzione aggiorna i link dei "parenti" di un nodo che sta per essere rimosso
 | 
						||
bool TAlbero_locale::delete_node(const TNumeric_id &id)
 | 
						||
{                 
 | 
						||
  
 | 
						||
  TRectype parente(current());
 | 
						||
  TNumeric_id id_padre, id_figlio, id_prec, id_succ;
 | 
						||
  
 | 
						||
  goto_node(id);
 | 
						||
  TToken_string key;
 | 
						||
  
 | 
						||
//  id = _currnode->get_real(ABRA_ID);
 | 
						||
  id_padre = _currnode->get_real(idfather_fieldname());
 | 
						||
  id_figlio = _currnode->get_real(idson_fieldname());
 | 
						||
  id_prec = _currnode->get_real(idprec_fieldname());
 | 
						||
  id_succ = _currnode->get_real(idsucc_fieldname());
 | 
						||
  
 | 
						||
  //Ricerco il padre per modificare il suo primo figlio, solo se io sono il suo primo figlio
 | 
						||
  if (id_padre != ID_NULLO)
 | 
						||
  {
 | 
						||
    key.cut(0);
 | 
						||
    key = get_headkey();
 | 
						||
    key.add(id_padre.string());
 | 
						||
    parente=_local_cache->get(key); //padre
 | 
						||
    if (parente.get(idson_fieldname()) == id.string())
 | 
						||
    { //Il nodo che sta per essere rimosso <20> il primo figlio di un padre
 | 
						||
      parente.put(idson_fieldname(),id_succ.string());  //Aggiorno il padre
 | 
						||
      set_status_node(id_padre, NODO_MODIFICATO);       //Aggiorno lo status
 | 
						||
      _local_cache->put(parente);
 | 
						||
    }
 | 
						||
  }
 | 
						||
  
 | 
						||
  //Ricerco il mio fratello precedente per dirgli che io non sono pi<70>
 | 
						||
  //suo fratello successivo, e gli dico anche quale sar<61> il suo successivo
 | 
						||
  if (id_prec != ID_NULLO)
 | 
						||
  {                     
 | 
						||
    key.cut(0);
 | 
						||
    key = get_headkey();
 | 
						||
    key.add(id_prec.string());
 | 
						||
    parente=_local_cache->get(key); //fratello sinistro
 | 
						||
    parente.put(idsucc_fieldname(),id_succ.string()); //Assegno al mio fratello sinistro il mio fratello destro
 | 
						||
    set_status_node(id_prec,NODO_MODIFICATO);         //Aggiorno lo status
 | 
						||
    _local_cache->put(parente);
 | 
						||
  }
 | 
						||
  
 | 
						||
  //Dico a mio fratello successivo chi il suo precedente non sono pi<70> io,
 | 
						||
  //e gli dico che il suo precedente <20> il MIO precedente
 | 
						||
  if (id_succ != ID_NULLO)
 | 
						||
  {                         
 | 
						||
    key.cut(0);
 | 
						||
    key = get_headkey();
 | 
						||
    key.add(id_succ.string());
 | 
						||
    parente=_local_cache->get(key); //fratello destro
 | 
						||
    parente.put(idprec_fieldname(),id_prec.string()); //Assegno al mio fratello destro il mio fratello sinistro
 | 
						||
    set_status_node(id_succ,NODO_MODIFICATO);         //Aggiorno lo status
 | 
						||
    _local_cache->put(parente);
 | 
						||
  }
 | 
						||
  
 | 
						||
  //I miei vicini mi hanno gi<67> escluso: non sono pi<70> raggiungibile
 | 
						||
  //Ricostruisco la chiave
 | 
						||
  //Elimino i miei link dai fratelli
 | 
						||
  key.cut(0);
 | 
						||
  key = get_headkey();
 | 
						||
  key.add(id.string());
 | 
						||
  //node.put(ABRA_IDPADRE,ID_NULLO);
 | 
						||
  _currnode->put(idprec_fieldname(),ID_NULLO);
 | 
						||
  _currnode->put(idsucc_fieldname(),ID_NULLO);
 | 
						||
  _local_cache->put(*_currnode);
 | 
						||
  //Elimino i miei figli
 | 
						||
  
 | 
						||
  TNumeric_id nextnode_id;
 | 
						||
  if (id_prec != ID_NULLO)
 | 
						||
  {
 | 
						||
    nextnode_id = id_prec;
 | 
						||
  }
 | 
						||
  else
 | 
						||
  {
 | 
						||
    if (id_succ != ID_NULLO)
 | 
						||
    {
 | 
						||
      nextnode_id = id_succ;
 | 
						||
    }
 | 
						||
    else
 | 
						||
    {
 | 
						||
      if (id_padre != ID_NULLO)
 | 
						||
      {
 | 
						||
        nextnode_id = id_padre;
 | 
						||
      }
 | 
						||
      else
 | 
						||
      {
 | 
						||
        CHECK (FALSE,"NON SO DOVE POSIZIONARMI !!!!");
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
  remove_subtree(nextnode_id);
 | 
						||
  //A questo punto l'assoc_array degli status <20> gi<67> completamente aggiornato
 | 
						||
  //write_cache();  //Solo per debug
 | 
						||
  return TRUE;
 | 
						||
}
 | 
						||
 | 
						||
void TAlbero_locale::zero()
 | 
						||
{
 | 
						||
  delete_tree();  // cancella l'albero
 | 
						||
  _status_node.destroy(); 
 | 
						||
  _currnode->put(id_fieldname(),ID_NULLO);
 | 
						||
}
 | 
						||
 | 
						||
bool TAlbero_locale::delete_tree()
 | 
						||
{
 | 
						||
  //write_cache();
 | 
						||
  goto_root();
 | 
						||
  remove_subtree(ID_NULLO); //Non eliminando il link coi fratelli della radice, remove_subtree naviga tutto l'albero
 | 
						||
  return TRUE;
 | 
						||
}
 | 
						||
 | 
						||
//Questa funzione elimina il nodo corrente e tutti i nodi sottostanti 
 | 
						||
bool TAlbero_locale::remove_subtree(const TNumeric_id return_id)
 | 
						||
{
 | 
						||
  TNumeric_id myself_id;
 | 
						||
  //cerco il figlio
 | 
						||
  if (has_son())
 | 
						||
  {                
 | 
						||
    myself_id = _currnode->get_real(id_fieldname());
 | 
						||
    goto_firstson();
 | 
						||
    remove_subtree(myself_id);
 | 
						||
  }
 | 
						||
  
 | 
						||
  //cerco il fratello
 | 
						||
  if (has_rbrother())
 | 
						||
  {
 | 
						||
    myself_id = _currnode->get_real(id_fieldname());
 | 
						||
    goto_rbrother();
 | 
						||
    remove_subtree(myself_id);
 | 
						||
  }                              
 | 
						||
  TNumeric_id id = _currnode->get(id_fieldname());
 | 
						||
  
 | 
						||
  //Questa parte esegue la gestione dell'assoc_array degli stati
 | 
						||
  //in modo tale da mantenerlo allineato con il contenuto della cache
 | 
						||
  TString *status;
 | 
						||
  status = (TString*)_status_node.objptr(id.string());
 | 
						||
  if ((status == NULL) || (*status != NODO_AGGIUNTO))
 | 
						||
  {//In questi due casi il nodo esisteva gi<67> nel file originario
 | 
						||
    _status_node.add(id.string(),(TString)NODO_RIMOSSO,TRUE); //Forzo la sovrascrittura in ogni caso
 | 
						||
  }
 | 
						||
  else
 | 
						||
  {//Nel caso di NODO_AGGIUNTO
 | 
						||
    _status_node.remove(id.string());
 | 
						||
  }
 | 
						||
  
 | 
						||
  if (return_id != ID_NULLO)
 | 
						||
    goto_node(return_id);
 | 
						||
  else
 | 
						||
    _currnode->put(id_fieldname(),ID_NULLO);
 | 
						||
 | 
						||
  return TRUE;
 | 
						||
}
 | 
						||
 | 
						||
bool TAlbero_locale::has_son()
 | 
						||
{
 | 
						||
  return (_currnode->get_real(idson_fieldname()) != ID_NULLO);
 | 
						||
}
 | 
						||
 | 
						||
bool TAlbero_locale::goto_firstson()
 | 
						||
{
 | 
						||
  goto_node(_currnode->get_real(idson_fieldname()));
 | 
						||
  return TRUE;
 | 
						||
}
 | 
						||
 | 
						||
bool TAlbero_locale::has_rbrother()
 | 
						||
{
 | 
						||
  return (_currnode->get_real(idsucc_fieldname()) != ID_NULLO);
 | 
						||
}
 | 
						||
 | 
						||
bool TAlbero_locale::goto_rbrother()
 | 
						||
{
 | 
						||
  goto_node(_currnode->get_real(idsucc_fieldname()));
 | 
						||
  return TRUE;
 | 
						||
}
 | 
						||
 | 
						||
bool TAlbero_locale::goto_root()
 | 
						||
{ //Il _current sar<61> posizionato sull'ultimo nodo che <20> stato visitato
 | 
						||
  if (current().get_real(id_fieldname())==ID_NULLO)
 | 
						||
    return FALSE;
 | 
						||
  TToken_string key;
 | 
						||
  TNumeric_id id_prec, id_padre;
 | 
						||
  key=get_headkey();
 | 
						||
  key.add(_currnode->get(id_fieldname()));
 | 
						||
  do
 | 
						||
  {
 | 
						||
    *_currnode = _local_cache->get(key);
 | 
						||
    id_prec = _currnode->get_real(idprec_fieldname());
 | 
						||
    id_padre = _currnode->get_real(idfather_fieldname());
 | 
						||
    if (id_prec != ID_NULLO)
 | 
						||
    {
 | 
						||
      key.cut(0);
 | 
						||
      key=get_headkey();
 | 
						||
      key.add(id_prec.string());
 | 
						||
    }
 | 
						||
    else
 | 
						||
    {
 | 
						||
      if (id_padre != ID_NULLO)
 | 
						||
      {
 | 
						||
        key.cut(0);
 | 
						||
        key=get_headkey();
 | 
						||
        key.add(id_padre.string());
 | 
						||
      }
 | 
						||
    }
 | 
						||
  } while (id_prec != ID_NULLO || id_padre != ID_NULLO);
 | 
						||
  return TRUE;
 | 
						||
}
 | 
						||
 | 
						||
void TAlbero_locale::goto_node(const TNumeric_id id)
 | 
						||
{
 | 
						||
  TToken_string key;
 | 
						||
  key=get_headkey();
 | 
						||
  key.add(id.string());
 | 
						||
  *_currnode = _local_cache->get(key);
 | 
						||
}
 | 
						||
 | 
						||
void TAlbero_locale::link_succ_zero(const TNumeric_id currid) 
 | 
						||
{ // Se il nodo <20> da rimuovere non eseguo nessuna operazione: potrebbe causre problemi alla cache
 | 
						||
  TString *status = get_status_node(currid);
 | 
						||
  if ((status != NULL) && (*status != NODO_RIMOSSO))
 | 
						||
  { //Posiziono il nodo che sto aggiornando
 | 
						||
    goto_node(currid);
 | 
						||
    //Tento di posizionarmi sul fratello se questo pu<70> avere senso
 | 
						||
    if (current().get_real(idsucc_fieldname()) != ID_NULLO)
 | 
						||
    { //Secondo il link, ci dovrebbe essere un fratello
 | 
						||
      status = get_status_node(current().get_real(idsucc_fieldname()));
 | 
						||
      if ((status != NULL) && (*status != NODO_RIMOSSO))
 | 
						||
      { // Entro qui solo se il nodo esite, e lo status <20> stato fissato ad un valore diverso dal RIMOSSO
 | 
						||
        goto_node(current().get_real(idsucc_fieldname()));
 | 
						||
        if (current().empty())
 | 
						||
        { // Se per<65> non esiste modifico il record
 | 
						||
          goto_node(currid);
 | 
						||
          current().put(idsucc_fieldname(),ID_NULLO);
 | 
						||
          _local_cache->put(current());
 | 
						||
          set_status_node(currid,NODO_MODIFICATO);
 | 
						||
        }
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
void TAlbero_locale::link_son_zero(const TNumeric_id currid) 
 | 
						||
{ // Se il nodo <20> da rimuovere non eseguo nessuna operazione: potrebbe causre problemi alla cache
 | 
						||
  TString *status = get_status_node(currid);
 | 
						||
  if ((status != NULL) && (*status != NODO_RIMOSSO))
 | 
						||
  { //Posiziono il nodo che sto aggiornando
 | 
						||
    goto_node(currid);
 | 
						||
    //Tento di posizionarmi sul fratello se questo pu<70> avere senso
 | 
						||
    if (current().get_real(idson_fieldname()) != ID_NULLO)
 | 
						||
    { //Secondo il link, ci dovrebbe essere un fratello
 | 
						||
      status = get_status_node(current().get_real(idson_fieldname()));
 | 
						||
      if ((status != NULL) && (*status != NODO_RIMOSSO))
 | 
						||
      { // Entro qui solo se il nodo esite, e lo status <20> stato fissato ad un valore diverso dal RIMOSSO
 | 
						||
        goto_node(current().get_real(idson_fieldname()));
 | 
						||
        if (current().empty())
 | 
						||
        { // Se per<65> non esiste modifico il record
 | 
						||
          goto_node(currid);
 | 
						||
          current().put(idson_fieldname(),ID_NULLO);
 | 
						||
          _local_cache->put(current());
 | 
						||
          set_status_node(currid,NODO_MODIFICATO);
 | 
						||
        }
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
/**************************************************************************************************/
 | 
						||
//  TAlbero_relana
 | 
						||
/**************************************************************************************************/
 | 
						||
//In questo costruttore cerco di capire anche quale <20> l'ultimo id utilizzato
 | 
						||
TAlbero_relana::TAlbero_relana( const char * tabcode)
 | 
						||
{
 | 
						||
  _codtab=tabcode;
 | 
						||
  _relana=new TLocalisamfile(LF_RELANA);
 | 
						||
  _relana->put(ABRA_CODAN,_codtab);
 | 
						||
  _relana->put(ABRA_ID,MAX_ID_REL);
 | 
						||
  
 | 
						||
  //Trova l'ultimo id usato in relana: DA COMPLETARE !!!
 | 
						||
  int err = _relana->read(_isgteq);  //Codifica errori in TIsamerr
 | 
						||
  if (err == NOERR)
 | 
						||
  { // Ho trovato il primo della tabella successiva: leggendo il precedente
 | 
						||
    // ho l'ultimo record dalla tabella cercata
 | 
						||
    _relana->prev();
 | 
						||
    if (_relana->get(ABRA_CODAN) != _codtab)
 | 
						||
    { // Non esiste la tabella
 | 
						||
      ; //_last_id viene lasciato a 0
 | 
						||
    }
 | 
						||
    _last_id = _relana->get_real(ABRA_ID);
 | 
						||
  }
 | 
						||
  
 | 
						||
  if (err == _isemptyfile)
 | 
						||
  { //Il file <20> vuoto
 | 
						||
    ;//_last_id viene lasciato a 0
 | 
						||
  }
 | 
						||
  
 | 
						||
  if (err == _iseof)
 | 
						||
  { // La tabella successiva non esiste: provo a leggere l'ultimo record
 | 
						||
    _relana->last();
 | 
						||
    if (_relana->get(ABRA_CODAN) != _codtab)
 | 
						||
    { //Tabella non trovata
 | 
						||
      ; //_last_id viene lasciato a 0
 | 
						||
    }
 | 
						||
    //Tabella trovata: prendo l'id dell'ultimo record
 | 
						||
    _last_id = _relana->get_real(ABRA_ID);
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
TAlbero_relana::~TAlbero_relana() 
 | 
						||
{
 | 
						||
  delete _relana;
 | 
						||
}
 | 
						||
 
 | 
						||
//Incremento l'id per dare il primo id disponibile
 | 
						||
TNumeric_id & TAlbero_relana::new_id(TNumeric_id id)
 | 
						||
{      
 | 
						||
  if (id == ID_NULLO)
 | 
						||
    _last_id = _last_id+1;
 | 
						||
  else
 | 
						||
    _last_id = max(_last_id,id);
 | 
						||
  return _last_id;
 | 
						||
}
 | 
						||
 | 
						||
//Posiziona relana sul record voluto
 | 
						||
bool TAlbero_relana::goto_id(const TNumeric_id &id)
 | 
						||
{
 | 
						||
  _relana->put(ABRA_CODAN,_codtab);
 | 
						||
  _relana->put(ABRA_ID,id);
 | 
						||
  if (_relana->read() == NOERR)
 | 
						||
    return TRUE;
 | 
						||
  return FALSE; //Non sono riuscito a posizionarmi sul nodo
 | 
						||
} 
 | 
						||
 
 | 
						||
bool TAlbero_relana::lock()
 | 
						||
{
 | 
						||
  //Potrebbe usare come parametro _codtab
 | 
						||
  return TRUE;
 | 
						||
} 
 | 
						||
 | 
						||
void TAlbero_relana::unlock()
 | 
						||
{                                        
 | 
						||
  //Potrebbe usare come parametro _codtab
 | 
						||
  return ;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca la radice di relana
 | 
						||
bool TAlbero_relana::goto_root()
 | 
						||
{
 | 
						||
  _relana->put(ABRA_CODAN,_codtab); //Ricerca il codice della tabella: <20> l'unica cosa che conosco
 | 
						||
  //No so nulla sull'id
 | 
						||
  _relana->read(_isgteq); //Leggo la prima chiave che si avvicina a quella specificata
 | 
						||
  if (_relana->get(ABRA_CODAN) == _codtab)
 | 
						||
  {       
 | 
						||
    while (has_father())
 | 
						||
    { 
 | 
						||
      goto_father();
 | 
						||
    } // Ho raggiunto il primo livello
 | 
						||
    while (has_lbrother())
 | 
						||
    {
 | 
						||
      goto_lbrother();
 | 
						||
    }// Ho raggiunto la radice
 | 
						||
    return TRUE;
 | 
						||
  }        
 | 
						||
  //Non ho trovato una voce con codice tabella richiesta
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
//Dice se un nodo di relana ha il primo figlio
 | 
						||
bool TAlbero_relana::has_son() const
 | 
						||
{                                         
 | 
						||
  return _relana->get_real(ABRA_IDFIGLIO)!=ID_NULLO;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il primo filglio di un nodo di relana
 | 
						||
bool TAlbero_relana::goto_firstson()
 | 
						||
{                                         
 | 
						||
  TNumeric_id id_figlio(_relana->get_real(ABRA_IDFIGLIO));
 | 
						||
  if (id_figlio > 0)
 | 
						||
  { //Ci deve essere un figlio: lo cerco
 | 
						||
    //Il CODAN deve rimanere uguale a quello del padre
 | 
						||
    _relana->put(ABRA_ID,_relana->get(ABRA_IDFIGLIO));
 | 
						||
    if (_relana->read() == NOERR)
 | 
						||
      return TRUE;  //Figlio trovato con successo
 | 
						||
  }
 | 
						||
  //Non c'<27> un figlio: non si dovrebbe mai verificare visto che
 | 
						||
  //si entra in questa funzione solo quando <20> previsto che ci sia un figlio.
 | 
						||
  return FALSE;
 | 
						||
}          
 | 
						||
 | 
						||
//Dice se un nodo di relana ha un fratello destro
 | 
						||
bool TAlbero_relana::has_rbrother() const 
 | 
						||
{              
 | 
						||
  return _relana->get_real(ABRA_IDSUCC) != ID_NULLO;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il fratello destro di un nodo di relana
 | 
						||
bool TAlbero_relana::goto_rbrother() 
 | 
						||
{
 | 
						||
  TNumeric_id id_fratello(_relana->get_real(ABRA_IDSUCC));
 | 
						||
  if (id_fratello > 0)
 | 
						||
  { //Ci deve essere un fratello: lo cerco
 | 
						||
    //Il CODAN deve rimanere uguale a quello del fratello precedente
 | 
						||
    _relana->put(ABRA_ID,_relana->get(ABRA_IDSUCC));
 | 
						||
    if (_relana->read() == NOERR)
 | 
						||
      return TRUE; //Fratello trovato con successo
 | 
						||
  }
 | 
						||
  //Non c'<27> un fratello: non si dovrebbe mai verificare visto che
 | 
						||
  //si entra in questa funzione solo quando <20> previsto che ci sia un fratello.
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
//Dice se un nodo di relana ha un padre
 | 
						||
bool TAlbero_relana::has_father() const 
 | 
						||
{ 
 | 
						||
  return _relana->get_real(ABRA_IDPADRE) != ID_NULLO;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il padre del nodo di relana
 | 
						||
bool TAlbero_relana::goto_father()
 | 
						||
{
 | 
						||
  _relana->put(ABRA_ID,_relana->get(ABRA_IDPADRE));
 | 
						||
  if (_relana->read() != NOERR)
 | 
						||
    CHECK (FALSE,"ERRORE DI PADRE"); //*!*!*!*! DA gestire
 | 
						||
  else
 | 
						||
    return TRUE;
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 
 | 
						||
//Ritrona il nodo corrente di relana
 | 
						||
TObject *TAlbero_relana::curr_node() const 
 | 
						||
{
 | 
						||
  return &_relana->curr();
 | 
						||
}
 | 
						||
 | 
						||
//Dice se un nodo di relana ha un fratello sinistro
 | 
						||
bool TAlbero_relana::has_lbrother() const 
 | 
						||
{
 | 
						||
  return _relana->get_real(ABRA_IDPREC) != ID_NULLO;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il fratello sinistro di un nodo di relana
 | 
						||
bool TAlbero_relana::goto_lbrother()
 | 
						||
{
 | 
						||
  TNumeric_id id_fratello(_relana->get_real(ABRA_IDPREC));
 | 
						||
  if (id_fratello > 0)
 | 
						||
  {//Ci deve essere un fratello: lo cerco
 | 
						||
    //Il CODAN deve rimanere uguale a quello del fratello successivo
 | 
						||
    _relana->put(ABRA_ID,_relana->get(ABRA_IDPREC));
 | 
						||
    if (_relana->read() == NOERR)
 | 
						||
      return TRUE; //Fratello trovato con successo
 | 
						||
  }
 | 
						||
  //ERRORE !!!
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
void TAlbero_relana::node2id(const TObject * node,TNodeId & id) const
 | 
						||
{
 | 
						||
  id.format("%ld",(long)_relana->recno()); 
 | 
						||
}
 | 
						||
 | 
						||
/**************************************************************************************************/
 | 
						||
//  TAlbero_relvoci
 | 
						||
/**************************************************************************************************/
 | 
						||
TAlbero_relvoci::TAlbero_relvoci(const char * tabcode) 
 | 
						||
{
 | 
						||
  _codtab=tabcode;
 | 
						||
  _relvoci=new TLocalisamfile(LF_RELVOCI);
 | 
						||
}
 | 
						||
 | 
						||
TAlbero_relvoci::~TAlbero_relvoci() 
 | 
						||
{
 | 
						||
  delete _relvoci;
 | 
						||
}
 | 
						||
  
 | 
						||
//Ricerca la radice di relvoci
 | 
						||
bool TAlbero_relvoci::goto_root()
 | 
						||
{
 | 
						||
  _relvoci->put(ABRL_TIPOCOD,TIPO_ANALISI);             // La radice ha tipocod = "A"
 | 
						||
  TString codtab = _codtab;                           //Mi serve per eseguire una formattazione senza modificare _codtab
 | 
						||
  _relvoci->put(ABRL_CODVC,codtab.right_just(10,' '));  //Inserisco il codice della tabella su cui sto lavorando
 | 
						||
  //No so nulla sull'id
 | 
						||
  _relvoci->read(_isgteq);                              //Leggo la prima chiave che si avvicina a quella specificata
 | 
						||
  if ((_relvoci->get(ABRL_TIPOCOD) == TIPO_ANALISI) || (_relvoci->get(ABRL_CODVC) == _codtab))
 | 
						||
  {
 | 
						||
    while (has_lbrother())
 | 
						||
    {
 | 
						||
      goto_lbrother();
 | 
						||
    }
 | 
						||
    return TRUE;
 | 
						||
  }                                                     
 | 
						||
  //Non ho trovato una voce di analisi richiesta o
 | 
						||
  //non ho trovato una voce con codice tabella richiesta
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
bool TAlbero_relvoci::lock()
 | 
						||
{
 | 
						||
  //Potrebbe usare come parametro _codtab
 | 
						||
  return TRUE;
 | 
						||
} 
 | 
						||
 | 
						||
 | 
						||
void TAlbero_relvoci::unlock()
 | 
						||
{                                        
 | 
						||
  //Potrebbe usare come parametro _codtab
 | 
						||
  return ;
 | 
						||
}
 | 
						||
 | 
						||
//Dice se il nodo ha un primo figlio; DA DEFINIRE
 | 
						||
bool TAlbero_relvoci::has_son() const
 | 
						||
{
 | 
						||
  CHECK(FALSE,"!!!");
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il primo figlio di un nodo di relvoci
 | 
						||
bool TAlbero_relvoci::goto_firstson()
 | 
						||
{               
 | 
						||
  TRecnotype temp_pos = _relvoci->recno();
 | 
						||
  
 | 
						||
  _relvoci->put(ABRL_TIPOCOD,TIPO_VOCE); //Il tipo codice del filgio di una radice o di un livello inferiore <20> sempre "V"
 | 
						||
  TString controllo_comp = _relvoci->get(ABRL_CODCOMP);
 | 
						||
  _relvoci->put(ABRL_CODVC,controllo_comp); //Setto il figlio
 | 
						||
  //Non posso sapere nulla sull'id corretto: lo azzero perch<63> il record contiene gi<67> l'id del record letto in precedenza
 | 
						||
  //e leggo la prima chiave che assomiglia a quella settata
 | 
						||
  _relvoci->put(ABRL_IDCOMP,0);
 | 
						||
  _relvoci->read(_isgteq); //Leggo la prima chiave che si avvicina a quella specificata
 | 
						||
  
 | 
						||
  if ((_relvoci->get(ABRL_TIPOCOD) == TIPO_VOCE) && (_relvoci->get(ABRL_CODVC) == controllo_comp))
 | 
						||
  {//Ho trovato un figlio, ma non so se <20> proprio il primo figlio:
 | 
						||
   //se non sono sul primo figlio navigo all'indietro
 | 
						||
    while (has_lbrother())
 | 
						||
    {
 | 
						||
      goto_lbrother();
 | 
						||
    }
 | 
						||
    return TRUE;
 | 
						||
  }
 | 
						||
  else
 | 
						||
  { //Non ho trovato il filgio: mi riposiziono alla posizione precedente
 | 
						||
    //Questo non rappresenta un errore perch<63> potrebbe essere 
 | 
						||
    //la foglia di un ramo dell'albero
 | 
						||
    _relvoci->readat(temp_pos);
 | 
						||
    return FALSE;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
//Dice su un nodo di relvoci ha un fratello destro
 | 
						||
bool TAlbero_relvoci::has_rbrother() const 
 | 
						||
{                                 
 | 
						||
  return _relvoci->get_long(ABRL_NEXTCOMP) != ID_NULLO;  
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il fratello destro di un nodo di relvoci
 | 
						||
bool TAlbero_relvoci::goto_rbrother()
 | 
						||
{             
 | 
						||
  //Il tipocod di un fratello deve essere uguale a quello attuale
 | 
						||
  //Il codice voce di un fratello deve essere uguale a quella attuale
 | 
						||
  _relvoci->put(ABRL_IDCOMP,_relvoci->get(ABRL_NEXTCOMP)); //Assegno all'id il successivo
 | 
						||
  if (_relvoci->read() == NOERR)
 | 
						||
    return TRUE; //Fratello trovato
 | 
						||
  else
 | 
						||
    return FALSE; //Fratello non trovato
 | 
						||
}
 | 
						||
 | 
						||
//Dice se un nodo di relvoci ha un fratello sinistro
 | 
						||
bool TAlbero_relvoci::has_lbrother() const 
 | 
						||
{                                 
 | 
						||
  return _relvoci->get_long(ABRL_PREVCOMP) != ID_NULLO;  
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il fratello sinistro di un nodo di relvoci
 | 
						||
bool TAlbero_relvoci::goto_lbrother()
 | 
						||
{             
 | 
						||
  //Il tipocod di un fratello deve essere uguale a quello attuale
 | 
						||
  //Il codice voce di un fratello deve essere uguale a quella attuale
 | 
						||
  _relvoci->put(ABRL_IDCOMP,_relvoci->get(ABRL_PREVCOMP)); //Assegno all'id il successivo
 | 
						||
  if (_relvoci->read() == NOERR)
 | 
						||
    return TRUE; //Fratello trovato
 | 
						||
  else
 | 
						||
    return FALSE; //Fratello non trovato
 | 
						||
}  
 | 
						||
 | 
						||
//Ritorna il nodo corrente di relvoci
 | 
						||
TObject *TAlbero_relvoci::curr_node() const 
 | 
						||
{
 | 
						||
  return &_relvoci->curr();
 | 
						||
}
 | 
						||
 | 
						||
void TAlbero_relvoci::node2id(const TObject * node,TNodeId &  id) const
 | 
						||
{
 | 
						||
  id.format("%ld",_relvoci->recno()); 
 | 
						||
}
 | 
						||
 | 
						||
/**************************************************************************************************/
 | 
						||
//  TAlbero_movdett
 | 
						||
/**************************************************************************************************/
 | 
						||
TAlbero_movdett::TAlbero_movdett( const char * tabcode)
 | 
						||
{
 | 
						||
  _codtab = tabcode;
 | 
						||
  _movdett=new TLocalisamfile(LF_MOVDETT);
 | 
						||
  
 | 
						||
/*  _movdett->put(ABMD_CODDITTA,_codtab.get(0));
 | 
						||
  _movdett->put(ABMD_ANNO,_codtab.get(1));
 | 
						||
  _movdett->put(ABMD_CODPDB,_codtab.get(2));
 | 
						||
  _movdett->put(ABMD_TIPOBIL,_codtab.get(3));
 | 
						||
  _movdett->put(ABMD_CODCBL,_codtab.get(4));
 | 
						||
  _movdett->put(ABMD_ID,MAX_ID_MOVDETT);
 | 
						||
 | 
						||
  //Trova l'ultimo id usato in MOVDETT: DA COMPLETARE !!!
 | 
						||
  int err = _movdett->read(_isgteq);  //Codifica errori in TIsamerr
 | 
						||
  if (err == NOERR)
 | 
						||
  { // Ho trovato il primo della "categoria" successiva: leggendo il precedente
 | 
						||
    // ho l'ultimo record cercato
 | 
						||
    _movdett->prev();
 | 
						||
    TString16 format =_movdett->get(ABMD_CODDITTA);
 | 
						||
    TToken_string controllo = format.right_just(5,'0');
 | 
						||
    controllo.add(_movdett->get(ABMD_ANNO));
 | 
						||
    controllo.add(_movdett->get(ABMD_CODPDB));
 | 
						||
    controllo.add(_movdett->get(ABMD_TIPOBIL));
 | 
						||
    controllo.add(_movdett->get(ABMD_CODCBL));
 | 
						||
    
 | 
						||
    if (controllo != _codtab)
 | 
						||
    { // Non esiste la tabella
 | 
						||
      ; //_last_id viene lasciato a 0
 | 
						||
    }
 | 
						||
    _last_id = _movdett->get_real(ABMD_ID);
 | 
						||
  }
 | 
						||
  
 | 
						||
  if (err == _isemptyfile)
 | 
						||
  { //Il file <20> vuoto
 | 
						||
    ;//_last_id viene lasciato a 0
 | 
						||
  }
 | 
						||
  
 | 
						||
  if (err == _iseof)
 | 
						||
  { // La tabella successiva non esiste: provo a leggere l'ultimo record
 | 
						||
    _movdett->last();
 | 
						||
    TString16 format =_movdett->get(ABMD_CODDITTA);
 | 
						||
    TToken_string controllo = format.right_just(5,'0');
 | 
						||
    controllo.add(_movdett->get(ABMD_ANNO));
 | 
						||
    controllo.add(_movdett->get(ABMD_CODPDB));
 | 
						||
    controllo.add(_movdett->get(ABMD_TIPOBIL));
 | 
						||
    controllo.add(_movdett->get(ABMD_CODCBL));
 | 
						||
    if (controllo != _codtab)
 | 
						||
    { //Tabella non trovata
 | 
						||
      ; //_last_id viene lasciato a 0
 | 
						||
    }
 | 
						||
    //Tabella trovata: prendo l'id dell'ultimo record
 | 
						||
    _last_id = _movdett->get_real(ABMD_ID);
 | 
						||
  } */
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
//Posiziona relana sul record voluto
 | 
						||
bool TAlbero_movdett::goto_id(const TNumeric_id &id)
 | 
						||
{
 | 
						||
  _movdett->put(ABMD_CODDITTA,_codtab);
 | 
						||
  _movdett->put(ABMD_ID,id);
 | 
						||
  if (_movdett->read() == NOERR)
 | 
						||
    return TRUE;
 | 
						||
  return FALSE; //Non sono riuscito a posizionarmi sul nodo
 | 
						||
} 
 | 
						||
 
 | 
						||
//Ricerca la radice di relana
 | 
						||
bool TAlbero_movdett::goto_root()
 | 
						||
{
 | 
						||
  _movdett->put(ABMD_CODDITTA,_codtab.get(0));
 | 
						||
  _movdett->put(ABMD_ANNO,_codtab.get(1));
 | 
						||
  _movdett->put(ABMD_CODPDB,_codtab.get(2));
 | 
						||
  _movdett->put(ABMD_TIPOBIL,_codtab.get(3));
 | 
						||
  _movdett->put(ABMD_CODCBL,_codtab.get(4));
 | 
						||
  //No so nulla sull'id
 | 
						||
  _movdett->read(_isgteq); //Leggo la prima chiave che si avvicina a quella specificata
 | 
						||
  TString fctrl = _movdett->get(ABMD_CODDITTA);
 | 
						||
  TToken_string controllo = fctrl.right_just(5,'0');
 | 
						||
  controllo.add(_movdett->get(ABMD_ANNO));
 | 
						||
  controllo.add(_movdett->get(ABMD_CODPDB));
 | 
						||
  controllo.add(_movdett->get(ABMD_TIPOBIL));
 | 
						||
  controllo.add(_movdett->get(ABMD_CODCBL));
 | 
						||
  
 | 
						||
  if (controllo == _codtab)
 | 
						||
  {       
 | 
						||
    while (has_father())
 | 
						||
    { 
 | 
						||
      goto_father();
 | 
						||
    } // Ho raggiunto il primo livello
 | 
						||
    while (has_lbrother())
 | 
						||
    {
 | 
						||
      goto_lbrother();
 | 
						||
    }// Ho raggiunto la radice
 | 
						||
    return TRUE;
 | 
						||
  }        
 | 
						||
  //Non ho trovato una voce con codice tabella richiesta
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
//Dice se un nodo di relana ha il primo figlio
 | 
						||
bool TAlbero_movdett::has_son() const
 | 
						||
{                                         
 | 
						||
  return _movdett->get_real(ABMD_IDFIGLIO)!=ID_NULLO;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il primo filglio di un nodo di relana
 | 
						||
bool TAlbero_movdett::goto_firstson()
 | 
						||
{                                         
 | 
						||
  TNumeric_id id_figlio(_movdett->get_real(ABMD_IDFIGLIO));
 | 
						||
  if (id_figlio > 0)
 | 
						||
  { //Ci deve essere un figlio: lo cerco
 | 
						||
    //Il CODAN deve rimanere uguale a quello del padre
 | 
						||
    _movdett->put(ABMD_ID,_movdett->get(ABMD_IDFIGLIO));
 | 
						||
    if (_movdett->read() == NOERR)
 | 
						||
      return TRUE;  //Figlio trovato con successo
 | 
						||
  }
 | 
						||
  //Non c'<27> un figlio: non si dovrebbe mai verificare visto che
 | 
						||
  //si entra in questa funzione solo quando <20> previsto che ci sia un figlio.
 | 
						||
  return FALSE;
 | 
						||
}          
 | 
						||
 | 
						||
//Dice se un nodo di relana ha un fratello destro
 | 
						||
bool TAlbero_movdett::has_rbrother() const 
 | 
						||
{              
 | 
						||
  return _movdett->get_real(ABMD_IDSUCC) != ID_NULLO;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il fratello destro di un nodo di relana
 | 
						||
bool TAlbero_movdett::goto_rbrother() 
 | 
						||
{
 | 
						||
  TNumeric_id id_fratello(_movdett->get_real(ABMD_IDSUCC));
 | 
						||
  if (id_fratello > 0)
 | 
						||
  { //Ci deve essere un fratello: lo cerco
 | 
						||
    //Il CODAN deve rimanere uguale a quello del fratello precedente
 | 
						||
    _movdett->put(ABMD_ID,_movdett->get(ABMD_IDSUCC));
 | 
						||
    if (_movdett->read() == NOERR)
 | 
						||
      return TRUE; //Fratello trovato con successo
 | 
						||
  }
 | 
						||
  //Non c'<27> un fratello: non si dovrebbe mai verificare visto che
 | 
						||
  //si entra in questa funzione solo quando <20> previsto che ci sia un fratello.
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
//Dice se un nodo di relana ha un padre
 | 
						||
bool TAlbero_movdett::has_father() const 
 | 
						||
{ 
 | 
						||
  return _movdett->get_real(ABMD_IDPADRE) != ID_NULLO;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il padre del nodo di relana
 | 
						||
bool TAlbero_movdett::goto_father()
 | 
						||
{
 | 
						||
  _movdett->put(ABMD_ID,_movdett->get(ABMD_IDPADRE));
 | 
						||
  if (_movdett->read() != NOERR)
 | 
						||
    CHECK (FALSE,"ERRORE DI PADRE"); //*!*!*!*! DA gestire
 | 
						||
  else
 | 
						||
    return TRUE;
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 
 | 
						||
//Ritrona il nodo corrente di relana
 | 
						||
TObject *TAlbero_movdett::curr_node() const 
 | 
						||
{
 | 
						||
  return &_movdett->curr();
 | 
						||
}
 | 
						||
 | 
						||
//Dice se un nodo di relana ha un fratello sinistro
 | 
						||
bool TAlbero_movdett::has_lbrother() const 
 | 
						||
{
 | 
						||
  return _movdett->get_real(ABMD_IDPREC) != ID_NULLO;
 | 
						||
}
 | 
						||
 | 
						||
//Ricerca il fratello sinistro di un nodo di relana
 | 
						||
bool TAlbero_movdett::goto_lbrother()
 | 
						||
{
 | 
						||
  TNumeric_id id_fratello(_movdett->get_real(ABMD_IDPREC));
 | 
						||
  if (id_fratello > 0)
 | 
						||
  {//Ci deve essere un fratello: lo cerco
 | 
						||
    //Il CODAN deve rimanere uguale a quello del fratello successivo
 | 
						||
    _movdett->put(ABMD_ID,_movdett->get(ABMD_IDPREC));
 | 
						||
    if (_movdett->read() == NOERR)
 | 
						||
      return TRUE; //Fratello trovato con successo
 | 
						||
  }
 | 
						||
  //ERRORE !!!
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
void TAlbero_movdett::node2id(const TObject * node,TNodeId &  id) const
 | 
						||
{
 | 
						||
  id.format("%ld",_movdett->recno()); 
 | 
						||
}
 |