/*
   Copyright (C) 2011  Statoil ASA, Norway. 
    
   The file 'hash_sll.c' is part of ERT - Ensemble based Reservoir Tool. 
    
   ERT 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 3 of the License, or 
   (at your option) any later version. 
    
   ERT 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.   
    
   See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html> 
   for more details. 
*/


#include <stdlib.h>
#include <stdio.h>

#include <ert/util/util.h>
#include <ert/util/hash_node.h>
#include <ert/util/hash_sll.h>

#ifdef __cplusplus
extern "C" {
#endif

struct hash_sll_struct {
  int              length;
  hash_node_type * head;
};


static hash_sll_type * hash_sll_alloc( void ) {
  hash_sll_type * hash_sll = util_malloc(sizeof * hash_sll );
  hash_sll->length = 0;
  hash_sll->head   = NULL;
  return hash_sll;
}


hash_sll_type ** hash_sll_alloc_table(int size) {
  hash_sll_type ** table = util_malloc(size * sizeof * table );
  int i;
  for (i=0; i<size; i++)
    table[i] = hash_sll_alloc();
  return table;
}


void hash_sll_del_node(hash_sll_type *hash_sll , hash_node_type *del_node) {
  if (del_node == NULL) 
    util_abort("%s: tried to delete NULL node - aborting \n",__func__);

  {
    hash_node_type *node, *p_node;
    p_node = NULL;
    node   = hash_sll->head;
    while (node != NULL && node != del_node) {
      p_node = node;
      node   = hash_node_get_next(node);
    }

    if (node == del_node) {
      if (p_node == NULL) 
        /* 
           We are attempting to delete the first element in the list.
        */
        hash_sll->head = hash_node_get_next(del_node);
      else
        hash_node_set_next(p_node , hash_node_get_next(del_node));
      hash_node_free(del_node);
      hash_sll->length--;
    } else 
      util_abort("%s: tried to delete node not in list - aborting \n",__func__);

  }
}


hash_node_type * hash_sll_get_head(const hash_sll_type *hash_sll) { return hash_sll->head; }

void hash_sll_add_node(hash_sll_type *hash_sll , hash_node_type *new_node) {
  hash_node_set_next(new_node, hash_sll->head);
  hash_sll->head = new_node;
  hash_sll->length++;
}



void hash_sll_free(hash_sll_type *hash_sll) {
  if (hash_sll->head != NULL) {
    hash_node_type *node , *next_node;
    node = hash_sll->head;
    while (node != NULL) {
      next_node = hash_node_get_next(node);
      hash_node_free(node);
      node = next_node;
    }
  }
  free( hash_sll );
}


bool hash_sll_empty(const hash_sll_type * hash_sll) {
  if (hash_sll->length == 0)
    return true;
  else
    return false;
}


hash_node_type * hash_sll_get(const hash_sll_type *hash_sll, uint32_t global_index , const char *key) {
  hash_node_type * node = hash_sll->head;
  
  while ((node != NULL) && (!hash_node_key_eq(node , global_index , key))) 
    node = hash_node_get_next(node);
  
  return node;
}


bool hash_sll_has_key(const hash_sll_type *hash_sll , uint32_t global_index , const char *key) {
  if (hash_sll_get(hash_sll , global_index , key))
    return true;
  else
    return false;
}


#ifdef __cplusplus
}
#endif
