/***************************************************************************
                          hash.cpp  -  description
                             -------------------
    begin                : Thu Aug 17 2000
    copyright            : (C) 2000 by Waldemar Baraldi
    email                : baraldi@lacasilla.com.ar
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>
#include <string.h>
#include "hash.h"
#include <stdio.h>

Hash::Bucket::Bucket(Str * str, Object * obj){
  this->str=str;
  this->obj=obj;
}

Hash::Bucket::~Bucket(){
  delete str;
}

void Hash::Bucket::setStr(Str * str){
  if (this->str) delete this->str;
  this->str=str;
}

void Hash::Bucket::setObject(Object * obj){
  this->obj=obj;
}

Str * Hash::Bucket::getStr(){
 return str;
}

Object * Hash::Bucket::getObject(){
  return obj;
}

int Hash::function(Str * str){
  int i=0, sum=0;
  const char * aux=str->get();

  while (aux[i]!='\0') sum+=aux[i++];

  return(sum % nbuckets);
}

Hash::Hash(int bs=256){
 int i;
 nbuckets=bs;
 lbuckets=new (List *)[nbuckets];

 for (i=0;i<nbuckets;i++)
   lbuckets[i]=new List();
}

Hash::~Hash(){
  int i;
  List * list;
  for (i=0;i<nbuckets;i++){
    list=lbuckets[i];
    list->empty(false);
    delete list;
  }
  delete[] lbuckets;
}

Hash::Result Hash::add(Str * str, Object * obj){
  if (str){
//    Index * i;
    List * list;
    list=lbuckets[function(str)];
    if (list->nObjects()>0){
      /*
      for (i=list->getFirst();i!=list->getEnd();i=list->getNext(i)){
        if (((Bucket*)list->getObject(i))->getStr()->isEqual(str)){
          ((Bucket*)list->getObject(i))->setObject(obj);
          return AddedOverwrite;
        }
      }
      */
      list->insert(list->getFirst(), new Bucket(str, obj));
      return AddedCollision;
    }else{
      list->insert(list->getFirst(), new Bucket(str, obj));
      return AddedNoCollision;
    }
  }
  return NotAdded;
}

Hash::Result Hash::remove(Str * str, bool del=false){
  if (str){
    Index * i;
    List * list=lbuckets[function(str)];

    for (i=list->getFirst();i!=list->getEnd();i=list->getNext(i))
      if (((Bucket *)list->getObject(i))->getStr()->isEqual(str)){
        if (del)
          delete ((Bucket *)list->getObject(i))->getObject();
        list->remove(i, true);
        delete str;
        return Removed;
      }
    delete str;
  }
  return NotFound;
}

Object * Hash::find(Str * str){
  if (str){
    Index * i;
    List * list=lbuckets[function(str)];

    i=list->getFirst();
    while (i!=list->getEnd()){
      if (((Bucket *)list->getObject(i))->getStr()->isEqual(str)){
        delete str;
        return ((Bucket *)list->getObject(i))->getObject();
      }
      i=list->getNext(i);
    }
    delete str;
  }
  return NULL;
}

void Hash::empty(bool del=true){
  int i;
  List * list;
  for (i=0;i<nbuckets;i++){
    list=lbuckets[i];
    if (del){
      Index * idx=list->getFirst();
      while (idx!=list->getEnd()){
        delete ((Bucket*)list->getObject(idx))->getObject();
        idx=list->getNext(idx);
      }
    }
    list->empty(del);
  }
}

