/*
  (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
*/

template<class T,class H,unsigned long dirsize,bool savemem> struct hashdir
{
  unsigned long counter;
  joined_list<T>* values;
  joined_list<H>* names;

  hashdir()
  {
    counter=0;
    if (!savemem)
      {
	values=new joined_list<T> [dirsize];
	names=new joined_list<string> [dirsize];
	if (!values || !names)
	  {
	    log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
	  };
      };
  };

  ~hashdir()
  {
    if (!savemem || counter)
      {
	delete[] values;
	delete[] names;
      };
  };

  hashdir(hashdir& src)
  {
    counter=src.counter;
    if (counter)
      {
        values=new joined_list<T> [dirsize];
        names=new joined_list<string> [dirsize];
        if (!values || !names)
          {
            log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
          };
	*values=*(src.values);
	*names=*(src.names);
      }
    else if (!savemem)
      {
        values=new joined_list<T> [dirsize];
        names=new joined_list<string> [dirsize];
        if (!values || !names)
          {
            log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
          };
      };
  };

  hashdir& operator=(hashdir&);
  bool insert_listelem(T&,H&);
  bool remove_listelem(H&);
  T* get_listelem(H&);
};

template<class T,class H,unsigned long dirsize,bool savemem>
hashdir<T,H,dirsize,savemem>& hashdir<T,H,dirsize,savemem>::
operator=(hashdir<T,H,dirsize,savemem>& src)
{
  if (!savemem || counter)
    {
      delete[] values;
      delete[] names;
    };

  counter=src.counter;
  if (counter)
    {
      values=new joined_list<T> [dirsize];
      names=new joined_list<string> [dirsize];
      if (!values || !names)
	{
	  log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
	};
      *values=*(src.values);
      *names=*(src.names);
    }
  else if (!savemem)
    {
      values=new joined_list<T> [dirsize];
      names=new joined_list<string> [dirsize];
      if (!values || !names)
	log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
    };
  return *this;
}

template<class T,class H,unsigned long dirsize,bool savemem>
bool hashdir<T,H,dirsize,savemem>::insert_listelem(T& x, H& name)
{
  unsigned long hashsum=hash(name);
  unsigned long i=0;

  if (!counter && savemem)
    {
      values=new joined_list<T> [dirsize];
      names=new joined_list<string> [dirsize];
      if (!values || !names)
	{
	  log(LOG_ERROR,__FILE__,__LINE__,ERROR_OUT_OF_MEM,0);
	  return 0;
	};

      values[hashsum].insert_listelem(x);
      names[hashsum].insert_listelem(name);
      counter++;
      return 1;
    };

  unsigned long len=names[hashsum].length();
  for (i=0;i!=len;i++)
    {
      if (names[hashsum][i]==name) { return 0; };
    };

  values[hashsum].insert_listelem(x);
  names[hashsum].insert_listelem(name);
  counter++;
  return 1;
}

template<class T,class H,unsigned long dirsize,bool savemem>
bool hashdir<T,H,dirsize,savemem>::remove_listelem(H& name)
{
  if (!counter) { return 0; };

  unsigned long hashsum=hash(name);
  unsigned long i;
  unsigned long len=names[hashsum].length();
  for (i=0;i!=len;i++)
    {
      if (names[hashsum][i]==name)
	{
	  names[hashsum].remove_listelem(i);
          values[hashsum].remove_listelem(i);
	  counter--;
	  if (!counter && savemem) { delete[] names; delete[] values; };
	  return 1;
	};
    };
  return 0;
}

template<class T,class H,unsigned long dirsize,bool savemem>
T* hashdir<T,H,dirsize,savemem>::get_listelem(H& name)
{
  if (!counter) { return 0; };

  unsigned long hashsum=hash(name);
  unsigned long i=0;
  unsigned long len=names[hashsum].length();

  for (i=0;i!=len;i++)
    {
      if (names[hashsum][i]==name)
        {
          return &values[hashsum][i];
        };
    };
  return 0;
}



