
/*****************************************************************************
written by Jens Thiele in June 1996
Email:  info39@dulzian.gris.uni-tuebingen.de
IRC:    karme
******************************************************************************/

// ****************************************************************************
// ****************************************************************************
//              L I S T E N V E R W A L T U N G   V.3.0
//              Written by Jens Thiele Oktober 1996 
// ****************************************************************************
// ****************************************************************************


#ifndef _listen2_H
#define _listen2_H

// **************************************************** Benoetigte Includes ***

#include <stdlib.h>
#include "mystream.H"
#include "allgtypedef.H"
#include "textfata.H"
#include "iotype.H"
#include <string>

// ****************************************************************************
// ****************************************************************************
//  M A K R O S zur einfachen Zeigerelementtypenerstellung 
// ****************************************************************************
// ****************************************************************************

#define machezeigerelemtype(elem) class elem##_zeigerelemtype : public elem##type, public zeigerelemtype<elem##_zeigerelemtype>{};

#define machezeigerelem_changetype(elem) class elem##_zeigerelemtype : public elem##type, public zeigerelem_changetype<elem##_zeigerelemtype>{};


#define machekettetype(elem) typedef kettetype<elem##_zeigerelemtype> elem##_kettetype;
#define machekette_changetype(elem) typedef kette_changetype<elem##_zeigerelemtype> elem##_kettetype;

#define machezeigerelem_iotype(elem) class elem##_zeigerelem_iotype:public elem##type, public zeigerelemtype<elem##_zeigerelem_iotype>{ public: elem##_zeigerelem_iotype(iotype *ioptr,int8 mode):elem##type(ioptr,mode){}elem##_zeigerelem_iotype(){}void change(iotype *ioptr,int8 mode){elem##type::change(ioptr,mode);}};

#define machekette_iotype(elem) typedef kettetype<elem##_zeigerelem_iotype> elem##_kette_iotype;
#define machezeigerelem_iqtype(elem) class elem##_zeigerelem_iqtype : public elem##type, public zeigerelem_iqtype<elem##_zeigerelem_iqtype>{public:elem##_zeigerelem_iqtype(){};};



#define machekette_iqtype(elem) typedef kette_iqtype<elem##_zeigerelem_iqtype> elem##_kette_iqtype;
#define DEBUG_listen_H_low

// ****************************************************************************
// ****************************************************************************
//                      Z E I G E R E L E M E N T T Y P E
// ****************************************************************************
// ****************************************************************************

template <class objtype>
class zeigerelemtype
{
public:
  objtype *previous;
  objtype *next;

};

template <class objtype>
class zeigerelem_changetype : public zeigerelemtype<objtype>
{
public:
  // Wird ueberlagert wenn bei der initialisation ein objekt mit abgeleiteten virtuellen routinen
  // erstellt wird
  // Wobei dieser standard create evtl. wegkommt zwecks ambugities !!
  // bei streams dann eh ueberfluessig !!
  // wegen unterscheidung zw. laden speichern und erstellen !!
  static objtype *create(iotype *ioptr,int8 mode)
  {
#ifdef DEBUG_listen_H
    printf("zeigerelemtype::create aufgerufen.\n");
#endif    
    objtype *objptr=new objtype;
    objptr->change(ioptr,mode);
    return objptr;
  }
};


// ****************************************************************************
// ****************************************************************************
// ***************************************************** Zeigerliste
// ***************************************************** Zeigerliste
// ****************************************************************************
// ****************************************************************************

// Beschreibung :
// Doppelt verkettete Zeigerliste !!!
// Destruktor ruft automatisch die Destruktoren der Elemente auf !

// Vorraussetzungen:
// Objekt muss vom zeigerelemtype abgeleitet werden !


template <class objtype>
class kettetype 
{
public:
  // Achtung zeigen tatsächlich nur auf ein zeigerelementtype
  typedef objtype *iteratortype;
  iteratortype anfang; 
  iteratortype ende;		
  int32 anzzeigerelem;
  
  kettetype();
  // Achtung ! ruft clear auf => wenn die Objekte nicht gekilled werden sollen vorher zeiger_clear()
  virtual ~kettetype()
  {
#ifdef DEBUG_listen_H
    printf("Listen Destruktor aufgerufen\n");
#endif
    clear();
#ifdef DEBUG_listen_H
    printf("Anzahl Elemente die noch in der Kette sind: %i\n",anzzeigerelem);
#endif
    delete (zeigerelemtype<objtype>*)anfang; // siehe Konstruktor
    delete (zeigerelemtype<objtype>*)ende;   // anfang und ende zeigen auf keinen objtype
  };
  
  // Bekommt Zeiger auf neues Element uebergeben !!
  void zeiger_addafter(objtype *akt,objtype *neu);
  void zeiger_addbefore(objtype *akt,objtype *neu);
  void zeiger_push(objtype *neu);
  
  // Removes object before akt of list but doesn't delete it 
  void zeiger_delbefore(objtype *akt);
  // Removes object of list but doesn't delete it 
  void zeiger_del(objtype *akt);
  // Removes and deletes object akt
  void del(objtype *akt);
  void pop();
  void delafter(objtype *akt);
  void delbefore(objtype *akt);
  // Killt alle Objekte (delbefore)
  void clear(void);
  // Schmeisst alle Objekte raus (zeiger_delbefore)
  void zeiger_clear();

  // n-tes Element holen
  // macht einen fatalfehler falls der index zu gross ist !
  objtype *zeiger_get(int32 index);

  // Liste testen !
  void test();

};

template <class objtype> kettetype<objtype>::kettetype()
{
  anfang=(objtype*)new zeigerelemtype<objtype>; // Absicht da ich nicht 
  ende=(objtype*)new zeigerelemtype<objtype>;   // new obtype machen will !
  ende->next=ende;
  ende->previous=anfang;
  anfang->next=ende;
  anfang->previous=anfang;
  anzzeigerelem=0;
};


template <class objtype> void kettetype<objtype>::zeiger_addafter(objtype *akt,objtype *neu)
{
    if (!neu)
	fatalfehler("kettetype::zeiger_addafter : Nil Zeiger uebergeben");
    neu->previous=akt;
    neu->next=akt->next;
    akt->next->previous=neu;
    akt->next=neu;
    anzzeigerelem++;
    test();
};

template <class objtype> void kettetype<objtype>::zeiger_addbefore(objtype *akt, objtype *neu)
{
    if (!neu)
	fatalfehler("kettetype::zeiger_addbefore : Nil Zeiger uebergeben");
    neu->next=akt;
    neu->previous=akt->previous;
    akt->previous->next=neu;
    akt->previous=neu;
    anzzeigerelem++;
    test();
};

template <class objtype>  void kettetype<objtype>::zeiger_push(objtype *neu)
{
  zeiger_addbefore(ende,neu);
};

template <class objtype>  void kettetype<objtype>::zeiger_del(objtype *akt)
{
#ifdef DEBUG_listen_H_low
  if ((akt==anfang)||(akt==ende))
    fatalfehler("listen2.H: kettetype<objtype>::zeiger_del(..): Some stupid guy wants to kill the beginning or the end\n");
  test();
#endif 
  akt->previous->next=akt->next;
  akt->next->previous=akt->previous;
  anzzeigerelem--;
}

template <class objtype>  void kettetype<objtype>::zeiger_delbefore(objtype *akt)
{
  zeiger_del(akt->previous);
}


template <class objtype>  void kettetype<objtype>::del(objtype *akt)
{
  zeiger_del(akt);
  delete akt;
};

template <class objtype>  void kettetype<objtype>::pop()
{
    del(((zeigerelemtype<objtype> *)ende)->previous);
}

template <class objtype>  void kettetype<objtype>::delbefore(objtype *akt)
{
    del(akt->previous);
};

template <class objtype>  void kettetype<objtype>::delafter(objtype *akt)
{
    del(akt->next);
};

template <class objtype>  void kettetype<objtype>::clear(void)
{
  if (!anzzeigerelem)
    return;
  objtype *akt=anfang->next;
  while (akt!=ende)
    {
      akt=akt->next;
      delbefore(akt);
    };
};

template <class objtype>  void kettetype<objtype>::zeiger_clear(void)
{
  objtype *akt=anfang->next;
  while (akt!=ende)
    {
      akt=akt->next;
      zeiger_delbefore(akt);
    };
};


template <class objtype> objtype *kettetype<objtype>::zeiger_get(int32 index)
{
  if (index>=anzzeigerelem)
    fatalfehler("kettetype::zeiger_get:\nIndex liegt ausserhalb des zulaessigen Bereichs\n");
  objtype *akt=anfang->next;
  for (int32 aktnr=0;aktnr<index;aktnr++)
    {
      akt=akt->next;
    }
  return akt;
}

template <class objtype> void kettetype<objtype>::test()
{
  if (anzzeigerelem<0)
    fatalfehler("listen2.H kettetype<objtype>::test(): kette has been destroyed (0)\n");
  objtype *akt=anfang->next;
  objtype *pre=anfang;
  for (int32 a=0;a<anzzeigerelem;a++)
    {
      if (akt->previous!=pre)
	fatalfehler("listen2.H kettetype<objtype>::test(): kette has been destroyed (1)\n");
      pre=akt;
      akt=akt->next;
    }
  if (akt!=ende)
    fatalfehler("listen2.H kettetype<objtype>::test(): kette has been destroyed (2)\n");
  return;
}


// ********************************************************************************
// ********************************************************************************
// ********************************************************************************
// ********************************************************************************
//
//                Funktionen fuer die Kette
//
// ********************************************************************************
// ********************************************************************************
// ********************************************************************************
// ********************************************************************************



// kette_calc:
// Eingabe:       Zeiger auf eine Kette
// Vorbedingung:  Jedes Element der Kette muß einen calc() haben
// Funktion:      Ruft von jedem Element der Kette die Funktion calc() auf und
//                loescht die Elemente der Kette bei denen calc() einen Wert ungleich 0 
//                zurueckgegeben hat
// Ausgabe:       Anzahl der Elemente der Kette
 
template <class tkettetypeptr> 
int kette_calc(tkettetypeptr ketteptr)
{
  return kette_calc2(*ketteptr);
}
template <typename tkettetype >
int kette_calc2(tkettetype &kette)
{
  typename tkettetype::iteratortype akt;
  //  typeof(ketteptr->anfang) akt;
  akt=kette.anfang->next;
  while (akt!=kette.ende)
    {
      if (akt->calc())
	{
	  akt=akt->next;
	  kette.delbefore(akt);
	}
      else
	akt=akt->next;
    }
  return(kette.anzzeigerelem);
}


// kette_search:
// Eingabe:       Zeiger auf eine Kette, Suchkriterium (Typ "frei" wählbar), 
//                Zeiger auf ein Element der Kette
// Vorbedingung:  alle Elemente der Kette muessen eine Funktion int compare(typeof(Suchkriterium))
//                haben, die bei Gleichheit einen Wert ungleich 0 zurückgibt
// Funktion:      Sucht in der Kette das erste Element mit dem Suchkriterium
// Ausgabe:       Falls ein Element gefunde wurde ein Zeiger auf das Element
//                sonst NULL und found:=Ausgabe
 
template <class tkettetype, class searchtype, class ergtype>
ergtype kette_search(const tkettetype ketteptr,const searchtype searchfor,ergtype &found)
{
  found=ketteptr->anfang->next;
  while (found!=ketteptr->ende)
    {
      if (found->compare(searchfor))
	  return found;
      found=found->next;
    }
  return NULL;
}



// CHANGE KETTE ***************************************************************************
// CHANGE KETTE ***************************************************************************
// CHANGE KETTE ***************************************************************************
// CHANGE KETTE ***************************************************************************
// CHANGE KETTE ***************************************************************************
// CHANGE KETTE ***************************************************************************

// todo muss weg !!
// ersetzen durch << und >>
#include "iotype.H"

// Kette laden/speichern
// uebergeben wird ein Zeiger auf eine Kette
// Die Objekte in der Kette muessen einen create, einen change und einen Standard Konstruktor haben

template <class objtype> 
void kette_change(kettetype<objtype> &kette,iotype *ioptr,int8 mode)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
      kette.clear();
    kette_merge(kette,ioptr,mode);
}

template <class objtype> 
void kette_merge(kettetype<objtype> &kette,iotype *ioptr,int8 mode)
{
    int32 toload;
    if (ioptr->getmode()==IOTYPE_WRITE_MODE)
	toload=kette.anzzeigerelem;
    
    // Elementanzahl changen !
    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
    cfgptr->change_int32_check(&toload);
    delete cfgptr;

    // LADEN ******************************************************************
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	{
	  //	  cout <<"kette_merge: vorher: "<<kette.anzzeigerelem;
	  while (toload)
	    {
	      objtype *akt=objtype::create(ioptr,mode);
	      kette.zeiger_push(akt);
	      toload--;
	    }
	  return;
	}
    // SPEICHERN **************************************************************
    //    typeof(kette.anfang) laufzeiger=kette.anfang->next;
    kettetype<objtype>::iteratortype laufzeiger;
    laufzeiger=kette.anfang->next;
    while (laufzeiger!=kette.ende)
	{
	    laufzeiger->change(ioptr,mode);
	    laufzeiger=laufzeiger->next;
	}
}


template <class objtype>
class kette_changetype : public kettetype<objtype>
{
public:
  virtual void change(iotype *ioptr,int8 mode)
  {
    kettetype<objtype> *subset=this;
    kette_change(*subset,ioptr,mode);
  }
  virtual void merge(iotype *ioptr,int8 mode)
  {
    kettetype<objtype> *subset=this;
    kette_merge(*subset,ioptr,mode);
  }
};



// IOS KETTE **********************************************************************
// IOS KETTE **********************************************************************
// IOS KETTE **********************************************************************
// IOS KETTE **********************************************************************
// IOS KETTE **********************************************************************

// class create_kettetype:
// create:
// Eingabe:       istream
// Vorbedingung:  Inhalt des istreams "entspricht" dem Aufbau der Kette
//                die Klasse des Typs objtype hat eine statische Funktion
//                objtype *create(istream) die bei Erfolg den neuen objtype
//                zurueckgibt und bei Mißerfolg NULL zurueckgibt.
// Funktion:      Konstruktoriert eine Kette
// Ausgabe:       NULL oder ein Pointer auf die neue Kette vom Typ kettetype<objtype>

template <class objtype>
class create_kettetype
{
public:
  static kettetype<objtype> *create(istream &ist)
  {
    kettetype<objtype> *neue_kette=new kettetype<objtype>;
    int32 anzelem;
    //    typeof(neue_kette->anzzeigerelem) anzelem;
    if (!(ist>>anzelem))
      return (NULL);
    while (anzelem)
      {
	objtype *neues_elem=objtype::create(ist);
	if (!neues_elem)
	  return NULL;
	neue_kette->zeiger_push(neues_elem);
	anzelem--;
      }
    return neue_kette;
  }
};


// todo an Ausgabe anpassen !!
// wirklich sinnig so eine schnoerkelige ausgabe ?
// witzig ist es schon vielleicht zwei alternativen ?

// Operator >> fuer kettetype<objtype>
// Eingabe:       istream, kettetype<objtype>
// Vorbedingung:  Alle Elemente der Kette haben ebenfalls den Operator >>
// Funktion:      liest aus dem istream die kette aus ("reload")
// Ausgabe:       Falls der Inhalt des Istreams dem Aufbau der Elemente,
//                zu Beginn einen typeof(kette.anzzeigerelem) und 
//                Die Anzahl der Elemente in der Liste gleich
//                der Anzahl im Istream ist: istream mit state ios::good
//                Sonst: Elemente der Liste koennen geladen worden sein
//                und andere nicht !!
//                Bem.: Dies entspricht eigentlich nicht der iostream Konvention
//                geht aber nicht sinnvoll anders. (Muesste komplette Liste koppieren!)
//                istream mit state ios::badbit

template <class objtype>
istream &operator>>(istream &ist, kettetype<objtype> &kette)
{
  if (ist.ipfx(0))
    {
      //      typeof(kette.anzzeigerelem) _anzzeigerelem;
      int32 _anzzeigerelem;
      if ((ist>>_anzzeigerelem)&&(kette.anzzeigerelem==_anzzeigerelem))
	{
	  objtype *akt=kette.anfang->next;
	  while (akt!=kette.ende)
	    {
	      ist >> *akt;
	      akt=akt->next;
	    }
	}
      else
	ist.clear(ios::badbit);
      ist.isfx();
    }
    return ist;
}


// Operator << fuer kettetype<objtype>
// Eingabe:       ostream, kette
// Vorbedingung:  Alle Elemente der Kette haben ebenfalls den Operator <<
// Funktion:      schreibt die kette in den ostream
// Ausgabe:       ostream

template <class objtype>
ostream &operator<<(ostream &ost,const kettetype<objtype> &kette)
{
  if (ost.opfx())
    {
      ost << kette.anzzeigerelem<<"=|{";
      if (kette.anzzeigerelem)
	{
	  objtype *laufzeiger=kette.anfang->next;
	  while (laufzeiger!=kette.ende->previous)
	    {
	      ost << (*laufzeiger)<<",";
	      laufzeiger=laufzeiger->next;
	    }
	  ost << (*laufzeiger);
	}
      ost <<"}|";
      ost.osfx();
    }
  return ost;
}

template <class objtype>
class kette_iostype : public kettetype<objtype>, public my_io_streamtype
{
public:
  ostream &write(ostream &ost) const
  {
    /*        const kettetype<objtype> *subset=this;
    ost << (*subset);*/
    return ost;
  }
  istream &read(istream &ist)
  {
    /*       kettetype<objtype> *subset=this;
    ist >> (*subset);*/
    return ist;
  }
};




// PUSH KETTE ***************************************************************************
// PUSH KETTE ***************************************************************************
// PUSH KETTE ***************************************************************************
// PUSH KETTE ***************************************************************************
// PUSH KETTE ***************************************************************************

/*
template <class objtype>
class kette_pushtype : public kettetype<objtype>
{
public:
  inline objtype *addafter(objtype *akt);
  inline objtype *addbefore(objtype *akt);
  inline objtype *push();
};

template <class objtype> inline objtype *kette_pushtype<objtype>::addafter(objtype *akt)
{
    objtype *neu=new objtype;
    zeiger_addafter(akt,neu);
    return(neu);
};

template <class objtype> inline objtype *kette_pushtype<objtype>::addbefore(objtype *akt)
{
    objtype *neu=new objtype;
    zeiger_addbefore(akt,neu);
    return(neu);
};

template <class objtype> inline objtype *kette_pushtype<objtype>::push()
{
    objtype *neu=new objtype;
    zeiger_push(neu);
    return(neu);
};
*/

// ***************************************************************************
// ***************************************************************************
// ******************************************** Iqe Kette 
// ******************************************** Iqe Kette 
// ******************************************** Iqe Kette 
// ***************************************************************************
// ***************************************************************************

// Was kann die Iqe Kette ???
// Initialisiert Objekte mit einem Indentifier string, der Normalerweise
// ein Dateiname ist. Wenn das Objekt noch nicht in der Liste ist wird es
// anhand der Datei initialiesiert ansonsten wird ein Counter incrementiert.
// Das Objekt wird erst deinitialisiert wenn der Counter wieder auf 0 de-
// crementiert wurde (Counter * delete_elementadress aufgerufen wurde)

// Falsch im Moment werden die Objekte garnicht geloescht da der Cache noch nicht funktioniert !


// Vorraussetzungen :
// Die zu speichernden Objekte haben einen Konstruktor mit der Parameterliste:
// (char *name)
// Benutzen sie einfach das Makro: machezeigerelem_iqtype
template <class objtype>
class kette_iqtype;


template <class objtype>
class zeigerelem_iqtype 
    : public zeigerelemtype<objtype>
{
  friend class kette_iqtype<objtype>;
public:
  string elementname;
  //  inline zeigerelem_iqtype(char *name);
  zeigerelem_iqtype();
private:
  uint32 anzmalloced;
  uint32 cache;
};

template <class objtype>  zeigerelem_iqtype<objtype>::zeigerelem_iqtype()
{
#ifdef DEBUG_listen_H
  printf("Konstruktor von zeigerelem_iqtype aufgerufen ! => Element geinitet\n");
#endif
  anzmalloced=1;
};


template <class objtype>
class kette_iqtype : public kette_changetype<objtype>
{
public:
  kette_iqtype(int _cachecounter_start=1){cachecounter_start=_cachecounter_start;};
  ~kette_iqtype(){clear();}

  objtype *make_elementadress(const char *name,int8 mode=CFG_TEXT_MODE);
  void delete_elementadress(objtype *objptr);
  void clear();
  // Liefert NULL zuerueck wenn das Element nicht vorhanden ist !
  objtype *get_elementadress(const char *name);
protected:
  void inc_element_counter(objtype *objptr)
  {
    objptr->anzmalloced++;
  }
private:
  uint32 cachecounter_start;
};

template <class objtype> objtype *kette_iqtype<objtype>::make_elementadress(const char *name,int8 mode)
{
#ifdef DEBUG_listen_H
    printf("kette_iqtype::make_elementadress: %s\n",name); // spaeter
#endif
    objtype *laufzeiger;
    if ((laufzeiger=get_elementadress(name))!=NULL)
	laufzeiger->anzmalloced++;
    else
      {
	// So umstaendlich damit auch objekte die nicht wirklich vom objtype sind
	// sondern erst noch initialisiert werden und nur vom objtype abgeleitet sind !!
	iotype *ioptr=make_file_to_io_check(name);
	laufzeiger=objtype::create(ioptr,mode);
	delete ioptr;
	laufzeiger->elementname+=name;
	zeiger_push(laufzeiger);
      }
    return(laufzeiger);
};

template <class objtype> objtype *kette_iqtype<objtype>::get_elementadress(const char *name)
{
    objtype *laufzeiger;
    laufzeiger=anfang->next;
    while (laufzeiger!=ende)
	{
	    if (laufzeiger->elementname==string(name))
		return(laufzeiger);
	    laufzeiger=laufzeiger->next;
	}
    return(NULL);
};

template <class objtype> void kette_iqtype<objtype>::delete_elementadress(objtype *objptr)
{
  if (!objptr) return;
#ifdef DEBUG_listen_H
  cout <<"Loesche Elemen (Decr. Counter)"<<objptr->elementname<<endl;
#endif
    if ((objptr->anzmalloced)>1)
      {
	objptr->anzmalloced--;
      }
    else if (objptr->anzmalloced)
      {
	// Der Counter wird auf null gesetzt => das Element wird gecached ?
	objptr->anzmalloced--;		
	objptr->cache=cachecounter_start;
	// todo Cache !! Problem: reihenfolge der destruktorierung !
#ifdef DEBUG_listen_H
	cout << "Cache " << objptr->elementname <<endl; // spaeter
#endif
	zeiger_del(objptr);
	zeiger_push(objptr);
	//	del(objptr);
      }
    else
      // todo !
      fatalfehler("delete_elementadress: Objekt ist schon tot => Zugriff auf nicht allocierten mem !\n");
};

template <class objtype> void kette_iqtype<objtype>::clear()
{
  objtype *akt=anfang->next;
  while (akt!=ende)
    {
      akt=akt->next;
      if (!(akt->previous->anzmalloced))
	delbefore(akt);
    }
}


// string_zeigerelemtype **********************************************************************
// string_zeigerelemtype **********************************************************************
// string_zeigerelemtype **********************************************************************
// string_zeigerelemtype **********************************************************************
// string_zeigerelemtype **********************************************************************

class string_zeigerelemtype : public string , public zeigerelem_changetype<string_zeigerelemtype>
{
public:
  string_zeigerelemtype(){}
  string_zeigerelemtype(const char *_str) : string(_str){}
  string_zeigerelemtype(const string &_str) : string(_str){}
  void change(iotype *ioptr,int8 mode)
  {
    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
    cfgptr->change_string_check(this);
    delete cfgptr;
  }
};

#endif

