/*
  (c) 1998 netEstate (http://www.netestate.de/, info@netestate.de),
Michael Brunnbauer & Markus Hendel, Gesellschaft fuer Netzwerkkommunikation bR
Am Bluetenanger 8, 80995 Muenchen, Germany

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*

parametrisierte klasse joined_list fuer eine verkettete liste.
die elemente koennen beliebige datentypen haben. urversion aus
ISBN 3-540-56524-8.

elementfunktionen:

-insert_listelem(const T& x [, unsigned long i] )
 fuegt x als (i+1)-te komponente ein, default fuer i ist 0.
-remove_listelem(unsigned long i)
 loescht die (i+1)-te komponente.
-unsigned long length()
 liefert die laenge
-die operatoren [] und = sind ueberladen

*/

/* klasse joined_list_element */

template<class T> struct joined_list_element
{
  /* konstruktor */
  joined_list_element(T& e, joined_list_element*  n = NULL) :
    value(e), nextone(n) { }

  T value;
  joined_list_element* nextone;
};

/* klasse joined_list */

template<class T> class joined_list
{
public:

  /* konstruktor */
  joined_list() : start(NULL), counter(0) { anfang(); }

  /* destruktor */
  virtual ~joined_list() { dest(); }

  /* copy-konstruktor */
  joined_list(joined_list& m)
  {
    start=NULL;
    counter=m.counter;
    copy(m);
  }

  /* ueberladene operatoren */
  joined_list& operator=(joined_list&);
  T& operator[](unsigned long);

  /* public-funktionen */
  void insert_listelem(T&, unsigned long = 0);
  void remove_listelem(unsigned long);

  /* spezialfunktionen */
  T& find_vnum(unsigned int);
  T& find_name(char*);

  /* laenge */
  unsigned long length() { return counter; }

protected:

  joined_list_element<T>* anfang()
  {
    ind_akt=0;
    return (zgr_akt = start);
  }
  
  joined_list_element<T>* iter()
  {
    return (zgr_akt!=NULL) ?  ind_akt++, zgr_akt=zgr_akt->nextone : 0;
  }
  
private:
  /* gibt den speicher frei */
  void dest();
  
  /* kopiert die liste */
  void copy(joined_list&);
  
  joined_list_element<T>* start;
  unsigned long counter;
  joined_list_element<T>* zgr_akt;
  unsigned long ind_akt;
};

template<class T>
void joined_list<T>::dest()
{
  joined_list_element<T>* tmp;

  while (start)
    {
      tmp=start->nextone;
      delete start;
      start=tmp;
    };

  return;
}

template<class T>
void joined_list<T>::copy(joined_list<T>& m)
{
  joined_list_element<T>* mZgr;
  joined_list_element<T>* z;

  if (!(counter=m.counter))
    {
      anfang();
      return;
    };

  ind_akt=m.ind_akt;
  mZgr=m.start;
  z=zgr_akt=start=new joined_list_element<T>(mZgr->value);
  if (!z)
    {
      log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
    };
  while ((mZgr=mZgr->nextone))
    {
      z=z->nextone=new joined_list_element<T>(mZgr->value);
      if (!z)
	{
	  log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
      	};
    };

  if (mZgr==m.zgr_akt) { zgr_akt=z; };

  return;
}

template<class T>
joined_list<T>& joined_list<T>::operator=(joined_list<T>& m)
{
  if (this==&m) { return *this; };
  dest();
  copy(m);
  return *this;
}

template<class T>
void joined_list<T>::insert_listelem(T& x, unsigned long i)
{
  unsigned long k;
  joined_list_element<T>* neu;
  joined_list_element<T>* zgr;

  if (counter==0xFFFFFFFF)
    {
      log(LOG_FATAL,__FILE__,__LINE__,ERROR_VALUE_OUT_OF_RANGE,
	  "counter is 0xFFFFFFFF");
    };

  if (i>counter)
    {	
      log(LOG_FATAL,__FILE__,__LINE__,ERROR_VALUE_OUT_OF_RANGE,
	  "Value was: %i",i);
    };

  neu=new joined_list_element<T>(x);

  if (!neu)
    {
      log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
    };

  if (!i)
    {
      neu->nextone=start;
      start=neu;
    }
  else
    {
      zgr=start;
      for (k=0;k<i-1;k++) { zgr=zgr->nextone; };
      neu->nextone=zgr->nextone;
      zgr->nextone=neu;
    }

  counter++;
  anfang();
  return;
}

template<class T>
void joined_list<T>::remove_listelem(unsigned long i)
{
  unsigned long k;
  joined_list_element<T>* zgr2;
  joined_list_element<T>* zgr1;

  if (i>=counter)
    {
      log(LOG_FATAL,__FILE__,__LINE__,ERROR_VALUE_OUT_OF_RANGE,
	  "Value was: %i",i);
    };
  zgr2=start;
  for (k=0;k<i;k++)
    {
      zgr1=zgr2;
      zgr2=zgr2->nextone;
    };
  ((zgr2==start) ? start : zgr1->nextone) = zgr2->nextone;
  delete zgr2;
  counter--;
  anfang();
  return;
}

template<class T>
T& joined_list<T>::operator[](unsigned long i)
{
  unsigned long k;

  if (i>=counter)
    {
      log(LOG_FATAL,__FILE__,__LINE__,ERROR_VALUE_OUT_OF_RANGE,
          "Value was: %i",i);
    };
  if (i<ind_akt) { anfang(); } else { i-=ind_akt; };
  for(k=0;k<i;k++) { iter(); };
  return zgr_akt->value;
}

/* spezialfunktion fuer dikumud */
template<class T>
T& joined_list<T>::find_vnum(unsigned int vnum)
{
  joined_list_element<T>* zgr=anfang();

  do
    {
      if (zgr->value.my_vnum==vnum) { return zgr->value; };
    } while ((zgr=iter()));

  log(LOG_FATAL,__FILE__,__LINE__,ERROR_WRONG_ARGUMENT,
      "diku vnum %i not found",(int) vnum);
  return zgr->value;
}

/* spezialfunktion fuer dikumud */
template<class T>
T& joined_list<T>::find_name(char* name)
{
  joined_list_element<T>* zgr=anfang();
  do
    {
      if (zgr->value.name==name) { return zgr->value; };
    } while ((zgr=iter()));

  log(LOG_FATAL,__FILE__,__LINE__,ERROR_WRONG_ARGUMENT,
      "aber name %s not found",(char*) name);
  return zgr->value;
}

