/*
 * This file is part of the Poliqarp suite.
 * 
 * Copyright (C) 2004-2009 by Instytut Podstaw Informatyki Polskiej
 * Akademii Nauk (IPI PAN; Institute of Computer Science, Polish
 * Academy of Sciences; cf. www.ipipan.waw.pl).  All rights reserved.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file gpl.txt included in the packaging
 * of this file.  (See http://www.gnu.org/licenses/translations.html for
 * unofficial translations.)
 * 
 * A commercial license is available from IPI PAN (contact
 * Michal.Ciesiolka@ipipan.waw.pl or ipi@ipipan.waw.pl for more
 * information).  Licensees holding a valid commercial license from IPI
 * PAN may use this file in accordance with that license.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

#ifndef BP_BINARY_POOL_H
#define BP_BINARY_POOL_H

#include <stdlib.h>
#include <sakura/common/memory-arena.h>

#include "viewport.h"

#define BINARY_POOL_ALIGNMENT        (sizeof(uint32_t))

/* make chains ordered */
/* #define USE_ORDERED_LIST */

typedef int (*compar_fn_t)(const void *, const void *);

struct binary_pool_node {
   size_t id;     /**< unique identifier */
   uint32_t count;  /**< frequency count */
   uint32_t length; /**< data length */
   void *data;    /**< data pointer */
};

struct binary_pool_chain {
   struct binary_pool_node node;
   struct binary_pool_chain *next;
};

struct binary_pool {
   struct binary_pool_chain *hash_array; /**< chained hash array */
   size_t array_size;                    /**< array size */
   size_t num_items;                     /**< number of unique items */
   struct binary_pool_node *dense_array; /**< dense array */
   /* base + offset[index[key]] == object */
   uint32_t *index;
   uint32_t *offset;
   struct binary_pool_chain *last;       /**< cached last object */
   struct marena *arena;                 /**< memory source */
};

/* this routine compares nodes in REVERSED order */
int binary_pool_compare_freq(const void *p1, const void *p2);

/* this routine compares nodes */
int binary_pool_compare_alpha(const void *p1, const void *p2);

/* this routine compares nodes, regardless of case*/
int binary_pool_compare_ialpha(const void *p1, const void *p2);

/* this routine compares nodes */
int binary_pool_compare_atergo(const void *p1, const void *p2);

int binary_pool_compare_iatergo(const void *p1, const void *p2);

/* initialize pool structs */
void binary_pool_init(struct binary_pool *this, struct marena *arena, 
   size_t size);

/* free pool structs */
void binary_pool_free(struct binary_pool *this);

/* add all items from dict */
int binary_pool_add_dict(struct binary_pool *pool, const char *image_pathname,
   const char *offset_pathname);

/* as above including frequency */
int binary_pool_add_dict_freq(struct binary_pool *pool, 
   const char *image_pathname, const char *offset_pathname, 
   const char *freq_pathname);

/* add object */
struct binary_pool_node *binary_pool_add(struct binary_pool *this,
   const void *buffer, size_t length);

/* add object */
struct binary_pool_node *binary_pool_add_freq(struct binary_pool *this,
   const void *buffer, size_t length, size_t freq);

/* add string, terminate with extra allocated \0 */
struct binary_pool_node *binary_pool_add_string(struct binary_pool *this,
   const void *buffer, size_t length);

/** Adds a zero-terminated string to the pool. */
struct binary_pool_node *binary_pool_add_string2(struct binary_pool *this,
   const char *str);

/** Retrieves an object from pool by ID. */
const void *binary_pool_get_by_id(const struct binary_pool *this, 
   size_t id);

/** 
 * Adds a lowercase-converted version of a zero-terminated string to 
 * the pool.
 */
struct binary_pool_node *binary_pool_add_string_lowercase(
   struct binary_pool *this, const char *str);

/* find object */
struct binary_pool_node *binary_pool_lookup(struct binary_pool *this,
   const void *buffer, size_t length);

/* find string */
struct binary_pool_node *binary_pool_lookup_string(struct binary_pool *this,
   const void *buffer, size_t length);

/* create dense array of nodes good for sorting */
void binary_pool_make_dense_array(struct binary_pool *this);

/* reset index */
void binary_pool_reset_index(struct binary_pool *this);

/* sort the index according to given comparator */
void binary_pool_sort(struct binary_pool *this, compar_fn_t comparator);

/* sort the index according to given comparator */
void binary_pool_sort_index(struct binary_pool *this, compar_fn_t comparator);

/* write index to stream */
void binary_pool_write_index(struct binary_pool *this, FILE * stream);

/* write data/offsets to stream */
void binary_pool_write_data(struct binary_pool *this, FILE *stream);

/* write offsets to stream */
void binary_pool_write_offsets(struct binary_pool *this, FILE *stream);

void binary_pool_debug(struct binary_pool *this, struct viewport *vp);

size_t binary_pool_longest_item(struct binary_pool *this);

size_t binary_pool_num_less_freq_than(struct binary_pool *this, size_t freq);

size_t binary_pool_num_more_freq_than(struct binary_pool *this, size_t freq);

#endif /* BP_BINARY_POOL_H */
