/**
 * Copyright INRIA and ENS, contributors Peterlongo and Chikhi
 * pierre.peterlongo@inria.fr
 * rayan.chikhi@irisa.fr
 *
 * This software is a computer program whose purpose is to detect the
 * presence of a starter in a set of NGS reads, and to provide the neighbor
 * in case of success..
 *
 * This software is governed by the CeCILL license under French law and
 * abiding by the rules of distribution of free software.  You can  use,
 * modify and/ or redistribute the software under the terms of the CeCILL
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".

 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability.

 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and,  more generally, to use and operate it in the
 * same conditions as regards security.
 *
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL license and that you accept its terms.
 */

/*
 * a simple implementation of a hash table, designed to be fast for key lookup
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "../commons.h"

#ifndef SIMPLEHASH_
#define SIMPLEHASH_
extern char keyi2nucleotide_array ['T'+1];

typedef unsigned int *hash_t;
typedef long* hash_iter;
typedef struct bucket
{
    const char *key;
    const void *value;
    struct bucket *next;
} bucket;

typedef struct
{
    bucket **buckets;

    // pool
    void **memory_pools;
    int nb_pools;
    int current_pool_pointer;

    // iterator
    signed int which_bucket;
    bucket *where_in_the_bucket;
} simplehash;





//#define DEBUG_SIMPLE_HASH

/*
 * simplehash has it's own memory pool for faster resizes/clears
 */
extern int POOL_CHUNK ;





//-------------------------------------------------
///////////// SIMPLE HASH FUNCTIONS /////////////

uint64_t compute_intermediate_hash(const char *key);

extern int nBUCKETS;
void custom_finalize_hash(int NBUCKETS);

uint64_t finalize_hash(uint64_t intermediate);

// also known as slow_hash_key
int slow_hash_key(const char *key);

// faster hashing by taking advantage of consecutive kmers

int fast_hash_key(const char *key, int k, uint64_t *intermediate_hash);



//-------------------------------------------------
///////////// END SIMPLE HASH FUNCTIONS /////////////








void *pool_malloc(simplehash *map, signed int alloc_size);

bucket * bucket_malloc(simplehash * map);

char*  pool_strdup(simplehash * map, const char *string);

void pools_free(simplehash *map);

extern int NBUCKETS;

/*
 * create the hash table
 */
hash_t hash_create(unsigned int nbuckets);

/*
 * free the structure
 */
void hash_free(hash_t given_map);

/*
 * just clear the structure, don't free
 */
void hash_clear_structure(hash_t given_map);


int compare_key(const char *key1,const char *key2);

/*
 * insert an element in the hash table
 *
 * hash_insert returns 0 on success
 *
 * in the case of mapsembler, hash_insert will only be used to insert pointers, so we dont need to reserve data space
 */
int hash_insert(hash_t given_map, const char *key, const void * data, size_t len);


/*
 * remove an element from the hash table
 */
int hash_remove(hash_t map, const char *key);


/*
 * retrieve an element from the hash table
 *
 * if mode==2, take advantage of the fact that we're hashing consecutive kmers
 * mode==1 computes the full hash everytime
 */
ssize_t generic_hash_entry_by_key(hash_t given_map, const char *key, int k, uint64_t *fast_hash, void **data, int mode);

ssize_t hash_entry_by_key(hash_t given_map, const char *key, void **data);

ssize_t fast_hash_entry_by_key(hash_t given_map, const char *key, int k, uint64_t *fast_hash,void **data);


/*
 * iterator functions
 *
 */
hash_iter hash_iterator_init(hash_t given_map);

hash_iter hash_iterator_next(hash_t given_map,  hash_iter iter);

int hash_iterator_is_end(hash_t given_map, hash_iter iter);

ssize_t hash_iterator_return_entry(hash_t given_map, hash_iter iter,
				   char **key, void **data);
#endif // SIMPLEHASH
