#ifndef ACL_VSTRING_INCLUDE_H
#define ACL_VSTRING_INCLUDE_H

#ifdef  __cplusplus
extern "C" {
#endif

#include "acl_define.h"
#include <stdarg.h>
#include "acl_vbuf.h"
#include "acl_dbuf_pool.h"
#include "acl_slice.h"

/**
 * 封装了 ACL_VBUF，ACL_VSTRING 结构类型定义
 */
typedef struct ACL_VSTRING {
    ACL_VBUF        vbuf;
    ssize_t         maxlen;
    ACL_SLICE_POOL *slice;
    ACL_DBUF_POOL  *dbuf;
    ACL_FILE_HANDLE fd;
#if defined(_WIN32) || defined(_WIN64)
    ACL_FILE_HANDLE hmap;
#endif
} ACL_VSTRING;

/**
 * 初始化 ACL_VSTRING 结构并指定缺省的缓冲区大小，当用户在自己的函数或
 * 内部以 ACL_VSTRING str 方式（非动态分配方式）使用时需要用此函数进行初始化,
 * 另外，必须用 acl_vstring_free_buf 方式来释放由该函数分配的内部缓冲区
 * @param vp {ACL_VSTRING*} 对象地址，不能为空
 * @param len {size_t} 初始时缓冲区大小
 */
ACL_API void acl_vstring_init(ACL_VSTRING *vp, size_t len);

/**
 * 当以 acl_vstring_init 初始化 ACL_VSTRING 对象时需要调用此函数释放缓冲区内存
 * @param vp {ACL_VSTRING*} 对象地址，不能为空
 */
ACL_API void acl_vstring_free_buf(ACL_VSTRING *vp);

/**
 * 动态分配一个 ACL_VSTRING 对象并指定内部缓冲区的初始化大小
 * @param len {size_t} 初始时缓冲区大小
 * @return {ACL_VSTRING*} 新分配的 ACL_VSTRING 对象
 */
ACL_API ACL_VSTRING *acl_vstring_alloc(size_t len);

/**
 * 动态分配一个 ACL_VSTRING 对象并指定内部缓冲区的初始化大小，
 * 同时指定内存池对象，优化内存分配
 * @param slice {ACL_SLICE_POOL*} 切片内存池管理对象
 * @param len {size_t} 初始时缓冲区大小
 * @return {ACL_VSTRING*} 新分配的 ACL_VSTRING 对象
 */
ACL_API ACL_VSTRING *acl_vstring_slice_alloc(ACL_SLICE_POOL *slice, size_t len);

/**
 * 动态分配一个 ACL_VSTRING 对象并指定内部缓冲区的初始化大小，
 * 同时指定内存池对象，优化内存分配
 * @param slice {ACL_SLICE_POOL*} 切片内存池管理对象
 * @param len {size_t} 初始时缓冲区大小
 * @return {ACL_VSTRING*} 新分配的 ACL_VSTRING 对象
 */
ACL_API ACL_VSTRING *acl_vstring_dbuf_alloc(ACL_DBUF_POOL *dbuf, size_t len);

/**
 * 采用内存映射文件方式分配内存时，调用此函数创建 ACL_VSTRING 动态缓冲区对象
 * @param fd {ACL_FILE_HANDLE} 有效的文件句柄
 * @param max_len {ssize_t} 所映射的最大内存大小
 * @param init_len {ssize_t} 初始化时的内存映射大小
 * @return {ACL_VSTRING*} 新创建的 ACL_VSTRING 对象
 */
ACL_API ACL_VSTRING *acl_vstring_mmap_alloc(ACL_FILE_HANDLE fd,
	ssize_t max_len, ssize_t init_len);

/**
 * 设置 ACL_VSTRING 对象的属性, 目前该函数的功能还不够完善
 * @param vp {ACL_VSTRING*}
 * @param ... 由 ACL_VSTRING_CTL_XXX 表示的控制参数，结束标志为
 *  ACL_VSTRING_CTL_END
 */
ACL_API void acl_vstring_ctl(ACL_VSTRING *vp,...);

#define ACL_VSTRING_CTL_MAXLEN      1
#define ACL_VSTRING_CTL_END         0

/**
 * 将缓冲区内的数据截短至指定长度，同时保证缓冲区数据以 '\0' 结尾
 * @param vp {ACL_VSTRING*}
 * @param len {size_t} 截短后的长度
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_truncate(ACL_VSTRING *vp, size_t len);

/**
 * 释放由 acl_vstring_alloc 动态分配的 ACL_VSTRING 对象
 * @param vp {ACL_VSTRING*}
 */
ACL_API void acl_vstring_free(ACL_VSTRING *vp);

/**
 * 拷贝字符串
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源字符串
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_strcpy(ACL_VSTRING *vp, const char *src);

/**
 * 拷贝字符串，但不得超过规定长度限制
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源字符串
 * @param len {size_t} 规定长度限制
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_strncpy(ACL_VSTRING *vp,
		const char *src, size_t len);

/**
 * 附加拷贝字符串
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源字符串
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_strcat(ACL_VSTRING *vp, const char *src);

/**
 * 附加拷贝字符串，但不得超过规定长度限制
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源字符串
 * @param len {size_t} 规定长度限制
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_strncat(ACL_VSTRING *vp,
		const char *src, size_t len);

/**
 * 拷贝内存区数据，同时保证目标缓冲区尾部置 '\0'
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源数据地址
 * @param len {size_t} 源数据长度
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_memcpy(ACL_VSTRING *vp,
		const char *src, size_t len);

/**
 * 移动内存区数据, 源数据与目标地址的内存区可以是同一块内存区也可以不是
 * 同一块内存区，该函数保证目标地址尾部以 '\0' 结尾
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源数据地址
 * @param len {size_t} 源数据长度
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_memmove(ACL_VSTRING *vp,
		const char *src, size_t len);

/**
 * 拷贝内存区，该函数保证目标缓冲区以 '\0' 结尾
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源数据地址
 * @param len {size_t} 源数据长度
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_memcat(ACL_VSTRING *vp,
		const char *src, size_t len);

/**
 * 查找某个字符
 * @param vp {ACL_VSTRING*}
 * @param ch {int} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 
 *  注：该返回地址是不能被单独释放的，因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_memchr(ACL_VSTRING *vp, int ch);

/**
 * 查找某个字符串，字符串大小写敏感
 * @param vp {ACL_VSTRING*}
 * @param needle {const char*} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 
 *  注：该返回地址是不能被单独释放的，因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_strstr(ACL_VSTRING *vp, const char *needle);

/**
 * 查找某个字符串，忽略字符串大小写
 * @param vp {ACL_VSTRING*}
 * @param needle {const char*} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 
 *  注：该返回地址是不能被单独释放的，因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_strcasestr(ACL_VSTRING *vp, const char *needle);

/**
 * 从后向前查找字符串，字符串大小写敏感
 * @param vp {ACL_VSTRING*}
 * @param needle {const char*} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 
 *  注：该返回地址是不能被单独释放的，因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_rstrstr(ACL_VSTRING *vp, const char *needle);

/**
 * 从后向前查找字符串，字符串大小写不敏感
 * @param vp {ACL_VSTRING*}
 * @param needle {const char*} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL,
 *  注：该返回地址是不能被单独释放的，因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_rstrcasestr(ACL_VSTRING *vp, const char *needle);

/**
 * 向缓冲区的某个指定位置后添加数据，同时保证目标缓冲区数据以 '\0' 结尾
 * @param vp {ACL_VSTRING*}
 * @param start {size_t} 指定的位置
 * @param buf {const char*} 数据地址
 * @param len {size_t} 数据长度
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_insert(ACL_VSTRING *vp, size_t start,
		const char *buf, size_t len);

/**
 * 向缓冲区的头部添加数据，同时保证目标缓冲区数据以 '\0' 结尾
 * @param vp {ACL_VSTRING*}
 * @param buf {const char*} 数据地址
 * @param len {size_t} 数据长度
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_prepend(ACL_VSTRING *vp,
		const char *buf, size_t len);

/**
 * 向缓冲区按格式方式添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*} 格式化字符串
 * @param ... 变参序列
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *ACL_PRINTF(2, 3) acl_vstring_sprintf(ACL_VSTRING *vp,
		const char *format,...);

/**
 * 以附加方式向缓冲区按格式方式添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*} 格式化字符串
 * @param ... 变参序列
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *ACL_PRINTF(2, 3) acl_vstring_sprintf_append(
		ACL_VSTRING *vp, const char *format,...);

/**
 * 导出缓冲区内的数据区同时将 ACL_VSTRING 对象释放，用户需要单独调用
 * acl_myfree 来释放返回的数据区内存
 * @param vp {ACL_VSTRING*}
 * @return {char*} 数据区地址，当返回值不为 NULL 时用户需要单独调用
 *  acl_myfree 来释放该地址，否则会造成内存泄漏
 */
ACL_API char *acl_vstring_export(ACL_VSTRING *vp);

/**
 * 将用户的存储字符串的动态分配内存区导入并生成新的 ACL_VSTRING 对象
 * @param str {char*} 外部动态分配的存储字符串的内存地址
 * @return {ACL_VSTRING*} 新分配的 ACL_VSTRING 对象
 */
ACL_API ACL_VSTRING *acl_vstring_import(char *str);

/**
 * 将动态内存区与 ACL_VSTRING 粘合
 * 注：vp 不能是调用 acl_vstring_alloc 产生的，并且不能调用 acl_vstring_init
 *     进行过初始化, vp 可以是由 acl_mymalloc 产生或位于栈上的一个变量
 *    （如: ACL_VSTRING v）
 * @param vp {ACL_VSTRING*} 需由 acl_mymalloc 生成或是一个栈变量, 当以
 *  acl_mymalloc 方式生成的时应该通过 acl_myfree 释放它
 * @param buf {void*} 用户传递的内存区, 可以是栈变量
 * @param len {size_t} buf 内存区的长度
 */
ACL_API void acl_vstring_glue(ACL_VSTRING *vp, void *buf, size_t len);

/**
 * 取得某个位置的字符
 * @param vp {ACL_VSTRING*}
 * @param len {size_t} 位置，如果该值越界，则函数内部会 fatal
 * @return {char} 查找的字符
 */
ACL_API char acl_vstring_charat(ACL_VSTRING *vp, size_t len);

/**
 * 按规定格式添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*}
 * @param ap {va_list}
 * @return {ACL_VSTRING*} 与 vp 相同
 * @see acl_vstring_sprintf
 */
ACL_API ACL_VSTRING *acl_vstring_vsprintf(ACL_VSTRING *vp,
		const char *format, va_list ap);

/**
 * 按规定格式向尾部添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*}
 * @param ap {va_list}
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_vsprintf_append(ACL_VSTRING *vp,
		const char *format, va_list ap);

/**
 * 按规定格式向头部添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*}
 * @param ... 变参序列
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *ACL_PRINTF(2, 3) acl_vstring_sprintf_prepend(
		ACL_VSTRING *vp, const char *format, ...);

/**
 * 从源串中获得一行数据(不含 "\r\n" 和 "\n")，同时将剩余数据缓存起来, 如果
 * 未获得完整行，则只缓存源串
 * @param vp {ACL_VSTRING*} 字符串数据缓存区
 * @param src {const char**} 源字符串指针地址, 返回后指针地址移动至下一位置
 * @param dlen {size_t} 源字符串数据长度
 * @return {const ACL_VSTRING*} NULL, 表示未找到 "\r\n" 或 "\n"，但会将剩余
 *  的数据拷贝至缓冲区内，应用需要通过 ACL_VSTRING_LEN 判断缓冲区中是否还有
 *  数据；!NULL，表示读到完整行
 *  注：读到完整行后应该调用 ACL_VSTRING_RESET(vp) 将缓冲区清空
 */
ACL_API const ACL_VSTRING *acl_buffer_gets_nonl(ACL_VSTRING *vp,
		const char **src, size_t dlen);

/**
 * 从源串中获得一行数据(包含 "\r\n" 或 "\n")，同时将剩余数据缓存起来, 
 * 如果未获得完整行，则只缓存源串
 * @param vp {ACL_VSTRING*} 字符串数据缓存区
 * @param src {const char**} 源字符串指针地址, 返回后指针地址移动至下一位置
 * @param dlen {size_t} 源字符串数据长度
 * @return {const ACL_VSTRING*} NULL, 表示未找到 "\r\n" 或 "\n"，但会将剩余
 *  的数据拷贝至缓冲区内，应用需要通过 ACL_VSTRING_LEN 判断缓冲区中是否还有
 *  数据；!NULL，表示读到完整行
 *  注：读到完整行后应该调用 ACL_VSTRING_RESET(vp) 将缓冲区清空
 */
ACL_API const ACL_VSTRING *acl_buffer_gets(ACL_VSTRING *vp,
		const char **src, size_t dlen);

 /*
  * Macros. Unsafe macros have UPPERCASE names.
  */
#define ACL_VSTRING_SPACE(vp, len) ((vp)->vbuf.space(&(vp)->vbuf, len))

/**
 * 取得当前 ACL_VSTRING 数据存储地址
 * @param vp {ACL_VSTRING*}
 * @return {char*}
 */
#define acl_vstring_str(vp) ((char *) (vp)->vbuf.data)

/**
 * 取得当前 ACL_VSTRING 所存储的数据的长度
 * @param vp {ACL_VSTRING*}
 * @return {int}
 */
#define ACL_VSTRING_LEN(vp) (size_t) ((vp)->vbuf.ptr - (vp)->vbuf.data)

/**
 * 取得当前 ACL_VSTRING 内部缓冲区的总大小
 * @param vp {ACL_VSTRING*}
 * @return {int}
 */
#define	ACL_VSTRING_SIZE(vp) ((vp)->vbuf.len)

/**
 * 取得当前 ACL_VSTRING 的数据偏移指针位置
 * @param vp {ACL_VSTRING*}
 * @return {char*}
 */
#define acl_vstring_end(vp) ((char *) (vp)->vbuf.ptr)

/**
 * 将 ACL_VSTRING 的数据偏移指针位置置 0
 * @param vp {ACL_VSTRING*}
 */
#define ACL_VSTRING_TERMINATE(vp) { \
	if ((vp)->vbuf.cnt <= 0) \
		ACL_VSTRING_SPACE((vp), 1); \
	if ((vp)->vbuf.cnt > 0) \
		*(vp)->vbuf.ptr = 0; \
	else if ((vp)->vbuf.ptr > (vp)->vbuf.data) { \
		(vp)->vbuf.ptr--; \
		*(vp)->vbuf.ptr = 0; \
		(vp)->vbuf.cnt++; \
	} \
}

/**
 * 重置 ACL_VSTRING 内部缓冲区指针地址起始位置，但不会将尾部数据置 0，应用可以
 * 通过调用 ACL_VSTRING_TERMINATE 将缓冲数据尾部置 0
 * @param vp {ACL_VSTRING*}
 */
#define ACL_VSTRING_RESET(vp) {	\
	(vp)->vbuf.ptr = (vp)->vbuf.data; \
	(vp)->vbuf.cnt = (vp)->vbuf.len; \
	acl_vbuf_clearerr(&(vp)->vbuf); \
}

/**
 * 添加一个字符至 ACL_VSTRING 缓冲区
 * @param vp {ACL_VSTRING*}
 * @param ch {int} 字符
 */
#define	ACL_VSTRING_ADDCH(vp, ch) ACL_VBUF_PUT(&(vp)->vbuf, ch)

/**
 * 移动数据偏移指针至内部缓冲区尾部
 * @param vp {ACL_VSTRING*}
 */
#define ACL_VSTRING_SKIP(vp) { \
	while ((vp)->vbuf.cnt > 0 && *(vp)->vbuf.ptr) \
		(vp)->vbuf.ptr++, (vp)->vbuf.cnt--; \
}

/**
 * 当前 ACL_VSTRING 中还有多少数据可用
 * @param vp {ACL_VSTRING*}
 */
#define acl_vstring_avail(vp) ((vp)->vbuf.cnt)

 /**
  * The following macro is not part of the public interface, because it can
  * really screw up a buffer by positioning past allocated memory.
  */
#define ACL_VSTRING_AT_OFFSET(vp, offset) { \
	(vp)->vbuf.ptr = (vp)->vbuf.data + (offset); \
	(vp)->vbuf.cnt = (vp)->vbuf.len - (offset); \
}

#ifdef  __cplusplus
}
#endif

#endif
