/** \file util.h
	Generic utilities library.
*/

#ifndef FISH_UTIL_H
#define FISH_UTIL_H

#include <wchar.h>
#include <stdarg.h>

/**
   Data structure for an automatically resizing dynamically allocated queue,
*/
typedef struct dyn_queue
{
	/** Start of the array */
	void **start;
	/** End of the array*/
	void **stop;
	/** Where to insert elements */
	void **put_pos;
	/** Where to remove elements */
	void **get_pos;
}
dyn_queue_t;

/**
   Internal struct used by hash_table_t.
*/
typedef struct
{
	/** Hash key*/
	const void *key;
	/** Value */
	const void *data;
}
hash_struct_t;

/**
   Data structure for the hash table implementaion. A hash table allows for
   retrieval and removal of any element in O(1), so long as a proper
   hash function is supplied.

   The hash table is implemented using a single hash function and
   element storage directly in the array. When a collision occurs, the
   hashtable iterates until a zero element is found. When the table is
   75% full, it will automatically reallocate itself. This
   reallocation takes O(n) time. The table is guaranteed to never be
   more than 75% full or less than 30% full (Unless the table is
   nearly empty). Its size is always a Mersenne number.

*/

typedef struct hash_table
{
	/** The array containing the data */
	hash_struct_t *arr;
	/** Number of elements */
	int count;
	/** Length of array */
	int size;
	/** Hash function */
	int (*hash_func)( const void *key );
	/** Comparison function */
	int (*compare_func)( const void *key1, const void *key2 );
}
hash_table_t;

/**
   Data structure for an automatically resizing dynamically allocated
   priority queue. A priority queue allows quick retrieval of the
   smallest element of a set (This implementation uses O(log n) time).
   This implementation uses a heap for storing the queue.
*/
typedef struct priority_queue
{
	/** Array contining the data */
	void **arr;
	/** Number of elements*/
	int count;
	/** Length of array */
	int size;
	/** Comparison function */
	int (*compare)(void *e1, void *e2);
}
priority_queue_t;

/**
   Array list struct.
   A dynamically growing list that supports stack operations.
*/
typedef struct array_list
{
	/** Array containing the data */
	const void **arr;
	/** Position to append elements at*/
	int pos;
	/** Length of array */
	int size;
}
array_list_t;

/**
   Linked list node.
*/
typedef struct _ll_node
{
	/** Next node */
	struct _ll_node *next, /** Previous node */ *prev;
	/** Node data */
	void *data;
}
ll_node_t;

/**
   Buffer for concatenating arbitrary data.
*/
typedef struct buffer
{
	char *buff; /**<data buffer*/
	size_t length; /**< Size of buffer */
	size_t used; /**< Size of data in buffer */
}
buffer_t;


/**
   String buffer struct.  An autoallocating buffer used for
   concatenating strings. This is really just a buffer_t.
*/
typedef buffer_t string_buffer_t;

	

/**
   Returns the larger of two ints
*/
int maxi( int a, int b );
/**
   Returns the smaller of two ints
 */
int mini( int a, int b );
/**
   Returns the larger of two floats
*/
float maxf( float a, float b );
/**
   Returns the smaller of two floats
*/
float minf( float a, float b );

/*
  All the datastuctures below autoresize. The queue, stack and
  priority queue are all impemented using an array and are guaranteed
  to never be less than 50% full. 
*/

/** 
	Initialize the queue. A queue is a FIFO buffer, i.e. the first
    element to be inserted into the buffer is the first element to be
    returned. 
*/
void q_init( dyn_queue_t *q );
/** Destroy the queue */
void q_destroy( dyn_queue_t *q );
/** Insert element into queue */
int q_put( dyn_queue_t *q, void *e );
/** Remove and return next element from queue */
void *q_get( dyn_queue_t *q);
/** Return next element from queue without removing it */
void *q_peek( dyn_queue_t *q);
/** Returns 1 if the queue is empty, 0 otherwise */
int q_empty( dyn_queue_t *q );

/**
   Initialize a hash table. The hash function must never return the value 0.
*/
void hash_init( hash_table_t *h,
				int (*hash_func)(const void *key),
				int (*compare_func)(const void *key1, const void *key2) );

/**
   Initialize a hash table. The hash function must never return the value 0.
*/
void hash_init2( hash_table_t *h,
				int (*hash_func)(const void *key),
				 int (*compare_func)(const void *key1, const void *key2),
				 size_t capacity);

/**
   Destroy the hash table and free associated memory.
*/
void hash_destroy( hash_table_t *h );
/**
   Set the key/value pair for the hashtable. 
*/
int hash_put( hash_table_t *h, 
			  const void *key,
			  const void *data );
/**
   Returns the data with the associated key, or 0 if no such key is in the hashtable
*/
const void *hash_get( hash_table_t *h,
					  const void *key );
/**
   Returns the hash tables version of the specified key
*/
const void *hash_get_key( hash_table_t *h, 
						  const void *key );

/**
   Returns the number of key/data pairs in the table.
*/
int hash_get_count( hash_table_t *h);
/**
   Remove the specified key from the hash table

   \param h The hashtable
   \param key The key
   \param old_key If not 0, a pointer to the old key will be stored at the specified address
   \param old_data If not 0, a pointer to the data will be stored at the specified address
*/
void hash_remove( hash_table_t *h, 
				  const void *key, 
				  const void **old_key,
				  const void **old_data );
/**
   Checks whether the specified key is in the hash table
*/
int hash_contains( hash_table_t *h, 
				   const void *key );

/**
   Appends all keys in the table to the specified list
*/
void hash_get_keys( hash_table_t *h,
					array_list_t *arr );
/**
   Appends all data elements in the table to the specified list
*/
void hash_get_data( hash_table_t *h,
					array_list_t *arr );
/** Call the function func for each key/data pair in the table*/
void hash_foreach( hash_table_t *h, 
				   void (*func)( const void *, const void * ) );
/** Same as hash_foreach, but the function func takes an additional
 * argument, which is provided by the caller in the variable aux */
void hash_foreach2( hash_table_t *h, void (*func)( const void *, 
												 const void *, 
												 void *), 
					void *aux );

/**
   Hash function suitable for character strings. 
*/
int hash_str_func( const void *data );
/**
   Hash comparison function suitable for character strings
*/
int hash_str_cmp( const void *a, const void *b );

/**
   Hash function suitable for wide character strings. 
*/
int hash_wcs_func( const void *data );

/**
   Hash comparison function suitable for wide character strings
*/
int hash_wcs_cmp( const void *a, const void *b );

/** Initialize the priority queue

 \param q the queue to initialize
 \param compare a comparison function that can compare two entries in the queue
*/
void pq_init( priority_queue_t *q,
			  int (*compare)(void *e1, void *e2) );
/**
   Add element to the queue

 \param q the queue
 \param e the new element
 
*/
int pq_put( priority_queue_t *q,
			 void *e );
/**
  Removes and returns the last entry in the priority queue
*/
void *pq_get( priority_queue_t *q );
/**
  Returns the last entry in the priority queue witout removing it.
*/
void *pq_peek( priority_queue_t *q );

/** 
	Returns 1 if the priority queue is empty, 0 otherwise.
*/
int pq_empty( priority_queue_t *q );

/**
   Returns the number of elements in the priority queue.
*/
int pq_get_count( priority_queue_t *q );

/** 
	Destroy the priority queue and free memory used by it.
*/
void pq_destroy(  priority_queue_t *q );

/**
   Allocate heap memory for creating a new list and initialize it
*/
array_list_t *al_new();

/** Initialize the list. */
void al_init( array_list_t *l );
/** Destroy the list and free memory used by it.*/
void al_destroy( array_list_t *l );
/**
   Append element to list

   \param l The list
   \param o The element
   \return
   \return 1 if succesfull, 0 otherwise
*/
int al_push( array_list_t *l, const void *o );
/**
   Append all elements of a list to another

   \param a The destination list
   \param b The source list
   \return 1 if succesfull, 0 otherwise
*/
int al_push_all( array_list_t *a, array_list_t *b );
/**
   Sets the element at the specified index

   \param l The array_list_t
   \param pos The index 
   \param o The element 
*/
int al_set( array_list_t *l, int pos, const void *o );
/**
   Returns the element at the specified index

   \param l The array_list_t
   \param pos The index 
   \return The element 
*/
const void *al_get( array_list_t *l, int pos );
/**
  Truncates the list to new_sz items.
*/
void al_truncate( array_list_t *l, int new_sz );
/**
  Removes and returns the last entry in the list
*/
const void *al_pop( array_list_t *l );
/**
   Returns the number of elements in the list
*/
int al_get_count( array_list_t *l );
/**
  Returns the last entry in the list witout removing it.
*/
const void *al_peek( array_list_t *l );
/** Returns 1 if the list is empty, 0 otherwise*/
int al_empty( array_list_t *l);
/** Call the function func for each entry in the list*/
void al_foreach( array_list_t *l, void (*func)(const void * ));
/** 
	Same as al_foreach, but the function func takes an additional
	argument, which is provided by the caller in the variable aux
*/
void al_foreach2( array_list_t *l, void (*func)(const void *, void *), void *aux);

/**
   Compares two wide character strings without case but with  
   a logical ordering for numbers.

   This function tries to order strings in a way which is intuitive to
   humans with regards to sorting strings containing numbers.

   Most sorting functions would sort the strings 'file1.txt'
   'file5.txt' and 'file12.txt' as:

   file1.txt
   file12.txt
   file5.txt

   This function regards any sequence of digits as a single entity
   when performing comparisons, so the output is instead:

   file1.txt
   file5.txt
   file12.txt

   Which most people would find more intuitive.

   The system breaks down if the user is using numbers of a base larger than 10.
*/
int wcsfilecmp( const wchar_t *a, const wchar_t *b );


/**
   Initialize the specified string_buffer
*/
void sb_init( string_buffer_t * );

string_buffer_t *sb_new();

/**
   Append a string to the buffer
*/
void sb_append( string_buffer_t *, const wchar_t * );

/**
   Append a part of a string to the buffer
*/
void sb_append_substring( string_buffer_t *, const wchar_t *, size_t );

/**
   Append a character to the buffer
*/
void sb_append_char( string_buffer_t *, wchar_t );


/**
   Append a null terminated list of strings to the buffer.
   Example:

   sb_append2( my_buff, L"foo", L"bar", 0 );
*/
void sb_append2( string_buffer_t *, ... );

/**
   Append formated string data to the buffer. This function internally
   relies on \c vswprintf, so any filter options supported by that
   function is also supported by this function
*/
int sb_printf( string_buffer_t *buffer, const wchar_t *format, ... );

/**
   Vararg version of sb_printf
*/
int sb_vprintf( string_buffer_t *buffer, const wchar_t *format, va_list va_orig );

/**
  Destroy the buffer and free it's memory
*/
void sb_destroy( string_buffer_t * );

/**
   Truncate the buffer.
*/
void sb_clear( string_buffer_t * );


/**
   Initialize the specified buffer_t
 */
void b_init( buffer_t *b);
/**
   Destroy the specified buffer_t
*/

void b_destroy( buffer_t *b );

/**
   Add data of the specified length to the specified buffer_t
*/
void b_append( buffer_t *b, const void *d, ssize_t len );

/**
   Get the current time in microseconds since Jan 1, 1970
*/
long long get_time();

#endif