//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//
// File        : indexed_hash_table.c
// Author      : Michael Jacobson, Jr. (MJ)
// Last change : MJ, September 24, 1996
//

#include "indexed_hash_table.h"

template < class T >
indexed_hash_table < T >::indexed_hash_table() : hash_table < T >()
{
  IDX.set_mode(EXPAND);
  IDX.set_size(0);
  outstyle = 1;
}


template < class T >
indexed_hash_table < T >::~indexed_hash_table()
{
  IDX.set_size(0);
}



template < class T >
void
indexed_hash_table < T >::assign(const indexed_hash_table < T > & old_table)
{
  lidia_size_t i;

  initialize(old_table.size);
  key = old_table.key;

  for (i=0; i<old_table.curr_size; ++i)
    hash(old_table[i]);
}



template < class T >
indexed_hash_table < T > & indexed_hash_table < T >::operator = (const indexed_hash_table < T > & old_table)
{
  this->assign(old_table);
  return *this;
}



template < class T >
const T & indexed_hash_table < T >:: operator [](lidia_size_t i) const
{
  hentry < T > *ptr;
  T *tptr;

  if ((i < 0) || (i >= curr_size))
    lidia_error_handler("indexed_hash_table","operator [] - i >= current size \
or < 0");

  ptr = (hentry < T > *) IDX[i];
  tptr = (T *) ptr->item;

  return *tptr;
}




template < class T >
const T & indexed_hash_table < T >::member(lidia_size_t i) const
{
  hentry < T > *ptr;
  T *tptr;

  if ((i < 0) || (i >= curr_size))
    lidia_error_handler("indexed_hash_table","member - i >= current size \
or < 0");

  ptr = (hentry < T > *) IDX[i];
  tptr = (T *) ptr->item;

  return *tptr;
}



template < class T >
void
indexed_hash_table < T >::remove(const T & G)
{
  hentry < T > *ptr;
  lidia_size_t j;
  T *target,*tptr;

  target = search(G);
  if (target) {
    for (j=0; j<curr_size; ++j) {
      ptr = (hentry < T > *) IDX[j];
      tptr = (T *) ptr->item;
      if (tptr == target)
        break;
    }

    remove_from(j);
  }
}



template < class T >
void
indexed_hash_table < T >::remove_from(const lidia_size_t i)
{
  hentry < T > *ptr,*pptr,*nptr;
  T *tptr;
  lidia_size_t j;

  if ((i < 0) || (i >= curr_size))
    lidia_error_handler("indexed_hash_table","remove_from - i >= current size \
or < 0");

  ptr = (hentry < T > *) IDX[i];
  pptr = ptr->prev;
  nptr = ptr->next;

  if (pptr) {
    pptr->next = nptr;
    if (nptr)
      nptr->prev = pptr;
    delete ptr;
  }
  else {
    tptr = (T *) ptr->item;
    j = (lidia_size_t) remainder(key(*tptr),size);
    if (j < 0)
      j += size;
    delete (hentry < T > *) buckets[j];
    buckets[j] = (int) nptr;
    if (nptr)
      nptr->prev = NULL;
  }

  --curr_size;
  IDX.remove_from(i);
}



template < class T >
void
indexed_hash_table < T >::empty()
{
  lidia_size_t i,end;

  end = curr_size;
  for (i=end-1; i>=0; --i)
    remove_from(i);

  IDX.set_size(0);
}



template < class T >
void
indexed_hash_table < T >::hash(const T & G)
{
  lidia_size_t i,current;
  hentry < T > *ptr,*nptr,*newone;
  T *newT;

  current = curr_size;
  ++curr_size;

  if (!(newone = new hentry < T >))
    lidia_error_handler("indexed_hash_table","hash - not enough memory");
  if (!(newT = new T))
    lidia_error_handler("indexed_hash_table","hash - not enough memory");
  (*newT) = G;
  newone->item = (int) newT;
  last_one = newT;

  i = (lidia_size_t) remainder(key(G),size);
  if (i < 0)
    i += size;
  ptr = (hentry < T > *) buckets[i];
  if (ptr) {
    while (ptr) {
      nptr = ptr;
      ptr = nptr->next;
    }
    nptr->next = newone;
    newone->prev = nptr;
  }
  else
    buckets[i] = (int) newone;

  IDX[current] = (int) newone;
}



template < class T >
void indexed_hash_table< T >::output_style(int style)
{
  if (style == 1)
    outstyle = 1;
  else
    outstyle = 0;
}



template < class T >
void indexed_hash_table< T >::read (istream & in)
{
  lidia_size_t new_size,num,i;
  T new_item;

  in >> new_size;
  initialize((long) new_size);

  in >> num;
  for (i=0; i<num; ++i) {
    in >> new_item;
    hash(new_item);
  }
}



template < class T >
void indexed_hash_table< T >::print (ostream & out) const
{
  lidia_size_t i;
  hentry < T > *ptr;
  T *tptr;

  if (outstyle == 0) {
    for (i=0; i<curr_size; ++i) {
      ptr = (hentry < T > *) IDX[i];
      tptr = (T *) ptr->item;
      out << i << ": " << (*tptr) << "\n";
    }
  }
  else {
    for (i=0; i<size; ++i) {
      if (buckets[i]) {
        out << "[" << i << "]";
        ptr = (hentry < T > *) buckets[i];
        while (ptr) {
          tptr = (T *) ptr->item;
          out << " : " << (*tptr);
          ptr = ptr->next;
        }
        out << "\n";
      }
    }
  }
}
