c2d6f1c32d
da testare la parte che riguarda la gestione degli id dei collegamenti a dichiarazione redditi Per le altre maschere sono state modificate esteticamente. Agli altri files sono stati apportate modifiche perchè causavano errori di compilazione a causa delle modifiche apportata alla libreria git-svn-id: svn://10.65.10.50/trunk@6286 c028cbd2-c16b-5b4b-a496-9718f37d4682
2260 lines
68 KiB
C++
Executable File
2260 lines
68 KiB
C++
Executable File
|
|
#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)
|
|
{
|
|
}
|