#ifndef ACL_JSON_INCLUDE_H
#define ACL_JSON_INCLUDE_H

#ifdef __cplusplus
extern "C" {
#endif

#include "../stdlib/acl_define.h"
#include "../stdlib/acl_dbuf_pool.h"
#include "../stdlib/acl_iterator.h"
#include "../stdlib/acl_vstring.h"
#include "../stdlib/acl_ring.h"
#include "../stdlib/acl_array.h"

typedef struct ACL_JSON ACL_JSON;
typedef struct ACL_JSON_NODE ACL_JSON_NODE;

struct ACL_JSON_NODE {
	ACL_VSTRING *ltag;          /**< ǩ */
	ACL_VSTRING *text;          /**< ڵΪҶڵʱıݷǿ */
	ACL_JSON_NODE *tag_node;    /**< ǩֵΪ json ڵʱǿ */
	ACL_JSON_NODE *parent;      /**< ڵ */
	ACL_RING children;          /**< ӽڵ㼯 */
	unsigned short type;        /**< ڵ */
#define	ACL_JSON_T_A_STRING      (1 << 0)
#define	ACL_JSON_T_A_NUMBER      (1 << 1)
#define	ACL_JSON_T_A_BOOL        (1 << 2)
#define	ACL_JSON_T_A_NULL        (1 << 3)
#define	ACL_JSON_T_A_DOUBLE      (1 << 4)

#define	ACL_JSON_T_A_TYPES       (ACL_JSON_T_A_NULL | ACL_JSON_T_A_BOOL | \
	ACL_JSON_T_A_NUMBER | ACL_JSON_T_A_DOUBLE | ACL_JSON_T_A_STRING)

#define	ACL_JSON_T_STRING        (1 << 5)
#define	ACL_JSON_T_NUMBER        (1 << 6)
#define	ACL_JSON_T_BOOL          (1 << 7)
#define	ACL_JSON_T_NULL          (1 << 8)
#define ACL_JSON_T_DOUBLE        (1 << 9)

#define ACL_JSON_T_ARRAY         (1 << 10)
#define ACL_JSON_T_OBJ           (1 << 11)
#define ACL_JSON_T_LEAF          (1 << 12)
#define ACL_JSON_T_MEMBER        (1 << 13)
#define ACL_JSON_T_PAIR          (1 << 14)
#define	ACL_JSON_T_ELEMENT       (1 << 15)

	unsigned short depth;       /**< ǰڵ */

	/* private */
	unsigned char quote;        /**<  0 ʾ '  " */
	unsigned char left_ch;      /**< ڵĵһַ: { or [ */
	unsigned char right_ch;     /**< ڵһַ: } or ] */
	unsigned backslash:1;       /**< תַ \ */
	unsigned part_word:1;       /**< ֵ־λ */
	unsigned disabled:1;        /**< ýڵǷ񱻽ֹ */
	ACL_JSON *json;             /**< json  */
	ACL_RING  node;             /**< ǰڵ */

	/* public: for acl_iterator, ͨ acl_foreach гýڵһӽڵ */

	/* ȡͷ */
	ACL_JSON_NODE *(*iter_head)(ACL_ITER*, ACL_JSON_NODE*);
	/* ȡһ */
	ACL_JSON_NODE *(*iter_next)(ACL_ITER*, ACL_JSON_NODE*);
	/* ȡβ */
	ACL_JSON_NODE *(*iter_tail)(ACL_ITER*, ACL_JSON_NODE*);
	/* ȡһ */
	ACL_JSON_NODE *(*iter_prev)(ACL_ITER*, ACL_JSON_NODE*);
};

enum {
	ACL_JSON_S_ROOT,	/**< ڵ */
	ACL_JSON_S_OBJ,		/**< ǩֵ */
	ACL_JSON_S_MEMBER,
	ACL_JSON_S_ARRAY,	/**< json ڵ array */
	ACL_JSON_S_ELEMENT,
	ACL_JSON_S_PAIR,	/**< name:value pair */
	ACL_JSON_S_NEXT,	/**< һڵ */
	ACL_JSON_S_TAG,		/**< ǩ */
	ACL_JSON_S_VALUE,	/**< ڵֵ */
	ACL_JSON_S_COLON,	/**< ð : */
	ACL_JSON_S_STRING,
	ACL_JSON_S_STREND
};

struct ACL_JSON {
	int   depth;                /**<  */
	int   node_cnt;             /**< ڵ,  root ڵ */
	ACL_JSON_NODE *root;        /**< json ڵ */
	int   finish;               /**< Ƿ */
	unsigned flag;              /**< ־λ */
#define	ACL_JSON_FLAG_PART_WORD	(1 << 0)  /**< Ƿݰ */
#define ACL_JSON_FLAG_ADD_SPACE	(1 << 1)  /**<  json ʱǷո */

	/* public: for acl_iterator, ͨ acl_foreach гӽڵ */

	/* ȡͷ */
	ACL_JSON_NODE *(*iter_head)(ACL_ITER*, ACL_JSON*);
	/* ȡһ */
	ACL_JSON_NODE *(*iter_next)(ACL_ITER*, ACL_JSON*);
	/* ȡβ */
	ACL_JSON_NODE *(*iter_tail)(ACL_ITER*, ACL_JSON*);
	/* ȡһ */
	ACL_JSON_NODE *(*iter_prev)(ACL_ITER*, ACL_JSON*);

	/* private */

	int   status;               /**< ״̬ǰ״̬ */

	ACL_JSON_NODE *curr_node;   /**< ǰڴ json ڵ */
	ACL_DBUF_POOL *dbuf;        /**< Ựڴض */
	ACL_DBUF_POOL *dbuf_inner;  /**< Ựڴض */
	size_t dbuf_keep;
};

/*----------------------------- in acl_json.c -----------------------------*/

/**
 * һ json ڵ
 * @param json {ACL_JSON*} json 
 * @return {ACL_JSON_NODE*} json ڵ
 */
ACL_API ACL_JSON_NODE *acl_json_node_alloc(ACL_JSON *json);

/**
 * ĳ json ڵ㼰ӽڵ json ɾ, ͷŸýڵ㼰ӽڵ
 * ռռ亯ͷŸ json ڵռڴ
 * @param node {ACL_JSON_NODE*} json ڵ
 * @return {int} ɾĽڵ
 */
ACL_API int acl_json_node_delete(ACL_JSON_NODE *node);

/**
 * ӵǰ json ڵɾڵ㣬һ json ڵ
 * @param node {ACL_JSON_NODE*} json ڵ
* @return {ACL_JSON_NODE*} صһ json ڵ
 */
ACL_API ACL_JSON_NODE *acl_json_node_erase(ACL_JSON_NODE *node, ACL_ITER *it);

/**
 * ӵǰ json ڵɾڵ㣬һ json ڵ
 * @param node {ACL_JSON_NODE*} json ڵ
* @return {ACL_JSON_NODE*} صǰһ json ڵ
 */
ACL_API ACL_JSON_NODE *acl_json_node_rerase(ACL_JSON_NODE *node, ACL_ITER *it);

/**
 * ֹ/ĳ json ڵ㣬ֹĽڵڹ json ַʱӣڱ json ʱ
 * ȴԱãԷٴν
 * @param node {ACL_JSON_NODE*} json ڵ
 * @param yes {int} Ƿֹ json ڵ
 */
ACL_API void acl_json_node_disable(ACL_JSON_NODE *node, int yes);

/**
 * жָ json ڵǷѾֹ
 * @param node {ACL_JSON_NODE*} json ڵ
 * @return {int}  0 ʾδֹ״̬ʾֹ
 */
ACL_API int acl_json_node_disabled(ACL_JSON_NODE *node);

/**
 * ĳ json ڵֵܽڵ(ֵܽڵǶ json ڵ)
 * @param node1 {ACL_JSON_NODE*} 򱾽ڵ json ڵ
 * @param node2 {ACL_JSON_NODE*} ӵֵ json ڵ
 */
ACL_API void acl_json_node_append(ACL_JSON_NODE *node1, ACL_JSON_NODE *node2);

/**
 * ĳ json ڵΪӽڵĳ json ڵ
 * @param parent {ACL_JSON_NODE*} ڵ
 * @param child {ACL_JSON_NODE*} ӽڵ
 */
ACL_API void acl_json_node_add_child(ACL_JSON_NODE *parent, ACL_JSON_NODE *child);

/**
 * һ JSON  JSON ڵ㸴 JSON еһ JSON ڵУ
 * Ŀ´ JSON ڵ
 * @param json {ACL_JSON*} Ŀ JSON 
 * @param from {ACL_JSON_NODE*} Դ JSON һ JSON ڵ
 * @return {ACL_JSON_NODE*} طǿնָ
 */
ACL_API ACL_JSON_NODE *acl_json_node_duplicate(ACL_JSON *json, ACL_JSON_NODE *from);

/**
 * ĳ json ڵĸڵ
 * @param node {ACL_JSON_NODE*} json ڵ
 * @return {ACL_JSON_NODE*} ڵ, Ϊ NULL ʾ丸ڵ㲻
 */
ACL_API ACL_JSON_NODE *acl_json_node_parent(ACL_JSON_NODE *node);

/**
 * ĳ json ڵĺһֵܽڵ
 * @param node {ACL_JSON_NODE*} json ڵ
 * @return {ACL_JSON_NODE*}  json ڵĺһֵܽڵ, ΪNULLʾ
 */
ACL_API ACL_JSON_NODE *acl_json_node_next(ACL_JSON_NODE *node);

/**
 * ĳ json ڵǰһֵܽڵ
 * @param node {ACL_JSON_NODE*} json ڵ
 * @return {ACL_JSON_NODE*}  json ڵǰһֵܽڵ, ΪNULLʾ
 */
ACL_API ACL_JSON_NODE *acl_json_node_prev(ACL_JSON_NODE *node);

/**
 * ڱ Json Уɾǰָ json ڵ㲢һ json ڵ
 * @param json {ACL_JSON*} json 
 * @param it {ACL_ITER*}  json ĵ
 * @return {ACL_JSON_NODE*} һ json ڵ
 */
ACL_API ACL_JSON_NODE *acl_json_erase(ACL_JSON *json, ACL_ITER *it);

/**
 * һ json 
 * @return {ACL_JSON*} ´ json 
 */
ACL_API ACL_JSON *acl_json_alloc(void);

/**
 * һ json 
 * @param dbuf {ACL_DBUF_POOL*} ڴض󣬵Է NULL ʱ json 
 *  ڵڴϽз䣬ڲԶ json ڴ
 * @return {ACL_JSON*} ´ json 
 */
ACL_API ACL_JSON *acl_json_dbuf_alloc(ACL_DBUF_POOL *dbuf);

/**
 * һ JSON һ JSON ڵ㴴һµ JSON 
 * @param node {ACL_JSON_NODE*} Դ JSON һ JSON ڵ
 * @return {ACL_JSON*} ´ JSON 
 */
ACL_API ACL_JSON *acl_json_create(ACL_JSON_NODE *node);

/**
 * һ JSON һ JSON ڵ㴴һµ JSON 
 * @param dbuf {ACL_DBUF_POOL*} ڴض󣬵Է NULL ʱ json 
 *  ڵڴϽз䣬ڲԶ json ڴ
 * @param node {ACL_JSON_NODE*} Դ JSON һ JSON ڵ
 * @return {ACL_JSON*} ´ JSON 
 */
ACL_API ACL_JSON *acl_json_dbuf_create(ACL_DBUF_POOL *dbuf, ACL_JSON_NODE *node);

/**
 * ĳһ ACL_JSON_NODE ڵΪһ json ĸڵ㣬
 * ӶԷرýڵĸӽڵ(ڱе
 * ڵ㲻ڵ)ñʽбڵ
 * ĳһ ACL_JSON_NODE ڵʱܱһӽڵ
 * @param json {ACL_JSON*} json 
 * @param node {ACL_JSON_NODE*} ACL_JSON_NODE ڵ
 */
ACL_API void acl_json_foreach_init(ACL_JSON *json, ACL_JSON_NODE *node);

/**
 * ͷһ json , ͬʱͷŸöɵ json ڵ
 * @param json {ACL_JSON*} json 
 */
ACL_API void acl_json_free(ACL_JSON *json);

/**
 *  json 
 * @param json {ACL_JSON*} json 
 */
ACL_API void acl_json_reset(ACL_JSON *json);

/*------------------------- in acl_json_parse.c ---------------------------*/

/**
 *  json , Զ json ڵ
 * @param json {ACL_JSON*} json 
 * @param data {const char*}  '\0' βַ,  json ;
 *  Ҳǲ json , ѭô˺, ݳ; ò
 *  Ϊ NULLֱӷؿմַ˽ֹΪ NULL
 * @return {const char*} 󣬸÷ֵʾʣݵַָ
 */
ACL_API const char* acl_json_update(ACL_JSON *json, const char *data);

/**
 * ж JSON Ƿ
 * @param json {ACL_JSON*} json 
 * @return {int} ط 0 ֵʾɣʾδ
 */
ACL_API int acl_json_finish(ACL_JSON *json);

/*------------------------- in acl_json_util.c ----------------------------*/

/**
 *  json лõһǩͬ json ڵ
 * @param json {ACL_JSON*} json 
 * @param tag {const char*} ǩ
 * @return {ACL_JSON_NODE*}  json ڵ,  NULL 
 *  ʾûз json ڵ
 */
ACL_API ACL_JSON_NODE *acl_json_getFirstElementByTagName(
	ACL_JSON *json, const char *tag);

/**
 * ͷ acl_json_getElementsByTagName, acl_json_getElementsByName,
 * ȺصĶ̬, Ϊö̬е
 * Ԫض ACL_JSON Ԫص, ͷŵö̬, ֻҪ ACL_JSON
 * ͷ, ԭڸеԪȻʹ.
 * ͷ xml ڵԪ
 * @param a {ACL_ARRAY*} ̬
 */
ACL_API void acl_json_free_array(ACL_ARRAY *a);

/**
 *  json леǩͬ json ڵļ
 * @param json {ACL_JSON*} json 
 * @param tag {const char*} ǩ
 * @return {ACL_ARRAY*}  json ڵ㼯,  ̬,  NULL 
 *  ʾûз json ڵ, ǿֵҪ acl_json_free_array ͷ
 */
ACL_API ACL_ARRAY *acl_json_getElementsByTagName(
	ACL_JSON *json, const char *tag);

/**
 *  json ле༶ǩͬ json ڵļ
 * @param json {ACL_JSON*} json 
 * @param tags {const char*} ༶ǩ '/' ָǩ json ݣ
 *  { 'root': [
 *      'first': { 'second': { 'third': 'test1' } },
 *      'first': { 'second': { 'third': 'test2' } },
 *      'first': { 'second': { 'third': 'test3' } }
 *    ]
 *  }
 *  ͨ༶ǩroot/first/second/third һԲзĽڵ
 * @return {ACL_ARRAY*}  json ڵ㼯,  ̬,  NULL 
 *  ʾûз json ڵ, ǿֵҪ acl_json_free_array ͷ
 */
ACL_API ACL_ARRAY *acl_json_getElementsByTags(
	ACL_JSON *json, const char *tags);

/**
 *  json ʱ json Ҷڵ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param name {const char*} ǩǿ
 * @param value {const char*} ǩֵǿ
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_text(ACL_JSON *json,
	const char *name, const char *value);
#define acl_json_create_leaf acl_json_create_text

/**
 *  json ʱ json ͵Ҷڵ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param name {const char*} ǩǿ
 * @param value {int} ֵ
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_bool(ACL_JSON *json,
	const char *name, int value);

/**
 *  json ʱ json null ͵Ҷڵ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param name {const char*} ǩǿ
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_null(ACL_JSON *json, const char *name);

/**
 *  json ʱ json int ͵Ҷڵ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param name {const char*} ǩǿ
 * @param value {acl_int64} зֵ
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_int64(ACL_JSON *json,
	const char *name, acl_int64 value);

/**
 *  json ʱ json double ͵Ҷڵ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param name {const char*} ǩǿ
 * @param value {double} зֵ
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_double(ACL_JSON *json,
	const char *name, double value);

/**
 *  json ʱ json double ͵Ҷڵ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param name {const char*} ǩǿ
 * @param value {double} зֵ
 * @param precision {int} С㾫ȣ 0 ʱЧȡȱʡֵΪ 4
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_double2(ACL_JSON *json,
	const char *name, double value, int precision);

/**
 *  json ַڵ㣬 json 淶ýڵֻܼ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param text {const char*}
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_array_text(ACL_JSON *json,
	const char *text);

/**
 *  json ֵڵ㣬 json 淶ýڵֻܼ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param value {acl_int64}
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_array_int64(ACL_JSON *json,
	acl_int64 value);
/**
 *  json ֵڵ㣬 json 淶ýڵֻܼ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param value {double}
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_array_double(ACL_JSON *json,
	double value);

/**
 *  json Ĳڵ㣬 json 淶ýڵֻܼ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param value {int}  0 ʾ trueʾ false
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_array_bool(ACL_JSON *json, int value);

/**
 *  json  null ڵ㣬 json 淶ýڵֻܼ
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_array_null(ACL_JSON *json);

/**
 *  json ʱ json ( {} Ķ)
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_obj(ACL_JSON *json);

/**
 *  json ʱ json ( [] Ķ)
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_array(ACL_JSON *json);

/**
 *  json ʱ json ڵ( tagname: ACL_JSON_NODE)
 * @param json {ACL_JSON*}  acl_json_alloc / acl_json_alloc1 
 * @param name {const char*} json ڵıǩ
 * @param value {ACL_JSON_NODE*} json ڵΪǩֵ
 * @return {ACL_JSON_NODE*} ´Ľڵͷ ACL_JSON ʱ
 *  һͷţԲҪͷ
 */
ACL_API ACL_JSON_NODE *acl_json_create_node(ACL_JSON *json,
	const char *name, ACL_JSON_NODE *value);

/**
 *  json ʱһ acl_json_create_obj  acl_json_create_array
 *  json ڵӽڵ㣬ӽڵ½ӿڴĽڵ:
 * acl_json_create_leaf, acl_json_create_obj, acl_json_create_array
 */
ACL_API void acl_json_node_append_child(ACL_JSON_NODE *parent,
	ACL_JSON_NODE *child);

/**
 *  json һ JSON ڵתַ
 * @param node {ACL_JSON_NODE*} json ڵ
 * @param buf {ACL_VSTRING*} 洢ĻòΪʱڲ
 *  ԶһλӦҪͷŵǿպڲֱӽ洢
 * @return {ACL_VSTRING*} json ڵתַĴ洢
 *  ÷ֵԶǿգʹ߿ͨ ACL_VSTRING_LEN(x) жǷΪգ
 *  ص ACL_VSTRING ָΪúڲģû
 *  acl_vstring_free ͷ
 */
ACL_API ACL_VSTRING *acl_json_node_build(ACL_JSON_NODE *node, ACL_VSTRING *buf);

/**
 *  json תַ
 * @param json {ACL_JSON*} json 
 * @param buf {ACL_VSTRING*} 洢ĻòΪʱڲ
 *  ԶһλӦҪͷŵǿպڲֱӽ洢
 * @return {ACL_VSTRING*} json תַĴ洢÷ֵԶǿգ
 *  ʹ߿ͨ ACL_VSTRING_LEN(x) жǷΪգص ACL_VSTRING
 *  ָΪúڲģû acl_vstring_free ͷ
 */
ACL_API ACL_VSTRING *acl_json_build(ACL_JSON *json, ACL_VSTRING *buf);

/**
 * ʽ JSON תַ̣úڽ JSON תΪַĹУ
 * һתһ߽ͨصߣ߿޶޶û
 * ʱôӦڵJSONתɵַǳʱ(糬100 MB),
 * ΪʽתʽԲҪһڴ
 * @param json {ACL_JSON*} json 
 * @param length {size_t} תΪַĹȳóص
 *  û趨Ļص
 * @param callback {int (*)(ACL_JSON*, ACL_VSTRING*, void*)} û趨Ļص
 *  صĵڶΪ NULL ʱʾϣûڸûص
 *  ĳαú󷵻ֵ < 0 ֹͣ
 * @param ctx {void*} callback һ
 */
ACL_API void acl_json_building(ACL_JSON *json, size_t length,
	int (*callback)(ACL_JSON *, ACL_VSTRING *, void *), void *ctx);

#ifdef __cplusplus
}
#endif

#endif
