#include "ablib01.h"
/**************************************************************************************************/
//  TAlbero_AB
/**************************************************************************************************/

TAlbero_AB::TAlbero_AB(int filenum)
             :TRectype(filenum), _inter_tree(NULL), _newrec(NULL)
{            
}

TAlbero_AB::~TAlbero_AB()
{
}

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
{                      
//  _inter_tree->write_cache(); //Solo debug
  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) //Eliminare questa lettura con isop = 0 o isop = 1
  {               
    read_body(FALSE);
    _inter_tree->make_root(saldi);
  }
  _inter_tree->write_cache(); //solo debig
  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);

// E' stata tolta la read_body perch� la readat viene richiamata
// prima di fare una write della relazione: si perdono le modifiche
// effettuate in quanto la read_body ripristina la vecchia situazione

//  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(NULL), _movdett(NULL)
{
  _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 _newrec;
  delete _inter_tree;
  _saldi = NULL;
  _movdett = NULL;
  _newrec = NULL;
  _inter_tree = NULL;
}

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()
{
  TString 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(NULL), _analisi(NULL)
{
  _voci   = new TLocalisamfile(LF_VOCI);
  _analisi= new TLocalisamfile(LF_ANALISI);
  _relaz  = NULL;
  _ana    = NULL;
  _inter_tree = new TLocal_relana3();
  _inter_tree_relvoci = new TAlbero_locale_relvoci();
  
  _record_caradd = new TRecord_caradd();
  _record_colldich = new TRecord_colldich();
  _newrec = new TRectype(LF_RELANA);
  last_id_caradd();
  last_id_colldich();
}


TAnalisi_bil::~TAnalisi_bil() 
{
  delete _newrec;
  delete _inter_tree;
  _analisi = NULL;
  _voci = NULL;
  _newrec = NULL;
  _inter_tree = NULL;
}

void TAnalisi_bil::last_id_caradd()
{
  TLocalisamfile caradd(LF_CARADD);
  if (caradd.last() == NOERR)
  {
    _last_id_caradd = caradd.get_real(ABCA_ID);
  }
  else
  {
    error_box ("Errore nella lettura dell'archivio %CARADD");
  }
}


void TAnalisi_bil::last_id_colldich()
{
  TLocalisamfile coll(LF_COLLDICH);
  if (coll.last() == NOERR)
  {
    _last_id_colldich = coll.get_real(ABCD_ID);
  }
  else
  {
    error_box ("Errore nella lettura dell'archivio %COLLDICH");
  }
}







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)                                              
  {
    TString id = ID_NULLO_STR;
    int prova = _inter_tree->dirty_nodes(); //solo debug

    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 � posizionato in modo errato:
        //lo sistemo sull'ultimo record del file
        //DOMANDA: - Perch� ???
        //TENATATIVO DI RISPOSTA: - Quando l'ultima azione effettuata (prima di questa "aggiunta") � la rimozione 
        //  dell'ultimo record probabilmente (ma non sono sicuro) il cursore non � posizionato (o forse
        //  � 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 � 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 )
{   
  //Vuoto la cache: da eventuali residui
  _inter_tree->clear_cache();
  if (_ana) //Azzero l'id del TAlbero_relana: deve essere ricostruito
    _ana->zero_id();
  if (_relaz) 
  {
    delete _relaz;
    delete _ana;
    _relaz=NULL;
    _ana=NULL;
    
/*    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);
  }
  //prova_inserimento();  //Solo debug per inserimento diretto di un nodo
  _inter_tree->write_cache(); //solo debug
  _inter_tree_relvoci->write_cache(); //solo debug
  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;
  TString key_rel;
  _relaz->curr_id(key_rel);
  _newrec = sincronizza_relana(begin_relana, id_relana);
  currid=_newrec->get_real(ABRA_ID);
  // Inserico relana
  _inter_tree->insert_node(*_newrec,id_prec,id_padre,currid);
  // Inserico relvoci 
  _inter_tree_relvoci->insert_node(_relaz->curr(),ID_NULLO,ID_NULLO,ID_NULLO);
  //Controllo se c'� 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'� 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: � previsto un fratello ma non � 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'� 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 � 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� degli archivi
    TLocalisamfile voc(LF_VOCI);
    _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_CODVC));
    _newrec->put(ABRA_NCOMP,_relaz->curr().get(ABRL_IDCOMP));
    // Prelevo la descrizione di default
    voc.put(ABVC_CODVC,_relaz->curr().get(ABRL_CODCOMP));
    voc.read();
    _newrec->put(ABRA_DESCRIZ,voc.get(ABVC_DESCR));
    id_relana = ID_NULLO; // Serve per eseguire correttamente la new_id
    _newrec->put(ABRA_ID,_ana->new_id(id_relana)); //Questa � stata spostata alla insert_node
    _inter_tree->set_status_node(_newrec->get(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� su relana come da cancellare
        _inter_tree->set_status_node(((TRectype *)o)->get(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
/**************************************************************************************************/
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);
  }

  if (filenum == LF_MOVDETT)
  {
    _f= new TIsamtempfile(filenum,"/com/movdett",FALSE,FALSE);
  }
  
  if (filenum==LF_RELVOCI)
  {
    _f= new TIsamtempfile(filenum,"/com/relvoci",FALSE,FALSE);
  }
  
  _local_cache = new TRWrecord_cache(_f);
  
}                       

TAlbero_locale::~TAlbero_locale()
{               
  delete _currnode;     
  delete _local_cache;
  delete _f;
  _currnode = NULL;
  _local_cache = NULL;
  _f = NULL;
}                       

TAlbero_locale_link::TAlbero_locale_link(int filenum) :
  TAlbero_locale(filenum)
{
}

TAlbero_locale_relvoci::TAlbero_locale_relvoci() :
  TAlbero_locale(LF_RELVOCI)
{
}

TLocal_relana3::TLocal_relana3() :
  TAlbero_locale_link(LF_RELANA)
{ 
  ;
}                       

TLocal_relana3::~TLocal_relana3()
{
}

TLocal_balance3::TLocal_balance3() :
  TAlbero_locale_link(LF_MOVDETT)
{
  ;
}                       

TLocal_balance3::~TLocal_balance3()
{
}                       
                
bool TLocal_relana3::get_description(TString& desc) const
{                  
  desc.cut(0);
//  curr_id(desc); 
  desc << " " << current().get(ABRA_DESCRIZ);
  return desc.not_empty();
}

bool TLocal_relana3::make_root(TBaseisamfile& saldi)
{                        
  TString descriz;
  descriz << "-- " << saldi.get(ABAN_DESCRIZ);
  goto_son_first_level();           //Vado sul primo figlio
  TNumeric_id temp_id = current().get_real(id_fieldname());  // e ne estraggo l'id
  current().zero();                //Vuoto il record
  current().put(id_fieldname(),ID_NULLO);   //ID
  current().put(idson_fieldname(),temp_id); //Assegno il link al primo figlio
  current().put(ABRA_DESCRIZ,descriz);  //Aggiungo la descrizione alla radice
  current_cache().put(current());    //Aggiungo alla cache il record della radice principale
  return TRUE;  
}

bool TLocal_balance3::get_description(TString& desc) const
{  
  curr_id(desc); 
//  desc << "|" << curnode.get(); 
  return desc.not_empty();
}

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

bool TLocal_balance3::make_root(TBaseisamfile& saldi)
{
  goto_son_first_level();           //Vado sul primo figlio
  TNumeric_id temp_id = current().get_real(id_fieldname());  // e ne estraggo l'id
  current().zero();                //Vuoto il record
  current().put(id_fieldname(),ID_NULLO);
  current().put(idson_fieldname(),temp_id); //Assegno il link al primo figlio
  current_cache().put(current());    //Aggiungo alla cache il record della radice principale
  return TRUE;  
}


/**************************************************************************************************/
// TAlbero_locale
/**************************************************************************************************/


//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_link::extract_dirtynode(TString &id, TString &status)
{ 
  TToken_string key = get_headkey();
  TRectype rec(current());
  THash_object *row_status;
  
  if (id == ID_NULLO_STR)
  { //Gestione interna
    _status_node.restart();
    row_status = _status_node.get_hashobj();
    status = (TString&)row_status->obj();
    id = (TString)row_status->key();
  }
  else
  {
    status = *(TString*)_status_node.objptr(id);
  }
  
  //Posso accedere alla cache (con la get) solo se il nodo non
  //� stato rimosso: se il nodo � stato rimosso, non sar� presente
  //nella cache, e quindi la get di un nodo che non esiste � un record
  //vuoto; questo record vuoto causer� errori nel momento in cui chiamer�
  //la flush per il distruttore; devo quindi evitare questo 
  //caso l'utilizzo della get
  if (status != NODO_RIMOSSO)  
  {
    key.add(id); //La chiave � 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);
  }
  //A questo punto il record � completo e so gi� 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 � presente nella cache
    fatal_box("Errore nella lettura della cache o nella costruzione del record.");
  }
  _status_node.remove(id);
  return rec; //Ritorno un Trectype e passo lo stauts node
}

//Setta lo stato del nodo: cio� decide che cosa dovr� fare con questo nodo
void TAlbero_locale::set_status_node(const TString &id, const char *status)
{
  // STATUS A priorit� assoluta e rimane sempre A
  // STATUS M priorit� su R ma non su A
  // STATUS R priorit� sul vuoto ma non su M o A
  // STATUS vuoto: nessuna priorit�

  // 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;
  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� 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� inserito e il suo flag � diverso da NODO_AGGIUNTO
      //allora devo settare che questo nodo � modificato (se non lo � ancora)
      if (*prec_status != NODO_MODIFICATO)
      {
        _status_node.add(key,TString (status),TRUE); //Forzo la sovrascrittura in ogni caso
      } 
      // Arriva qui se il nodo � inserito e il flag era gi� 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
      //message_box("Sto rimuovendo un nodo appena modificato e non ancora registrato");
    }
  }
}

//Restituisce un nuovo id
TNumeric_id &TAlbero_locale_link::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_link::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.string(),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 � effettivamente modificato: apporto le modifiche e setto lo status
     // Se il nodo � 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.string(),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 � 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.string(),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_son_first_level();
        id_succ = _currnode->get_real(id_fieldname());
      }
    }
  }
  
  // Se il nodo � 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.string(),dirty_value); //Setto l'eventuale flag di array modificato per il fratello
      }// Altrimenti il nodo non � 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 � 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.string(),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_link::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());
  
//  if (id_padre != ID_NULLO)
//  {

// Il padre esiste sempre: al limite � la radice stessa
  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 � il primo figlio di un padre
    parente.put(idson_fieldname(),id_succ.string());  //Aggiorno il padre
    if (id_padre != ID_NULLO)
    {
      // Se l'id del padre = ID_NULLO vuol dire che � la radice e non devo settare
      //nessun status perch� questa non dovr� essere salvata nel DB
      set_status_node(id_padre.string(), NODO_MODIFICATO);       //Aggiorno lo status
    }
    _local_cache->put(parente);
  }
//  }
  
  //Ricerco il mio fratello precedente per dirgli che io non sono pi�
  //suo fratello successivo, e gli dico anche quale sar� 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.string(),NODO_MODIFICATO);         //Aggiorno lo status
    _local_cache->put(parente);
  }
  
  //Dico a mio fratello successivo chi il suo precedente non sono pi� io,
  //e gli dico che il suo precedente � 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.string(),NODO_MODIFICATO);         //Aggiorno lo status
    _local_cache->put(parente);
  }
  
  //I miei vicini mi hanno gi� escluso: non sono pi� 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 � gi� completamente aggiornato
  //write_cache();  //Solo per debug
  return TRUE;
}

void TAlbero_locale_link::zero()
{
  delete_tree();  // cancella l'albero
  _status_node.destroy(); 
  _currnode->put(id_fieldname(),ID_NULLO);
}

bool TAlbero_locale_link::delete_tree()
{
  //write_cache();
  goto_son_first_level();
  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_link::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� 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_link::has_son() const
{
  return (_currnode->get_real(idson_fieldname()) != ID_NULLO);
}

bool TAlbero_locale_link::goto_firstson()
{                        
  if (has_son())
  {
    goto_node(_currnode->get_real(idson_fieldname()));
    return TRUE;
  }
  return FALSE;
}


bool TAlbero_locale_link::has_father() const
{
//  return (_currnode->get_real(idfather_fieldname()) != ID_NULLO); 
//Se l'id = 0 allora sono la radice
  return (_currnode->get_real(id_fieldname()) != ID_NULLO);
}

bool TAlbero_locale_link::goto_father()
{                        
  if (has_father())
  {
    goto_node(_currnode->get_real(idfather_fieldname()));
    return TRUE;
  }
  return FALSE;
} 

bool TAlbero_locale_link::has_rbrother() const
{
  return (_currnode->get_real(idsucc_fieldname()) != ID_NULLO);
}

bool TAlbero_locale_link::goto_rbrother()
{
  if (has_rbrother())
  {
    goto_node(_currnode->get_real(idsucc_fieldname()));
    return TRUE;
  }
  return FALSE;
}

bool TAlbero_locale_link::has_lbrother() const
{
  return (_currnode->get_real(idprec_fieldname()) != ID_NULLO);
}

bool TAlbero_locale_link::goto_lbrother()
{
  if (has_lbrother())
  {
    goto_node(_currnode->get_real(idprec_fieldname()));
    return TRUE;
  }
  return FALSE;
}

bool TAlbero_locale_link::goto_root()
{
  if (_currnode->get_real(id_fieldname()) != ID_NULLO )
  { //Significa che non sono sulla radice: sono su un livello sottostante
    goto_son_first_level();
    goto_father();
  }
  return TRUE;
}

bool TAlbero_locale_link::goto_son_first_level()
{ //Il _current sar� posizionato sull'ultimo nodo che � stato visitato
  if (current().get_real(id_fieldname())==ID_NULLO)
  {
    CHECK (FALSE,"Non so dove posizionarmi !*!*!");
    return FALSE;
  }
  TToken_string key;
  TNumeric_id id_prec, id_padre;
  key=get_headkey();
  key.add(_currnode->get(id_fieldname()));
  do
  {
    _currnode->zero();
    *_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_link::goto_node(const TNumeric_id id)
{
/*  if (id != ID_NULLO)
  { */
    TToken_string key;
    key=get_headkey();
    key.add(id.string());
    *_currnode = _local_cache->get(key);
/*  }
  else
    _currnode = NULL;*/
}

void TAlbero_locale_link::link_succ_zero(const TNumeric_id currid) 
{ // Se il nodo � da rimuovere non eseguo nessuna operazione: potrebbe causre problemi alla cache
  TString *status = get_status_node(currid.string());
//  if ((status != NULL) && (*status != NODO_RIMOSSO)) 
  if ((status == NULL) || (*status != NODO_RIMOSSO))
  { //Posiziono il nodo che sto aggiornando
    goto_node(currid);
    //Tento di posizionarmi sul fratello se questo pu� avere senso
    if (current().get_real(idsucc_fieldname()) != ID_NULLO)
    { //Secondo il link, ci dovrebbe essere un fratello
      status = get_status_node(current().get(idsucc_fieldname()));
      if ((status != NULL) && (*status != NODO_RIMOSSO))
      { // Entro qui solo se il nodo esite, e lo status � stato fissato ad un valore diverso dal RIMOSSO
        goto_node(current().get_real(idsucc_fieldname()));
        if (current().empty())
        { // Se per� non esiste modifico il record
          goto_node(currid);
          current().put(idsucc_fieldname(),ID_NULLO);
          _local_cache->put(current());
          set_status_node(currid.string(),NODO_MODIFICATO);
        }
      }
    }
  }
}

void TAlbero_locale_link::link_son_zero(const TNumeric_id currid) 
{ // Se il nodo � da rimuovere non eseguo nessuna operazione: potrebbe causre problemi alla cache
  TString *status = get_status_node(currid.string());
//  if ((status != NULL) && (*status != NODO_RIMOSSO)) 
  if ((status == NULL) || (*status != NODO_RIMOSSO))
  { //Posiziono il nodo che sto aggiornando
    goto_node(currid);
    //Tento di posizionarmi sul fratello se questo pu� avere senso
    if (current().get_real(idson_fieldname()) != ID_NULLO)
    { //Secondo il link, ci dovrebbe essere un fratello
      status = get_status_node(current().get(idson_fieldname()));
      if ((status != NULL) && (*status != NODO_RIMOSSO))
      { // Entro qui solo se il nodo esite, e lo status � stato fissato ad un valore diverso dal RIMOSSO
        goto_node(current().get_real(idson_fieldname()));
        if (current().empty())
        { // Se per� non esiste modifico il record
          goto_node(currid);
          current().put(idson_fieldname(),ID_NULLO);
          _local_cache->put(current());
          set_status_node(currid.string(),NODO_MODIFICATO);
        }
      }
    }
  }
}



/**************************************************************************************************/
//  TAlbero_relana
/**************************************************************************************************/
//In questo costruttore cerco di capire anche quale � 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 � 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: � 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'� 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'� un fratello: non si dovrebbe mai verificare visto che
  //si entra in questa funzione solo quando � 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,TString & 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 � 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� il record contiene gi� 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 � 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� 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,TString &  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 � 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);
  } */
}

TAlbero_movdett::~TAlbero_movdett()
{
  delete _movdett;
}


//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'� un figlio: non si dovrebbe mai verificare visto che
  //si entra in questa funzione solo quando � 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'� un fratello: non si dovrebbe mai verificare visto che
  //si entra in questa funzione solo quando � 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,TString &  id) const
{
  id.format("%ld",_movdett->recno()); 
}



/****************************************/
/* TAlbero_locale_relvoci                 */
/*********************************/
TRectype TAlbero_locale_relvoci::extract_dirtynode(TString &id, TString &status)
{ 
  TToken_string key_rel = (TToken_string&)id;
  TRectype rec(current());
  THash_object *row_status;
  _status_node.restart();
  row_status = _status_node.get_hashobj();
  status = (TString&)row_status->obj();
  key_rel = (TToken_string)row_status->key();
  rec = current_cache().get(key_rel);
  _status_node.remove(key_rel);
  return rec; //Ritorno un Trectype e passo lo stauts node
}























bool TAlbero_locale_relvoci::has_lbrother() const
{
  return current().get_real(ABRL_PREVCOMP) != ID_NULLO; 
}

bool TAlbero_locale_relvoci::goto_lbrother()
{
  TToken_string key_rel;
  key_rel.add(current().get(ABRL_TIPOCOD));
  key_rel.add(current().get(ABRL_CODVC));
  key_rel.add(current().get(ABRL_PREVCOMP));
  return goto_node(key_rel);
}

bool TAlbero_locale_relvoci::has_rbrother() const
{
  return current().get_real(ABRL_NEXTCOMP) != ID_NULLO; 
}

bool TAlbero_locale_relvoci::goto_rbrother()
{
  TToken_string key_rel;
  key_rel.add(current().get(ABRL_TIPOCOD));
  key_rel.add(current().get(ABRL_CODVC));
  key_rel.add(current().get(ABRL_NEXTCOMP));
  return goto_node(key_rel);
}


TNumeric_id TAlbero_locale_relvoci::new_id()
{   
  TNumeric_id max_id;
  
  // Vado sul primo figlio
  while (has_lbrother())
  {
    goto_lbrother();
  }
    
  max_id = current().get_real(ABRL_IDCOMP);
  
  while (has_rbrother())
  {
    goto_rbrother();
    if ((current().get_real(ABRL_IDCOMP)) > max_id)
      max_id = current().get_real(ABRL_IDCOMP);
  }
  return max_id + 1;
}

bool TAlbero_locale_relvoci::insert_node(TRectype &node, const TNumeric_id id_prec, const TNumeric_id id_padre, TNumeric_id id, const char trasf_immes)
{
  if (trasf_immes == IMMESSO)
  {
    TNumeric_id prev_comp = current().get_real(ABRL_IDCOMP);
    TNumeric_id next_comp = current().get_real(ABRL_NEXTCOMP);
    TNumeric_id new_comp;
    new_comp = new_id();    
    
    TToken_string key_rel;
    // Mi riposiziono sul record PRECEDENTE  a quello che sto inserendo
    key_rel.cut(0);
    key_rel.add(current().get(ABRL_TIPOCOD));
    key_rel.add(current().get(ABRL_CODVC));
    key_rel.add(prev_comp.string());
    goto_node(key_rel);
      
    // Creo il nuovo record di relvoci e lo inserisco
    TRectype new_rel(current());
    new_rel.zero();
    new_rel.put(ABRL_TIPOCOD,current().get(ABRL_TIPOCOD));
    new_rel.put(ABRL_CODVC,current().get(ABRL_CODVC));
    new_rel.put(ABRL_IDCOMP,new_comp.string());
    new_rel.put(ABRL_PREVCOMP,prev_comp.string());
    new_rel.put(ABRL_NEXTCOMP,next_comp.string());
    _local_cache->put(new_rel);
    
    // Creo la chiave corretta per lo status node
    key_rel.cut(0);
    key_rel.add(new_rel.get(ABRL_TIPOCOD));
    key_rel.add(new_rel.get(ABRL_CODVC));
    key_rel.add(new_rel.get(ABRL_IDCOMP));
    // Setto lo status 
    set_status_node(key_rel,NODO_AGGIUNTO);
    
    //Aggiorno eventualmente il precedente del nodo che sto inserendo
    if (prev_comp > ID_NULLO)
    {
      key_rel.cut(0);
      key_rel.add(current().get(ABRL_TIPOCOD));
      key_rel.add(current().get(ABRL_CODVC));
      key_rel.add(prev_comp.string());
      goto_node(key_rel);
      current().put(ABRL_NEXTCOMP,new_comp); // Il successivo del precedente sono io !!
      _local_cache->put(*_currnode);
      set_status_node(key_rel,NODO_MODIFICATO);
    }
    
    //Aggiorno eventualmente il successivo
    if (next_comp > ID_NULLO)
    {       
      key_rel.cut(0);
      key_rel.add(current().get(ABRL_TIPOCOD));
      key_rel.add(current().get(ABRL_CODVC));
      key_rel.add(next_comp.string());
      goto_node(key_rel);
      current().put(ABRL_PREVCOMP,new_comp);  // Il precedente del successivo sono io !!
      _local_cache->put(*_currnode);
      set_status_node(key_rel,NODO_MODIFICATO);
    }
    
    //Mi posizione sul nodo di relvoci appena immesso
    key_rel.cut(0);
    key_rel.add(current().get(ABRL_TIPOCOD));
    key_rel.add(current().get(ABRL_CODVC));
    key_rel.add(new_comp.string());
    goto_node(key_rel);
  }
  else
  {
    _local_cache->put(node);
  }
  return TRUE;
}


bool TAlbero_locale_relvoci::delete_node(const TNumeric_id &id_nullo)
{
//  current_cache().put(current());
  TToken_string key = current().get(ABRL_TIPOCOD);
  key.add(current().get(ABRL_CODVC));
  key.add(current().get(ABRL_IDCOMP));
  set_status_node(key,NODO_RIMOSSO);
  
  TNumeric_id id, next, prev;
  id = current().get_real(ABRL_IDCOMP);
  prev = current().get_real(ABRL_PREVCOMP);
  next = current().get_real(ABRL_NEXTCOMP);
    
  // Aggiorno eventualmente il precedente
  if (prev != ID_NULLO)
  { // Costruisco la chiave di ricerca, lo ricerco e gli dico che il suo successivo
    //� diventato il mio successivo, aggiorno
    key.cut(0);
    key.add(current().get(ABRL_TIPOCOD));
    key.add(current().get(ABRL_CODVC));
    key.add(prev.string());
    goto_node(key);
    current().put(ABRL_NEXTCOMP,next);
    current_cache().put(current());
    set_status_node(key,NODO_MODIFICATO);
  }
  
  if (next != ID_NULLO)
  {
    key.cut(0);
    key.add(current().get(ABRL_TIPOCOD));
    key.add(current().get(ABRL_CODVC));
    key.add(next.string());
    goto_node(key);
    current().put(ABRL_PREVCOMP,prev);
    current_cache().put(current());
    set_status_node(key,NODO_MODIFICATO);
  }
  
  return TRUE;
} 
 
bool TAlbero_locale_relvoci::goto_node(const TString &key)
{
  TToken_string key_rel = (TToken_string &) key;
  *_currnode = current_cache().get(key);
  return TRUE;
}

bool TAnalisi_bil::insert_new_node(TToken_string &codice)
{     
    TNumeric_id prec_id = codice.get(0);   
    user_tree()->goto_node(prec_id);
    TToken_string key = user_tree()->current().get(ABRA_TIPOCOD);
    key.add(user_tree()->current().get(ABRA_CODVC));
    key.add(user_tree()->current().get(ABRA_NCOMP));
    
    if (user_tree_voc()->goto_node(key))
    {
      TNumeric_id father_id = user_tree()->current().get(ABRA_IDPADRE);
      TRectype new_node(user_tree()->current());
      new_node.zero();
      //Inserisco il nodo corrispondente nella struttura di relvoci
      user_tree_voc()->insert_node(new_node,ID_NULLO,ID_NULLO,ID_NULLO,IMMESSO);
      
      //Completo le informazioni di new_node con quelle appena inserite in relvoci
      new_node.put(ABRA_TIPOCOD,user_tree_voc()->current().get(ABRL_TIPOCOD));
      new_node.put(ABRA_CODVC,user_tree_voc()->current().get(ABRL_CODVC));
      new_node.put(ABRA_NCOMP,user_tree_voc()->current().get(ABRL_IDCOMP));
      
      user_tree()->insert_node(new_node,prec_id,father_id,ID_NULLO,IMMESSO);
      
      return TRUE;
    }
    return FALSE;
}

bool TAnalisi_bil::remove_node(const TNumeric_id &id)
{                            
  user_tree()->goto_node(id);
  TToken_string key_rel; 
  key_rel.add(user_tree()->current().get(ABRA_TIPOCOD));
  key_rel.add(user_tree()->current().get(ABRA_CODVC));
  key_rel.add(user_tree()->current().get(ABRA_NCOMP));
  
  if (user_tree_voc()->goto_node(key_rel))
  { // Questa delete_node vorrebbe un TNumeric_id; ma siccome non
    // ho nulla del genere, e sono gi� sul nodo da rimuovere,
    // gli passo ID_NULLO e rimuovo il nodo
    user_tree_voc()->delete_node(ID_NULLO);
    user_tree()->delete_node(id);
    user_tree_voc()->write_cache(); //solo debug
    user_tree()->write_cache(); //solo debug
    return TRUE;
  }
  error_box("Sto rimuovendo un nodo di relana che non dovrebbe esserci");
  return FALSE;
}

int TAnalisi_bil::commit_body() const
{
  TAlbero_AB::commit_body();
  
  TRectype rec(_inter_tree_relvoci->current().num());
  TRectype rec_car(_record_caradd->current_rec().num());
  TRectype rec_col(_record_colldich->current_rec().num());
  
  TLocalisamfile file_caradd(rec_car.num());
  TLocalisamfile file_colldich(rec_col.num());
  TLocalisamfile filebody(rec.num());
  
  TString status;

/**********************************************************/
/* PARTE RISERVATA A RELVOCI */  
/**********************************************************/
  
  //Estraggo un nodo per volta basandomi sull'assoc_array degli status  
  while (_inter_tree_relvoci->dirty_nodes() > 0)                                              
  {
    TString id = ID_NULLO_STR;
    int prova = _inter_tree_relvoci->dirty_nodes(); //solo debug
    
    rec= _inter_tree_relvoci->extract_dirtynode(id, status);
    
    //Ho un rectype e uno status node
    if (status == NODO_AGGIUNTO)
    { 
      if (filebody.curr().empty())
      { //Se il cursor di relana � posizionato in modo errato:
        //lo sistemo sull'ultimo record del file
        //DOMANDA: - Perch� ???
        //TENATATIVO DI RISPOSTA: - Quando l'ultima azione effettuata (prima di questa "aggiunta") � la rimozione 
        //  dell'ultimo record probabilmente (ma non sono sicuro) il cursore non � posizionato (o forse
        //  � 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 � 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
  }
    
/**********************************************************/
/* PARTE RISERVATA A CARADD */  
/**********************************************************/

    
  //Estraggo un nodo per volta basandomi sull'assoc_array degli status di caradd
  while (_record_caradd->dirty_nodes() > 0)                                              
  {
    TString id = ID_NULLO_STR;
    
    rec_car= _record_caradd->extract_dirtynode(id, status);
    
    //Ho un rectype e uno status node
    if ((status == NODO_AGGIUNTO) || (status == NODO_MODIFICATO))
    {
      if (file_caradd.curr().empty())
      { //Se il cursor di relana � posizionato in modo errato:
        //lo sistemo sull'ultimo record del file
        file_caradd.last();
      }
      int err = file_caradd.write(rec_car);
      if (err != NOERR)
        return err;
    
      if (status == NODO_MODIFICATO)
      {            
        int err = file_caradd.rewrite(rec_car);
        if (err != NOERR)
          return err;
      }
      if (status == NODO_RIMOSSO)
      {
        file_caradd.read(rec_car); //Devo leggere sul file per posizionare il cursore: stesso motivo di prima
        int err = file_caradd.remove(rec_car);
        if (err != NOERR)
          return err;
      }
      // In tutti gli altri casi il nodo non viene modificato
    }
  }
  
/**********************************************************/
/* PARTE RISERVATA A COLLDICH */  
/**********************************************************/

  
  //Estraggo un nodo per volta basandomi sull'assoc_array degli status di colldich
  while (_record_colldich->dirty_nodes() > 0)                                              
  {
    TString id = ID_NULLO_STR;
    
    rec_col= _record_colldich->extract_dirtynode(id, status);
    
    //Ho un rectype e uno status node
    if ((status == NODO_AGGIUNTO) || (status == NODO_MODIFICATO))
    {
      if (file_colldich.curr().empty())
      { //Se il cursor di relana � posizionato in modo errato:
        //lo sistemo sull'ultimo record del file
        file_colldich.last();
      }
      int err = file_colldich.write(rec_col);
      if (err != NOERR)
        return err;
    
      if (status == NODO_MODIFICATO)
      {            
        int err = file_colldich.rewrite(rec_col);
        if (err != NOERR)
          return err;
      }
      if (status == NODO_RIMOSSO)
      {
        file_colldich.read(rec_col); //Devo leggere sul file per posizionare il cursore: stesso motivo di prima
        int err = file_colldich.remove(rec_col);
        if (err != NOERR)
          return err;
      }
      // In tutti gli altri casi il nodo non viene modificato
    }
  }
  
     
  return NOERR;
}

void TAnalisi_bil::modify_node(TToken_string &codice)
{                
   //Posiziono il nodo sul record selezionato
  TNumeric_id temp_id = codice.get(0);
  user_tree()->goto_node(temp_id);
  //Aggiorno il contenuto del record
  user_tree()->current().put(ABRA_TIPOCOD,codice.get(1));
  user_tree()->current().put(ABRA_CODVC,codice.get(2));
  user_tree()->current().put(ABRA_NCOMP,codice.get(3));
  user_tree()->current().put(ABRA_VOCEINCID,codice.get(4));
  user_tree()->current().put(ABRA_DESCRIZ,codice.get(5));
  user_tree()->current().put(ABRA_USACARADD,codice.get(6));
  user_tree()->current().put(ABRA_IDCARADD,codice.get(8));
  user_tree()->current().put(ABRA_IDCOLDICH,codice.get(9));
    
  // Rintraccio il record corrispondente di relvoci e apporto le modifiche
  TToken_string key_rel;
  key_rel.add(codice.get(1));
  key_rel.add(codice.get(2));
  key_rel.add(codice.get(3));
  user_tree_voc()->goto_node(key_rel);
  user_tree_voc()->current().put(ABRL_CODCOMP,codice.get(7));
        
  // Salvo le modifiche di relana
  user_tree()->current_cache().put(user_tree()->current());
  user_tree()->set_status_node(temp_id.string(),NODO_MODIFICATO);
  user_tree()->write_cache();  //Solo debug
    
  // Salvo le modifiche di relvoci
  user_tree_voc()->current_cache().put(user_tree_voc()->current());
  user_tree_voc()->set_status_node(key_rel,NODO_MODIFICATO);
  user_tree_voc()->write_cache();  //Solo debug
}

/***********************************************************/
/***********************************************************/

TRecord::TRecord(int filenum)

{
// debug mods:
  _currrec = new TRectype(filenum);
  
  if (filenum==LF_COLLDICH)
  {
    _r= new TIsamtempfile(filenum,"/com/colldich",FALSE,FALSE);
  }

  if (filenum == LF_CARADD)
  {
    _r= new TIsamtempfile(filenum,"/com/caradd",FALSE,FALSE);
  }
  
  _local_cache_record = new TRWrecord_cache(_r);
}                       

TRecord::~TRecord()
{               
  delete _currrec;
  delete _local_cache_record;
  delete _r;
  _currrec = NULL;
  _local_cache_record = NULL;
  _r = NULL;
} 

TRectype TRecord::extract_dirtynode(TString &id, TString& status)
{              
  TRectype rec(current_rec());
  THash_object *row_status;
  _status_node_record.restart();
  row_status = _status_node_record.get_hashobj();
  status = (TString&)row_status->obj();
  id = (TString)row_status->key();
  rec = current_cache_record().get(id);
  _status_node_record.remove(id);
  return rec; //Ritorno un Trectype e passo lo stauts node
}     

void TRecord::set_status_node(const TString &id, const char *status)
{
  TString key = id;
  const TString *prec_status = (const TString *)_status_node_record.objptr(key);
  
  if (!prec_status)
  { //Elemento ancora non presente nell'array
    _status_node_record.add(key,TString (status));
  }
  else
  { //Elemento gi� inserito
    if (stricmp(status,NODO_AGGIUNTO)==0 && (*prec_status != NODO_AGGIUNTO))
      _status_node_record.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� inserito e il suo flag � diverso da NODO_AGGIUNTO
      //allora devo settare che questo nodo � modificato (se non lo � ancora)
      if (*prec_status != NODO_MODIFICATO)
      {
        _status_node_record.add(key,TString (status),TRUE); //Forzo la sovrascrittura in ogni caso
      } 
      // Arriva qui se il nodo � inserito e il flag era gi� 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
      //message_box("Sto rimuovendo un nodo appena modificato e non ancora registrato");
    }
  }
}

TRecord_caradd::TRecord_caradd() :
TRecord(LF_CARADD)
{
}
            
TRecord_colldich::TRecord_colldich() :
TRecord(LF_COLLDICH)
{
}