#include "bingo_mapping.h"

using namespace bingo;

BingoMapping::BingoMapping  (size_t safe_prime) : _prime(safe_prime)
{
   _block_size = 100;
   _mapping_table.resize(safe_prime);
}

size_t BingoMapping::get (size_t id)
{
   _MapIterator iter;
   int idx_in_block;

   if (_findElem (id, iter, idx_in_block))
      return iter->buf[idx_in_block].second;

   return (size_t)-1;
}

void BingoMapping::getAll (size_t id1, Array<size_t> &id2_array)
{
   id2_array.clear();

   if ((BingoAddr)(_mapping_table[_hashFunc(id1)]) == BingoAddr::bingo_null)
      return;   

   _MapList::Iterator it;
   _MapList &cur_list = _mapping_table[_hashFunc(id1)].ref();

   int i;
   for (it = cur_list.begin(); it != cur_list.end(); it++)
   {
      for (i = 0; i < it->count; i++)
      {
         if (it->buf[i].first == id1)
            id2_array.push(it->buf[i].second);
      }
   }
}

void BingoMapping::add (size_t id1, size_t id2)
{
   if ((BingoAddr)(_mapping_table[_hashFunc(id1)]) == BingoAddr::bingo_null)
   {
      _mapping_table[_hashFunc(id1)].allocate();
      new(_mapping_table[_hashFunc(id1)].ptr()) _MapList();
   }

   _MapList &cur_list = _mapping_table[_hashFunc(id1)].ref();
         
   if (cur_list.size() == 0 || cur_list.top()->count == _block_size)
   {
      BingoPtr< _ListCell > new_array_ptr;
      new_array_ptr.allocate();
      new(new_array_ptr.ptr()) _ListCell(_block_size);

      cur_list.pushBack(new_array_ptr);
   }

   int &top_size = cur_list.top()->count;
   cur_list.top()->buf[top_size++] = _KeyPair(id1, id2);
}

void BingoMapping::remove (size_t id)
{
   if ((BingoAddr)(_mapping_table[_hashFunc(id)]) == BingoAddr::bingo_null)
      throw Exception("BingoMapping: There is no such id");   

   _MapList::Iterator it;
   //_MapList &cur_list = _mapping_table[_hashFunc(id)].ref();

   int idx_in_block;
   bool res = _findElem(id, it, idx_in_block);

   if (!res)
      throw Exception("BingoMapping: There is no such id");

   it->buf[idx_in_block].first = -1;
   it->buf[idx_in_block].second = -1;
}


size_t BingoMapping::_hashFunc (size_t id)
{
   return (id % _prime);
}

bool BingoMapping::_findElem (size_t id, _MapIterator &iter, int &idx_in_block)
{
   if ((BingoAddr)(_mapping_table[_hashFunc(id)]) == BingoAddr::bingo_null)
      return false;   

   _MapList::Iterator it;
   _MapList &cur_list = _mapping_table[_hashFunc(id)].ref();

   int i;
   for (it = cur_list.begin(); it != cur_list.end(); it++)
   {
      for (i = 0; i < it->count; i++)
      {
         if (it->buf[i].first == id)
            break;
      }
      if (i < it->count)
         break;
   }
   if (it == cur_list.end())
      return false;

   iter = it;
   idx_in_block = i;

   return true;
}
