// ---------------------------------------------------------------------------
// - Reactor.cpp                                                             -
// - standard object library - nuclear reactor class implementation          -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - 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.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2008 amaury darsch                                   -
// ---------------------------------------------------------------------------

#include "Utility.hpp"
#include "Reactor.hpp"

namespace afnix {

  // -------------------------------------------------------------------------
  // - private section                                                       -
  // -------------------------------------------------------------------------
  
  // the hash table node
  struct s_qnode {
    // the quark name
    String d_name;
    // the hashid value
    long   d_hvl;
    // the quark value 
    long  d_quark;
    // next record in the list
    s_qnode* p_next;
    // simple constructor
    s_qnode (void) {
      d_hvl   = 0;
      d_quark = 0;
    }
    // simple destructor
    ~s_qnode (void) {
      delete p_next;
    }
  };
  
  // find a node by name given its root node
  static inline s_qnode* getnode (s_qnode* node, const String& name) {
    // simple check as fast as we can
    if (node == nilp) return nilp;
    // loop until we have a match
    while (node != nilp) {
      if (node->d_name == name) return node;
      node = node->p_next;
    }
    // no node found
    return nilp;
  }

  // -------------------------------------------------------------------------
  // - class section                                                         -
  // -------------------------------------------------------------------------
    
  // create a new reactor
  
  Reactor::Reactor (void) {
    // build the array
    d_size   = Utility::toprime (0);
    d_thrs   = (d_size * 7) / 10;
    d_count  = 0;
    p_table  = new s_qnode*[d_size];
    for (long i = 0; i < d_size; i++) p_table[i] = nilp;
    p_vector = new Strvec (d_size);
    p_vector->add ("");
  }
  
  // delete this reactor
  
  Reactor::~Reactor (void) {
    if (p_table != nilp) {
      for (long i = 0; i < d_size; i++) delete p_table[i];
      delete [] p_table;
    }
    delete p_vector;
  }

  // intern a name in this reactor
  
  long Reactor::intern (const String& name) {
    // check for nil
    if (name.isnil () == true) return 0;
    // compute the hash value
    long hvl = name.hashid ();
    long hid = hvl % d_size;
    // look for existing node
    s_qnode* node = getnode (p_table[hid],name);
    if (node != nilp) return node->d_quark;;
    // the node does not exist, create it 
    node          = new s_qnode;
    node->d_name  = name;
    node->d_hvl   = hvl;
    node->d_quark = ++d_count;
    node->p_next  = p_table[hid];
    p_table[hid]  = node;
    if (d_count > d_thrs) resize (Utility::toprime (d_size + 1));
    p_vector->add (name);
    return d_count;
  }
  
  // remap a quark to a string
  
  String Reactor::qmap (const long quark) const {
    return p_vector->get (quark);
  }

  // resize the hash table by creating a new one
  
  void Reactor::resize (const long size) {
    // check for the size
    if (size < d_size) return;
    // initialize the table
    s_qnode** table = new s_qnode*[size];
    for (long i = 0; i < size; i++) table[i] = nilp;
    // rebuild the table
    for (long i = 0; i < d_size; i++) {
      s_qnode* node = p_table[i];
      while (node != nilp) {
	s_qnode* next = node->p_next;
	node->p_next = nilp;
	long hid = node->d_hvl % size;
	node->p_next = table[hid];
	table[hid]   = node;
	node = next;
      }
    }
    // clean the old table
    delete [] p_table;
    // restore the new table
    d_size  = size;
    d_thrs  = (d_size * 7) / 10;
    p_table = table;
  }
}
