#ifndef	ACL_DBPOOL_INCLUDE_H
#define	ACL_DBPOOL_INCLUDE_H

#ifndef ACL_CLIENT_ONLY

#ifdef	__cplusplus
extern "C" {
#endif

#include "../stdlib/acl_define.h"
#include <time.h>
#include "../stdlib/acl_stdlib.h"

#define	ACL_DB_DEBUG_MEM	(1<<0)

typedef struct ACL_DB_HANDLE ACL_DB_HANDLE;
typedef struct ACL_SQL_RES ACL_SQL_RES;
typedef struct ACL_DB_POOL ACL_DB_POOL;

typedef struct ACL_DB_INFO {
	int   db_max;		/* ӳ */
	char  db_addr[256];	/* ݿַ */
	char  db_name[256];	/* ݿ */
	char  db_user[256];	/* ݿʺ */
	char  db_pass[256];	/* ʺ */
	unsigned long db_flags;	/* (mysql) ӱ־λ */
	int   ping_inter;	/* ̽ݿӵʱ */
	int   timeout_inter;	/* ݿӵĿгʱʱ */
	int   auto_commit;	/* (mysql) ǷԶύ */
	int   conn_timeout;	/* (mysql/null) ӳʱʱ */
	int   rw_timeout;	/* (mysql/null) IOдʱʱ */
	int   buf_size;		/* (null) IOС */
	int   debug_flag;	/* Ա־λ */

	/* ʵݿ֮ǰ/ûõĻص, Ϊ NULL,
	 *  db_before_connect/db_after_connect  < 0 ᵼ
	 * acl_dbpool_peek  NULL
	 */
	int  (*db_before_connect)(ACL_DB_HANDLE* db_handle, void *ctx);
	int  (*db_after_connect)(ACL_DB_HANDLE* db_handle, void *ctx);

	void *ctx;		/* db_before_connect/db_after_connect ֮һ */
} ACL_DB_INFO;

struct ACL_DB_HANDLE {
#define	ACL_DBH_STATUS_NULL	0
#define	ACL_DBH_STATUS_READY	1
#define	ACL_DBH_STATUS_INUSE	2
	int    status;
	time_t timeout;
	time_t ping;

	ACL_DB_POOL *parent;

	int (*sql_results)(ACL_DB_HANDLE *handle, const char *sql, int  *error,
		int (*walk_fn)(const void** result_row, void *arg), void *arg);
	int (*sql_result)(ACL_DB_HANDLE *handle, const char *sql, int  *error,
		int (*callback)(const void** result_row, void *arg), void *arg);
	int (*sql_update)(ACL_DB_HANDLE *handle, const char *sql, int  *error);

	ACL_SQL_RES *(*sql_select)(ACL_DB_HANDLE *handle, const char *sql, int *error);
	void (*free_result)(ACL_SQL_RES *res);
};

struct ACL_SQL_RES {
	void *res;
	int   num;

        /* for acl_iterator */

	/* ȡͷ */
	const void *(*iter_head)(ACL_ITER*, struct ACL_SQL_RES*);
	/* ȡһ */
	const void *(*iter_next)(ACL_ITER*, struct ACL_SQL_RES*);
};

struct ACL_DB_POOL {
	ACL_DB_INFO db_info;

	ACL_DB_HANDLE *(*dbh_peek)(ACL_DB_POOL *);
	void  (*dbh_check)(ACL_DB_POOL *);
	void  (*dbh_release)(ACL_DB_HANDLE *);
	void *(*dbh_export)(ACL_DB_HANDLE *);
	void  (*dbh_close)(ACL_DB_HANDLE *);
	int   (*dbh_ping)(ACL_DB_HANDLE *);

	void  (*destroy)(ACL_DB_POOL *);

	int  db_max;
	int  db_ready;
	int  db_inuse;
};

/*----------------------------------------------------------------------------*/
#define	ACL_DB_AUTO_COMMIT(_db_pool_) (_db_pool_ ? _db_pool_->db_info.auto_commit : 0)

/* in acl_dbpool.c */
/**
 * һݿӳ
 * @param db_type {const char*} ݿ, Ŀǰ֧ mysql
 * @param db_info {const ACL_DB_INFO*} ¼йҪϢ
 * @return {ACL_DB_POOL*} һݿӳ
 */
ACL_API ACL_DB_POOL *acl_dbpool_create(const char *db_type, const ACL_DB_INFO *db_info);

/**
 * һݿӳ
 * @param db_pool ݿӳؾ
 */
ACL_API void acl_dbpool_destroy(ACL_DB_POOL *db_pool);

/**
 * ӳлȡһӾ
 * @param db_pool {ACL_DB_POOL*} ݿӳؾ
 * @return {ACL_DB_HANDLE*} ݿӾΪʾӳ
 */
ACL_API ACL_DB_HANDLE *acl_dbpool_peek(ACL_DB_POOL *db_pool);

/**
 * ֹӳصÿ?һӳڲᶨڼÿӣ
 * Ҳͨ˺ֹǿƼ
 * @param db_pool {ACL_DB_POOL*} ݿӳؾ
 */
ACL_API void acl_dbpool_check(ACL_DB_POOL *db_pool);

/**
 * ݿӾͷŸݿӳ
 * @param db_handle {ACL_DB_HANDLE*} ݿӾ
 */
ACL_API void acl_dbpool_release(ACL_DB_HANDLE *db_handle);
/**
 * ݿתΪʵʵݿӾ
 * @param db_handle {ACL_DB_HANDLE*} ݿӾ
 * @return void * ʹҪǿתΪԼõݿ
 */
ACL_API void *acl_dbpool_export(ACL_DB_HANDLE *db_handle);
/**
 * ʹԼ⵽ݿӳʱͨ˽ӿǿйرո
 * @param db_handle {ACL_DB_HANDLE*} ݿӾ
 */
ACL_API void acl_dbpool_close(ACL_DB_HANDLE *db_handle);

/**
 * ӳصĶʱPINGôֵڲȱʡʽ
 * @param db_pool {ACL_DB_POOL*} ݿӳؾ
 * @param ping_fn {int (*)(ACL_DB_HANDLE*)} ̽״̬ĺָ
 */
ACL_API void acl_dbpool_set_ping(ACL_DB_POOL *db_pool, int (*ping_fn)(ACL_DB_HANDLE*));
/*----------------------------------------------------------------------------*/

#ifdef	__cplusplus
}
#endif

#endif /* ACL_CLIENT_ONLY */
#endif
