/*
   HashList.c, Copyright  (c) by George Fankhauser,
   Swiss Federal Institute of Technology,
   Computer Engineering and Networks Laboratory.
 
   TOPSY -- A Teachable Operating System.
   Implementation of a tiny and simple
   micro kernel for teaching purposes.
 
   For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
   This software is provided under the terms of the GNU General Public Licence.
 
   A full copy of the GNU GPL is provided in the file COPYING found in the 
   development root of Topsy.
 */
/*
 
	File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/Topsy/HashList.c,v $
	Author(s):             George Fankhauser
	Affiliation:           ETH Zuerich, TIK
	Version:               $Revision: 2936 $
	Creation Date:         
	Last Date of Change:   $Date: 2007-03-21 15:23:42 +0100 (Mit, 21 Mär 2007) $      by: $Author: baderma $
*/

#include "HashList.h"
#include "Error.h"
#include "Threads.h"


Error hashListFree(HashList list);

static unsigned long int hashFunction(unsigned long int key)
{
  return( key % HASHLISTSIZE);       /* modulo array size */
}

HashList hashListNew()
{
  Error xerror;
  int i = 0;
  HashList list;

  xerror = hmAlloc((Address*)&list, sizeof(HashListDesc));
  if (xerror != HM_ALLOCOK)
  {
    ERROR("hmAlloc failed");
    return NULL;
  }
  for (i = 0; i < HASHLISTSIZE; i++)
  {
    list->table[i] = NULL;
  }
  return list;
}


Error hashListFree(HashList list)
{
  int i = 0;
  HashListElement toBeFreed, toBeFreedNext;

  for (i = 0; i < HASHLISTSIZE; i++)
  {
    toBeFreed = list->table[i];
    while (toBeFreed != NULL)
    {
      toBeFreedNext = toBeFreed->next;
      hmFree(toBeFreed);
      toBeFreed = toBeFreedNext;
    }
  }
  hmFree(list);
  return HASHOK;
}


Error hashListAdd(HashList list, void* data, unsigned long int key)
{
  Address address;
  Error xerror;
  HashListElement element;

  address = NULL;
  xerror = hmAlloc(&address, sizeof(HashListElementDesc));
  if (xerror != HM_ALLOCOK)
  {
    ERROR("hmAlloc failed");
    return HASHERROR;
  }

  if (list->table[hashFunction(key)] == NULL)
  {
    list->table[hashFunction(key)] = (HashListElement)address;
    element = (HashListElement)address;
  }
  else
  {
    element = list->table[hashFunction(key)];
    if (element->key == key)
    {
      hmFree(address);
      return HASHDUPLICATEKEY;
    }
    while (element->next != NULL)
    {
      element = element->next;
      if (element->key == key)
      {
        hmFree(address);
        return HASHDUPLICATEKEY;
      }
    }
    element->next = (HashListElement)address;
    element = element->next;
  }
  element->item = data;
  element->key = key;
  element->next = NULL;
  return HASHOK;
}


Error hashListGet(HashList list, void** data, unsigned long int key)
{
  HashListElement element = list->table[hashFunction(key)];

  while (element != NULL)
  {
    if (element->key == key)
    {
      *data = element->item;
      return HASHOK;
    }
    element = element->next;
  }
  *data = NULL;
  return HASHNOTFOUND;
}


Error hashListRemove(HashList list, unsigned long int key)
{
  HashListElement previous = NULL;
  HashListElement element = list->table[hashFunction(key)];

  if (element != NULL)
  {
    if (element->key == key)
    {
      list->table[hashFunction(key)] = element->next;
      hmFree(element);
      return HASHOK;
    }
    else
    {
      previous = element;
      element = element->next;
      while (element != NULL)
      {
        if (element->key == key)
        {
          previous->next = element->next;
          hmFree(element);
          return HASHOK;
        }
        previous = element;
        element = element->next;
      }
    }
  }
  return HASHNOTFOUND;
}
