#ifndef ACL_XML3_INCLUDE_H
#define ACL_XML3_INCLUDE_H

#ifdef __cplusplus
extern "C" {
#endif

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

typedef struct ACL_XML3	ACL_XML3;
typedef struct ACL_XML3_NODE	ACL_XML3_NODE;
typedef struct ACL_XML3_ATTR	ACL_XML3_ATTR;

struct ACL_XML3_ATTR {
	ACL_XML3_NODE *node;            /**< ڵ */
	char *name;                     /**<  */
	char *value;                    /**< ֵ */

	size_t name_size;               /**<  */
	size_t value_size;              /**< ֵ */

	/* private */
	int   quote;                    /**<  0 ʾ '  " */
	int   backslash;                /**< תַ \ */
	int   slash;                    /**< Ƿ '/' ־λ趨 */
};

struct ACL_XML3_NODE {
	char *ltag;                     /**< ǩ */
	char *rtag;                     /**< ұǩ */
	size_t ltag_size;               /**< ǩ */
	size_t rtag_size;               /**< ұǩ */
	const char *id;                 /**< IDʶ, ֻ xml->id_table
					  ڵĽڵ id ŷǿ */
	char *text;                     /**< ıʾ */
	size_t text_size;               /**< ļݳ */

	ACL_ARRAY *attr_list;           /**< (ACL_XML3_ATTR)б */
	ACL_XML3_NODE *parent;          /**< ڵ */
	ACL_RING children;              /**< ӽڵ㼯 */
	int  depth;                     /**< ǰڵ */

	/* private */
	ACL_XML3 *xml;                  /**< xml  */
	ACL_RING node;                  /**< ǰڵ */
	ACL_XML3_ATTR *curr_attr;       /**< ǰڽ */
	int   quote;                    /**<  0 ʾ '  " */
	int   last_ch;                  /**< ¼ڵǰһֵֽ */
	int   nlt;                      /**< '<'  */
	char  meta[3];                  /**< Ԫʱ */

	unsigned int flag;
#define	ACL_XML3_F_META_QM	(1 << 0)    /**< '?' flag */
#define	ACL_XML3_F_META_CM	(1 << 1)    /**< '!--' flag */
#define	ACL_XML3_F_META_EM	(1 << 2)    /**< only '!' flag */
#define ACL_XML3_F_SELF_CL	(1 << 3)    /**< self closed flag */
#define	ACL_XML3_F_LEAF		(1 << 4)    /**< leaf node has no child node */

/**< ǷԪ */
#define	ACL_XML3_F_META		\
	(ACL_XML3_F_META_QM | ACL_XML3_F_META_CM | ACL_XML3_F_META_EM)

#define	ACL_XML3_IS_COMMENT(x)	(((x)->flag & ACL_XML3_F_META_CM))

	int   status;                   /**< ״̬ǰ״̬ */
#define ACL_XML3_S_NXT	0               /**< һڵ */
#define ACL_XML3_S_LLT	1               /**<  '<' */
#define ACL_XML3_S_LGT	2               /**< ұ '>' */
#define	ACL_XML3_S_LCH	3               /**<  '<' һֽ */
#define ACL_XML3_S_LEM	4               /**<  '<'  '!' */
#define ACL_XML3_S_LTAG	5               /**< ߵıǩ */
#define ACL_XML3_S_RLT	6               /**< ұߵ '<' */
#define ACL_XML3_S_RGT	7               /**< ұߵ '>' */
#define ACL_XML3_S_RTAG	8               /**< ұߵıǩ */
#define ACL_XML3_S_ATTR	9               /**< ǩ */
#define ACL_XML3_S_AVAL	10              /**< ǩֵ */
#define ACL_XML3_S_TXT	11              /**< ڵı */
#define ACL_XML3_S_MTAG	12              /**< Ԫݱǩ */
#define ACL_XML3_S_MTXT	13              /**< Ԫı */
#define ACL_XML3_S_MCMT	14              /**< Ԫע */
#define ACL_XML3_S_MEND	15              /**< Ԫݽ */

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

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

struct ACL_XML3 {
	/* public */
					
	int   depth;                    /**<  */
	int   node_cnt;                 /**< ڵ,  root ڵ */
	int   root_cnt;                 /**< ڵ */
	ACL_XML3_NODE *root;            /**< XML ڵ */

	/* private */
	char  addr[1];
	ACL_HTABLE *id_table;           /**< id ʶϣ */
	ACL_XML3_NODE *curr_node;       /**< ǰڴ XML ڵ */
	ACL_DBUF_POOL *dbuf;            /**< ڴض */
	ACL_DBUF_POOL *dbuf_inner;      /**< ڲֲڴض */
	size_t dbuf_keep;               /**< ڴбĳ */

	unsigned flag;                  /**< ־λ: ACL_XML3_FLAG_xxx */ 

	/**< Ƿһ xml ĵжڵ㣬ڲȱʡΪ */
#define	ACL_XML3_FLAG_MULTI_ROOT	(1 << 0)

	/**< Ƿݵڵû '/'  */
#define	ACL_XML3_FLAG_IGNORE_SLASH	(1 << 1)

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

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

/****************************************************************************/
/*                  ӿڣûԷʹøýӿڼ                  */
/****************************************************************************/

/*----------------------------- in acl_xml3.c ------------------------------*/

/**
 * ж xml Ƿպϵ, ǷǷ,  xml 
 * xml ڵԪΪ, ҲΪǱպϵ
 * @param xml {ACL_XML3*} xml 
 * @return {int} 0: ; 1: 
 */
ACL_API int acl_xml3_is_closure(ACL_XML3 *xml);

/**
 * ָǩж xml Ѿ, ñǩ xml  root һӽڵ
 * еһ xml ڵıǩͬʱ, Ϊ xml , Ϊ֤жϵȷ,
 * ԴӦ֤ĸڵֻһ,  xml->root һӽڵֻһ, 
 * 
 * @param xml {ACL_XML3*} xml 
 * @param tag {const char*} ûǩ, ڲƥʱִСд
 * @return {int} 0: ; 1: 
 */
ACL_API int acl_xml3_is_complete(ACL_XML3 *xml, const char *tag);

/**
 * һ xml 
 * @return {ACL_XML3*} ´ xml 
 */
ACL_API ACL_XML3 *acl_xml3_alloc(void);

/**
 * һ xml 󣬸 xml еڲڴ䶼ڸڴϽз
 * @param dbuf {ACL_DBUF_POOL*} ڴض󣬵Է NULL ʱ xml 
 *  ڵڴϽз䣬ڲԶ xml ڴ
 * @return {ACL_XML3*} ´ xml 
 */
ACL_API ACL_XML3 *acl_xml3_dbuf_alloc(ACL_DBUF_POOL *dbuf);

/**
 * ĳһ ACL_XML3_NODE ڵΪһ XML ĸڵ㣬ӶԷر
 * ڵӽڵ(ڱенڵ㲻ڵ)ñʽбڵ
 * ĳһ ACL_XML3_NODE ڵʱܱһӽڵ
 * @param xml {ACL_XML3*} xml 
 * @param node {ACL_XML3_NODE*} AXL_XML_NODE ڵ
 */
ACL_API void acl_xml3_foreach_init(ACL_XML3 *xml, ACL_XML3_NODE *node);

/**
 * һ xml ĵǷж xml ڵ㣬ڲȱʡֶ֧ڵ
 * @param xml {ACL_XML3*} xml 
 * @param on {int}  0 Ϊ 0 ʾֹж xml ڵʱ
 *  ڽʱһڵʱ㷵ʣ
 */
ACL_API void acl_xml3_multi_root(ACL_XML3 *xml, int on);

/**
 *  XML ڵ, Ƿû /, :
 * <test id=111>, <test id=111 />, û / д
 * ǺϷģֻеڶдǺϷģּԣ
 * һʧ
 * @param xml {ACL_XML3*} xml 
 * @param ignore {int}  0 ʾڵ /
 */
ACL_API void acl_xml3_slash(ACL_XML3 *xml, int ignore);

/**
 * ͷһ xml , ͬʱͷŸöɵ xml ڵ
 * @param xml {ACL_XML3*} xml 
 * @return {int} ͷŵ xml ڵ
 */
ACL_API int acl_xml3_free(ACL_XML3 *xml);

/**
 *  XML 
 * @param xml {ACL_XML3*} xml 
 */
ACL_API void acl_xml3_reset(ACL_XML3 *xml);

/*------------------------- in acl_xml3_parse.c ----------------------------*/

/**
 *  xml , Զ xml ڵ
 * @param xml {ACL_XML3*} xml 
 * @param data {char*}  '\0' βַ,  xml ;
 *  Ҳǲ xml , ѭô˺, ݳ
 * @return {char*} ͨ acl_xml3_multi_root һ xml ĵ
 *   xml ڵʱúصĵַֽΪ '\0'; 򷵻ʣݵַ
 *  ǿַ
 *  עҲͨ acl_xml3_is_complete жǷ
 */
ACL_API char *acl_xml3_update(ACL_XML3 *xml, char *data);
#define	acl_xml3_parse	acl_xml3_update

/*------------------------- in acl_xml3_util.c -----------------------------*/

/**
 * ʼ input, br, hr ȵԱպϱǩ, γԱպϱǩ, Ա
 * acl_xml3_tag_selfclosed ѯ, ǩǷǱԱպϱǩ,
 * úֻܱʼһ, ҲԲʼ
 */
ACL_API void acl_xml3_tag_init(void);

/**
 * ûԼһЩԱպϵıǩ
 * @param tag {const char*} ǩעǩȲô 254 ֽ
 */
ACL_API void acl_xml3_tag_add(const char *tag);

/**
 *  acl_xml3_tag_init ʼԱպϱǩ, Եô˺ж
 * ǩǷԱպϱǩ, δ acl_xml3_tag_init, úԶ 0
 * @parma tag {const char*} ǩ
 * @return {int} 0: ʾ, 1: ʾ
 */
ACL_API int  acl_xml3_tag_selfclosed(const char *tag);

/**
 * жϱǩ xml ڵǷҶڵ, Ҷڵûӽڵ
 * @param tag {const char*} ǩ
 * @return {int} 0: Ҷڵ; 1: Ҷڵ
 */
ACL_API int  acl_xml3_tag_leaf(const char *tag);

/**
 * ͷ acl_xml3_getElementsByTagName, acl_xml3_getElementsByName,
 * acl_xml3_getElementsByAttr ȺصĶ̬, Ϊö̬е
 * Ԫض ACL_XML3 Ԫص, ͷŵö̬, ֻҪ ACL_XML3
 * ͷ, ԭڸеԪȻʹ.
 * ͷ xml ڵԪ
 * @param a {ACL_ARRAY*} ̬
 */
ACL_API void acl_xml3_free_array(ACL_ARRAY *a);

/**
 *  xml лǩͬ xml һڵ
 * @param xml {ACL_XML3*} xml 
 * @param tag {const char*} ǩ
 * @return {ACL_XML3_NODE*}  xml ڵ,  NULL 
 *  ʾûз xml ڵ
 */
ACL_API ACL_XML3_NODE *acl_xml3_getFirstElementByTagName(
	ACL_XML3 *xml, const char *tag);

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

/**
 *  xml ле༶ǩͬ xml ڵļ
 * @param xml {ACL_XML3*} xml 
 * @param tags {const char*} ༶ǩ '/' ָǩ xml ݣ
 *  <root> <first> <second> <third name="test1"> text1 </third> </second> </first>
 *  <root> <first> <second> <third name="test2"> text2 </third> </second> </first>
 *  <root> <first> <second> <third name="test3"> text3 </third> </second> </first>
 *  ͨ༶ǩroot/first/second/third һԲзĽڵ
 * @return {ACL_ARRAY*}  xml ڵ㼯,  ̬,  NULL 
 *  ʾûз xml ڵ, ǿֵҪ acl_xml3_free_array ͷ
 */
ACL_API ACL_ARRAY *acl_xml3_getElementsByTags(ACL_XML3 *xml, const char *tags);

/**
 *  xml ле name ֵͬ xml ڵԪؼ
 * @param xml {ACL_XML3*} xml 
 * @param value {const char*} Ϊ name ֵ
 * @return {ACL_ARRAY*}  xml ڵ㼯,  ̬,  NULL 
 *  ʾûз xml ڵ, ǿֵҪ acl_xml3_free_array ͷ
 */
ACL_API ACL_ARRAY *acl_xml3_getElementsByName(ACL_XML3 *xml, const char *value);

/**
 *  xml лиֵ xml ڵԪؼ
 * @param xml {ACL_XML3*} xml 
 * @param name {const char*} 
 * @param value {const char*} ֵ
 * @return {ACL_ARRAY*}  xml ڵ㼯,  ̬,  NULL 
 *  ʾûз xml ڵ, ǿֵҪ acl_xml3_free_array ͷ
 */
ACL_API ACL_ARRAY *acl_xml3_getElementsByAttr(ACL_XML3 *xml,
	const char *name, const char *value);

/**
 *  xml лָ id ֵ xml ڵԪصĳԶ
 * @param xml {ACL_XML3*} xml 
 * @param id {const char*} id ֵ
 * @return {ACL_XML3_ATTR*} ĳ xml ڵĳԶ,  NULL ʾ
 *  ûз, ֵҪͷ
 */
ACL_API ACL_XML3_ATTR *acl_xml3_getAttrById(ACL_XML3 *xml, const char *id);

/**
 *  xml лָ id ֵ xml ڵԪصĳֵ
 * @param xml {ACL_XML3*} xml 
 * @param id {const char*} id ֵ
 * @return {const char*} ĳ xml ڵĳֵ,  NULL ʾûз
 *  
 */
ACL_API const char *acl_xml3_getAttrValueById(ACL_XML3 *xml, const char *id);

/**
 *  xml лָ id ֵ xml ڵԪ
 * @param xml {ACL_XML3*} xml 
 * @param id {const char*} id ֵ
 * @return {ACL_XML3_NODE*} xml ڵԪ,  NULL ʾûз
 *   xml ڵ, ֵҪͷ
 */
ACL_API ACL_XML3_NODE *acl_xml3_getElementById(ACL_XML3 *xml, const char *id);

/**
 *  xml ȡ ? ! ȿͷĽڵ
 * @param xml {ACL_XML3*} xml 
 * @param tag {const char*} ǩ
 * @return {ACL_XML3_NODE*} xml ڵԪ,  NULL ʾûз
 *   xml ڵ, ֵҪͷ
 */
ACL_API ACL_XML3_NODE *acl_xml3_getElementMeta(ACL_XML3 *xml, const char *tag);

/**
 *  xml ַʽ
 * @param xml {ACL_XML3*} xml 
 * @return {const char*} ַʽ NULL ʱʾûи
 */
ACL_API const char *acl_xml3_getEncoding(ACL_XML3 *xml);

/**
 *  xml ݵͣ磺text/xsl
 * @param xml {ACL_XML3*} xml 
 * @return {const char*}  NULL ʾûи
 */
ACL_API const char *acl_xml3_getType(ACL_XML3 *xml);

/**
 *  xml ڵлָԶ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @param name {const char*} 
 * @return {ACL_XML3_ATTR*} Զ, Ϊձʾ, ֵҪͷ
 */
ACL_API ACL_XML3_ATTR *acl_xml3_getElementAttr(ACL_XML3_NODE *node,
		const char *name);

/**
 *  xml ڵлֵָ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @param name {const char*} 
 * @return {const char*} ֵ, Ϊձʾ
 */
ACL_API const char *acl_xml3_getElementAttrVal(
			ACL_XML3_NODE *node, const char *name);

/**
 *  xml ڵɾĳԶ, Ϊ id , ͬʱ xml->id_table ɾ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @param name {const char*} 
 * @return {int} 0 ʾɾɹ, -1: ʾɾʧ(пǸԲ)
 */
ACL_API int acl_xml3_removeElementAttr(ACL_XML3_NODE *node, const char *name);

#if 0
/**
 *  xml ڵ, Ѵ, µֵ滻ֵ, 
 * µԶ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @param name {const char*} 
 * @param value {const char*} ֵ
 * @return {ACL_XML3_ATTR*} ظԶ(пԭ, Ҳпµ), 
 *  ֵͷ
 */
ACL_API ACL_XML3_ATTR *acl_xml3_addElementAttr(ACL_XML3_NODE *node,
		const char *name, const char *value);

/**
 * ǩڵıΪ xml ڵ㣬úҪڹ xml ʱ
 * @param xml {ACL_XML3*} xml 󣬸öӦ acl_xml3_alloc 
 * @param tagname {const char*} ǩǿַȴ 0
 * @param text {const char*} ڵıݣΪ
 * @return {ACL_XML3_NODE*} ´ xml ڵ㣬÷Զطǿգ
 *  ǷᵼڲԶ
 */
ACL_API ACL_XML3_NODE *acl_xml3_create_node(ACL_XML3 *xml,
	const char *tagname, const char *text);

/**
 * һ xml ڵԣúҪڹ xml ʱ
 * @param node {ACL_XML3_NODE*}  acl_xml3_create_node Ľڵ
 * @param name {const char*} Ϊǿַַȴ 0
 * @param value {const char*} ֵΪ
 * @return {ACL_XML3_ATTR*} xml ڵԶ󣬵Ƿʱú
 *  ڲԶ
 */
ACL_API ACL_XML3_ATTR *acl_xml3_node_add_attr(ACL_XML3_NODE *node,
	const char *name, const char *value);

/**
 * һ xml ڵһԣúҪڹ xml ʱ
 * @param node {ACL_XML3_NODE*}  acl_xml3_create_node Ľڵ
 * @param ... һԣ NULL ʱʾ磺
 *  {name1}, {value1}, {name2}, {value2}, ... NULL
 */
ACL_API void acl_xml3_node_add_attrs(ACL_XML3_NODE *node, ...);

/**
 * һ xml ڵıݣúҪڹ xml ʱ
 * @param node {ACL_XML3_NODE*}  acl_xml3_create_node Ľڵ
 * @param text {const char*} ı
 */
ACL_API void acl_xml3_node_set_text(ACL_XML3_NODE *node, const char *text);

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

/**
 *  xml תָУעתϢΪõ
 * @param xml {ACL_XML3*} xml 
 * @param fp {ACL_VSTREAM*} 
 */
ACL_API void acl_xml3_dump(ACL_XML3 *xml, ACL_VSTREAM *fp);

/**
 *  xml תָУעתϢΪõ
 * @param xml {ACL_XML3*} xml 
 * @param buf {ACL_VSTRING*} , ҪûԼռ
 */
ACL_API void acl_xml3_dump2(ACL_XML3 *xml, ACL_VSTRING *buf);

#endif

/***************************************************************************/
/*          ΪΪͼĽӿ, ûԸҪ½ӿ             */
/***************************************************************************/

/*----------------------------- in acl_xml3.c ------------------------------*/

/**
 *  xml ڵ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @return {ACL_XML3_ATTR*} ´Ľڵ
 */
ACL_API ACL_XML3_ATTR *acl_xml3_attr_alloc(ACL_XML3_NODE *node);

/**
 * һ xml ڵ
 * @param xml {ACL_XML3*} xml 
 * @return {ACL_XML3_NODE*} xml ڵ
 */
ACL_API ACL_XML3_NODE *acl_xml3_node_alloc(ACL_XML3 *xml);

/**
 * ĳ xml ڵ㼰ӽڵ xml ɾ, ͷŸýڵ㼰ӽڵռռ
 * ͷŸ xml ڵռڴ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @return {int} ɾĽڵ
 */
ACL_API int acl_xml3_node_delete(ACL_XML3_NODE *node);

/**
 * ĳ xml ڵֵܽڵ(ֵܽڵǶ xml ڵ)
 * @param node1 {ACL_XML3_NODE*} 򱾽ڵ xml ڵ
 * @param node2 {ACL_XML3_NODE*} ӵֵ xml ڵ
 */
ACL_API void acl_xml3_node_append(ACL_XML3_NODE *node1, ACL_XML3_NODE *node2);

/**
 * ĳ xml ڵΪӽڵĳ xml ڵ
 * @param parent {ACL_XML3_NODE*} ڵ
 * @param child {ACL_XML3_NODE*} ӽڵ
 */
ACL_API void acl_xml3_node_add_child(ACL_XML3_NODE *parent, ACL_XML3_NODE *child);

/**
 * ĳ xml ڵĸڵ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @return {ACL_XML3_NODE*} ڵ, Ϊ NULL ʾ丸ڵ㲻
 */
ACL_API ACL_XML3_NODE *acl_xml3_node_parent(ACL_XML3_NODE *node);

/**
 * ĳ xml ڵĺһֵܽڵ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @return {ACL_XML3_NODE*}  xml ڵĺһֵܽڵ, ΪNULLʾ
 */
ACL_API ACL_XML3_NODE *acl_xml3_node_next(ACL_XML3_NODE *node);

/**
 * ĳ xml ڵǰһֵܽڵ
 * @param node {ACL_XML3_NODE*} xml ڵ
 * @return {ACL_XML3_NODE*}  xml ڵǰһֵܽڵ, ΪNULLʾ
 */
ACL_API ACL_XML3_NODE *acl_xml3_node_prev(ACL_XML3_NODE *node);

#ifdef __cplusplus
}
#endif
#endif
