#ifndef ACL_HTABLE_INCLUDE_H
#define ACL_HTABLE_INCLUDE_H

#ifdef  __cplusplus
extern "C" {
#endif

#include "acl_define.h"
#include "../thread/acl_thread.h"
#include "acl_hash.h"			/* just for ACL_HASH_FN */
#include "acl_slice.h"
#include "acl_iterator.h"

/*--------------------------------------------------------------------------*/
typedef struct ACL_HTABLE	ACL_HTABLE;
typedef struct ACL_HTABLE_INFO 	ACL_HTABLE_INFO;

/**
 * ϣṹ
 */
struct ACL_HTABLE {
	int     size;                   /* length of entries array */
	int     init_size;              /* length of initial entryies array */
	int     used;                   /* number of entries in table */
	ACL_HTABLE_INFO **data;         /* entries array, auto-resized */
	unsigned int flag;              /* properties flag */
	int     status;                 /* the operator's status on the htable */

	ACL_HASH_FN  hash_fn;           /* hash function */
	ACL_SLICE_POOL *slice;
	acl_pthread_mutex_t *rwlock;

	/* for acl_iterator */

	/* ȡͷ */
	void *(*iter_head)(ACL_ITER*, struct ACL_HTABLE*);
	/* ȡһ */
	void *(*iter_next)(ACL_ITER*, struct ACL_HTABLE*);
	/* ȡβ */
	void *(*iter_tail)(ACL_ITER*, struct ACL_HTABLE*);
	/* ȡһ */
	void *(*iter_prev)(ACL_ITER*, struct ACL_HTABLE*);
	/* ȡĵǰԱṹ */
	ACL_HTABLE_INFO *(*iter_info)(ACL_ITER*, struct ACL_HTABLE*);
};

/**
 * ϣÿһϣĴ洢Ϣ
 */
struct ACL_HTABLE_INFO {
	/**
	 * ϣ, ֻΪϣı־λΪ
	 * ACL_BINHASH_FLAG_KEY_REUSE ʱҪļռ
	 */
	union {
		char *key;
		const char *c_key;
	} key;
	void   *value;			/**< associated value */
	unsigned hash;			/**< store the key's hash value */
	struct ACL_HTABLE_INFO *next;	/**< colliding entry */
	struct ACL_HTABLE_INFO *prev;	/**< colliding entry */
};

/**
 * ACL_HTABLE 
 */
typedef struct ACL_HTABLE_ITER {
	/* public */
	ACL_HTABLE_INFO *ptr;

	/* private */
	int  i;
	int  size;
	ACL_HTABLE_INFO **h;
} ACL_HTABLE_ITER;

/**
 * ϣ
 * @param size ϣ
 * @param flag {unsigned int} ϣԱ־λ, ACL_BINHASH_FLAG_xxx
 * @return ϣͷָΪ(ʱʾصĴ, Ҫڴ)
 */
ACL_API ACL_HTABLE *acl_htable_create(int size, unsigned int flag);
/* µĶʱǷֱӸüַ */
#define	ACL_HTABLE_FLAG_KEY_REUSE	(1 << 0)

/* Ƿö̻߳ⷽʽ */
#define	ACL_HTABLE_FLAG_USE_LOCK	(1 << 1)

/* ÿβѯʱǷ񽫲ѯͷ */
#define	ACL_HTABLE_FLAG_MSLOOK		(1 << 2)

/* ͳһתΪСдӶʵּѯִСдĹ */
#define	ACL_HTABLE_FLAG_KEY_LOWER	(1 << 3)

ACL_API ACL_HTABLE *acl_htable_create3(int size, unsigned int flag,
		ACL_SLICE_POOL *slice);

/**
 * ùϣĿƲ
 * @param table ϣ
 * @param name Ʋıγʼֵ, name ԺĿƲ¶
 *  ACL_HTABLE_CTL_END: α־
 *  ACL_HTABLE_CTL_RWLOCK: Ƿöд
 *  ACL_HTABLE_CTL_HASH_FN: ûԶĹϣֵ㺯
 */
ACL_API void acl_htable_ctl(ACL_HTABLE *table, int name, ...);
#define	ACL_HTABLE_CTL_END      0  /**< ƽ־ */
#define	ACL_HTABLE_CTL_RWLOCK   1  /**< Ƿ */
#define	ACL_HTABLE_CTL_HASH_FN  2  /**< ˽йϣ */

/**
 * һιϣϣ״̬
 * @param table ϣָ
 * @return {int} ϣ״̬, μµ ACL_HTABLE_STAT_XXX
 */
ACL_API int acl_htable_errno(ACL_HTABLE *table);
#define	ACL_HTABLE_STAT_OK          0  /**< ״̬ */
#define	ACL_HTABLE_STAT_INVAL       1  /**< Ч */
#define	ACL_HTABLE_STAT_DUPLEX_KEY  2  /**< ظ */

/**
 * ùϣĵǰ״̬, error ȡֵ ACL_HTABLE_STAT_XXX
 * @param table ϣָ
 * @param error ùϣĴ״̬
 */
ACL_API void acl_htable_set_errno(ACL_HTABLE *table, int error);

ACL_API void acl_htable_lock_read(ACL_HTABLE *table);
ACL_API void acl_htable_lock_write(ACL_HTABLE *table);
ACL_API void acl_htable_unlock(ACL_HTABLE *table);

/**
 * ϣµ
 * @param table ϣָ
 * @param key , ںڲḴƴ key 
 * @param value ûԼض(Ӳת, Ǵ
 *  ܶջ)
 * @return Ĺϣָ, == NULL: ʾڲڴ, ΪصĴ
 *  עʱùϣڣ򷵻ѾڵĹϣʹӦͨ
 *  acl_htable_errno() 鿴Ƿظͬһֵ(ACL_HTABLE_STAT_DUPLEX_KEY)
 */
ACL_API ACL_HTABLE_INFO *acl_htable_enter(ACL_HTABLE *table,
		const char *key, void *value);

/**
 * ϣµ߳ͬʱд˲ʱڲԶ֤
 * @param table ϣָ
 * @param key , ںڲḴƴ key 
 * @param value ûԼض(Ӳת, Ǵ
 *  ܶջ)
 * @param old_holder {void**}  key ұǿʱڲԶֵ滻
 *  ֵ old_holder žֵַԷӦͷ
 * @return Ĺϣָ, == NULL: ʾڲڴ, ΪصĴ
 *  עʱùϣڣ򷵻ѾڵĹϣʹӦͨ
 *  acl_htable_errno() 鿴Ƿظͬһֵ(ACL_HTABLE_STAT_DUPLEX_KEY)
 */
ACL_API ACL_HTABLE_INFO *acl_htable_enter_r2(ACL_HTABLE *table,
		const char *key, void *value, void **old_holder);

ACL_API ACL_HTABLE_INFO *acl_htable_enter_r(ACL_HTABLE *table,
		const char *key, void *value);

/**
 *  key Ѱĳһضϣ
 * @param table ϣָ
 * @param key 
 * @return Ϊָ: ʾ鵽˶Ӧ key Ĺϣ
 *         Ϊ: ʾδ鵽Ӧ key Ĺϣ
 */
ACL_API ACL_HTABLE_INFO *acl_htable_locate(ACL_HTABLE *table, const char *key);

/**
 *  key Ѱĳһضϣ߳ͬʱд˲ʱ
 * ڲԶ֤
 * @param table ϣָ
 * @param key 
 * @return Ϊָ: ʾ鵽˶Ӧ key Ĺϣ
 *         Ϊ: ʾδ鵽Ӧ key Ĺϣ
 */
ACL_API ACL_HTABLE_INFO *acl_htable_locate_r(ACL_HTABLE *table, const char *key);

/**
 *  key Ѱû
 * @param table ϣָ
 * @param key 
 * @return Ϊ: ʾ鵽˶Ӧ key , ûԸûԼ
 *  ͽת; Ϊ: ʾδ鵽Ӧ key 
 */
ACL_API void *acl_htable_find(ACL_HTABLE *table, const char *key);

/**
 *  key Ѱû, ߳ͬʱд˲ʱ
 * ڲԶ֤
 * @param table ϣָ
 * @param key 
 * @return Ϊ: ʾ鵽˶Ӧ key , ûԸûԼ
 *  ͽת; Ϊ: ʾδ鵽Ӧ key 
 */
ACL_API void *acl_htable_find_r(ACL_HTABLE *table, const char *key);

/**
 *  key ɾĳһϣ
 * @param table ϣָ
 * @param key 
 * @param free_fn úָ벻Ϊղҵ˶Ӧ key , 
 *  ûṩһЩβ, ȻͷŸùϣ
 * @return 0: ɹ;  -1: δҵ key 
 */
ACL_API int acl_htable_delete(ACL_HTABLE *table, const char *key,
		void (*free_fn) (void *));
#define	acl_htable_delete_r	acl_htable_delete

/**
 * ֱӸ acl_htable_locate صķǿնӹϣɾö
 * @param table ϣָ
 * @param ht {ACL_HTABLE_INFO*} 洢ڹϣеڲṹ
 * @param free_fn úָ벻Ϊղҵ˶Ӧ key , 
 *  ûṩһЩβ, ȻͷŸùϣ
 */
ACL_API void acl_htable_delete_entry(ACL_HTABLE *table, ACL_HTABLE_INFO *ht,
		void (*free_fn) (void *));

/**
 * ͷϣ
 * @param table ϣָ
 * @param free_fn ָ벻ΪԹϣеÿһϣøú
 *  β, Ȼͷ
 */
ACL_API void acl_htable_free(ACL_HTABLE *table, void (*free_fn) (void *));

/**
 * ùϣ, úͷŹϣе, ³ʼ
 * @param table ϣָ
 * @param free_fn ָ벻ΪԹϣеÿһϣøú
 *  β, Ȼͷ
 * @return Ƿóɹ. 0: OK; < 0: error.
 */
ACL_API int acl_htable_reset(ACL_HTABLE *table, void (*free_fn) (void *));
#define	acl_htable_reset_r	acl_htable_reset

/**
 * Թϣеÿһϣд
 * @param table ϣָ
 * @param walk_fn ÿһϣĺָ, Ϊ
 * @param arg ûԼ͵
 */
ACL_API void acl_htable_walk(ACL_HTABLE *table,
		void (*walk_fn) (ACL_HTABLE_INFO *, void *), void *arg);
#define	acl_htable_walk_r	acl_htable_walk

/**
 * عϣǰռС
 * @param table ϣָ
 * @return ϣռС
 */
ACL_API int acl_htable_size(const ACL_HTABLE *table);

/**
 * عϣǰĴԪظ
 * @param table ϣָ
 * @return ϣԪظ
 */
ACL_API int acl_htable_used(const ACL_HTABLE *table);

/**
 * ϣϳһ
 * @param table ϣ
 * @return Ϊ: ָ; Ϊ: ʾùϣûйϣ
 */
ACL_API ACL_HTABLE_INFO **acl_htable_list(const ACL_HTABLE *table);

/**
 * ʾϣ key ķֲ״̬
 * @param table ϣָ
 */
ACL_API void acl_htable_stat(const ACL_HTABLE *table);
#define	acl_htable_stat_r	acl_htable_stat

ACL_API ACL_HTABLE_INFO **acl_htable_data(ACL_HTABLE *table);
ACL_API const ACL_HTABLE_INFO *acl_htable_iter_head(
		ACL_HTABLE *table, ACL_HTABLE_ITER *iter);
ACL_API const ACL_HTABLE_INFO *acl_htable_iter_next(ACL_HTABLE_ITER *iter);
ACL_API const ACL_HTABLE_INFO *acl_htable_iter_tail(
		ACL_HTABLE *table, ACL_HTABLE_ITER *iter);
ACL_API const ACL_HTABLE_INFO *acl_htable_iter_prev(ACL_HTABLE_ITER *iter);

/*--------------------  һЩݵĺ --------------------------------*/

#define	ACL_HTABLE_ITER_KEY(iter)	((iter).ptr->key.c_key)
#define	acl_htable_iter_key		ACL_HTABLE_ITER_KEY

#define	ACL_HTABLE_ITER_VALUE(iter)	((iter).ptr->value)
#define	acl_htable_iter_value		ACL_HTABLE_ITER_VALUE

/**
 *  ACL_HTABLE
 * @param iter {ACL_HTABLE_ITER}
 * @param table_ptr {ACL_HTABLE *}
 * @example:
	void test()
	{
		ACL_HTABLE *table = acl_htable_create(10, 0);
		ACL_HTABLE_ITER iter;
		char *value, key[32];
		int   i;

		for (i = 0; i < 100; i++) {
			value = (char*) acl_mystrdup("value");
			snprintf(key, sizeof(key), "key:%d", i);
			(void) acl_htable_enter(table, key, value);
		}

		acl_htable_foreach(iter, table) {
			printf("%s=%s\n", acl_htable_iter_key(iter),
				acl_htable_iter_value(iter));
			if (i == 50)
				break;
		}
		acl_htable_free(table, acl_myfree_fn);
	}
 */

#if 0
#define	ACL_HTABLE_FOREACH(iter, table_ptr)  \
    if (table_ptr)  \
        for((iter).size = acl_htable_size((table_ptr)), (iter).i = 0,  \
          (iter).h = acl_htable_data((table_ptr)); (iter).i < (iter).size; (iter).i++)  \
            for ((iter).ptr = *(iter).h++; (iter).ptr; (iter).ptr = (iter).ptr->next)
#define	ACL_HTABLE_FOREACH_REVERSE(iter, table_ptr)  \
    if (table_ptr)  \
        for((iter).size = acl_htable_size((table_ptr)), (iter).i = (iter).size - 1,  \
          (iter).h = acl_htable_data((table_ptr)) + (iter).i; (iter).i >= 0; (iter).i--)  \
            for ((iter).ptr = *(iter).h--; (iter).ptr; (iter).ptr = (iter).ptr->next)
#else
#define	ACL_HTABLE_FOREACH(iter, table_ptr)  \
    if (table_ptr)  \
        for((void) acl_htable_iter_head((table_ptr), &iter);  \
            (iter).ptr;  \
            (void) acl_htable_iter_next(&iter))
#define	ACL_HTABLE_FOREACH_REVERSE(iter, table_ptr)  \
    if (table_ptr)  \
        for((void) acl_htable_iter_tail((table_ptr), &iter);  \
            (iter).ptr;  \
            (void) acl_htable_iter_prev(&iter))
#endif

#define	acl_htable_foreach		ACL_HTABLE_FOREACH
#define	acl_htable_foreach_reverse	ACL_HTABLE_FOREACH_REVERSE

#ifdef  __cplusplus
}
#endif

#endif

