#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <pthread.h>
#include <uthash/uthash.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <configm/configmapi.h>

#include "compile.h"
#include "log.h"
#include "object_manager.h"
#include "json_interface.h"
#include "regex_table.h"
#include "ret_errno.h"

#define MAX_OBJ             (300)

#define JS_FILE_ROOT        "/mnt/e/wsl"
#define ADD_JS_FILE         (JS_FILE_ROOT"/secogateway/Product/user/object_manager/json_test/add.json")
#define DEL_JS_FILE         (JS_FILE_ROOT"/secogateway/Product/user/object_manager/json_test/del.json")
#define MOD_JS_FILE         (JS_FILE_ROOT"/secogateway/Product/user/object_manager/json_test/mod.json")
#define QUERY_JS_FILE       (JS_FILE_ROOT"/secogateway/Product/user/object_manager/json_test/page_queue.json")
#define DETAIL_JS_FILE      (JS_FILE_ROOT"/secogateway/Product/user/object_manager/json_test/detail.json")
#define SEARCH_JS_FILE      (JS_FILE_ROOT"/secogateway/Product/user/object_manager/json_test/search.json")

static PSPLIT_PAGE g_pSplitPage = NULL;
static PCMHI_OBJECT g_pObject = NULL;
static OBJECT_K g_objItem[MAX_OBJ];
static pthread_mutex_t g_obj_lock = PTHREAD_MUTEX_INITIALIZER;

static void create_session(unsigned char *buf, int size)
{
    int i;
    const char *asc_char = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    int max = strlen(asc_char);
    srand(time(NULL));

    for (i = 0; i < size && buf; i++) {
        buf[i] = asc_char[rand() % max];
    }

    LOG_EX(LOG_Debug, "random string(%d): %s\n", strlen((const char *) buf), (char *) buf);
}

static int split_params(char *pInput, char **pFirst, char **pSecond,
                        const char *split)
{
    char *pStr = (char *) pInput;
    char *p;

    if (!pInput || !pFirst || !pSecond) {
        LOG_EX(LOG_Error, "Input params error: %p, %p, %p\n", pInput, pFirst, pSecond);
        return -RET_INPUTERR;
    }

    p = strsep(&pStr, split);

    if (strlen(p) == 0) {
        *pFirst = pInput;
        *pSecond = NULL;
    } else {
        *pFirst = p;
        *pSecond = pStr;
    }

    return RET_OK;
}

static int get_free_pos(void)
{
    int i;

    for (i = 0; i < MAX_OBJ; i++) {
        if (strlen(g_objItem[i].memTag) == 0) {
            return i;
        }
    }

    return -1;
}

static void dump_object(void)
{
    int i;
    PCMHI_OBJECT pObj, pTmp;
    pthread_mutex_lock(&g_obj_lock);
    HASH_ITER(hh, g_pObject, pObj, pTmp) {
        LOG_EX(LOG_Info, "name:         %s\n", pObj->name);
        LOG_EX(LOG_Info, "desc:         %s\n", pObj->desc);
        LOG_EX(LOG_Info, "prio:         %d\n", pObj->prio);
        LOG_EX(LOG_Info, "Tags:         %s\n", g_objItem[pObj->obj_index].memTag);
        LOG_EX(LOG_Info, "type:         %d\n", g_objItem[pObj->obj_index].type);
        LOG_EX(LOG_Info, "refs:         %d\n", g_objItem[pObj->obj_index].ref_count);
        LOG_EX(LOG_Info, "items:        %d\n", g_objItem[pObj->obj_index].ctx_num);

        for (i = 0; i < g_objItem[pObj->obj_index].ctx_num; i++) {
            struct tm *pTm;
            char buf[256];
            time_t t;
            POBJECT_K pObjK = &g_objItem[pObj->obj_index];

            switch (pObjK->type / 10) {
                case OBJ_TYPE_SERVER:
                    LOG_EX(LOG_Info, "    porType:      %d\n", pObjK->objs.svr_obj[i].pro_type);
                    LOG_EX(LOG_Info, "    min Port:     %d\n", pObjK->objs.svr_obj[i].min_port);
                    LOG_EX(LOG_Info, "    min Port:     %d\n", pObjK->objs.svr_obj[i].max_port);
                    break;

                case OBJ_TYPE_ADDR:
                    LOG_EX(LOG_Info, "    ip_version:   %d\n", pObjK->objs.addr_obj[i].ip_version);
                    LOG_EX(LOG_Info, "    netmask:      %u\n", pObjK->objs.addr_obj[i].net_mask);

                    if (IP_V4 == pObjK->objs.addr_obj[i].ip_version) {
                        LOG_EX(LOG_Info, "    min addr:     %08X\n",
                               pObjK->objs.addr_obj[i].min_addr.addr_v4.ip4_addr);
                        LOG_EX(LOG_Info, "    max addr:     %08X\n",
                               pObjK->objs.addr_obj[i].max_addr.addr_v4.ip4_addr);
                    } else {
                        LOG_EX(LOG_Info,
                               "    min addr:     %04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X\n",
                               pObjK->objs.addr_obj[i].min_addr.addr_v6.addr.addr16[0],
                               pObjK->objs.addr_obj[i].min_addr.addr_v6.addr.addr16[1],
                               pObjK->objs.addr_obj[i].min_addr.addr_v6.addr.addr16[2],
                               pObjK->objs.addr_obj[i].min_addr.addr_v6.addr.addr16[3],
                               pObjK->objs.addr_obj[i].min_addr.addr_v6.addr.addr16[4],
                               pObjK->objs.addr_obj[i].min_addr.addr_v6.addr.addr16[6],
                               pObjK->objs.addr_obj[i].min_addr.addr_v6.addr.addr16[7]);
                        LOG_EX(LOG_Info,
                               "    max addr:     %04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X\n",
                               pObjK->objs.addr_obj[i].max_addr.addr_v6.addr.addr16[0],
                               pObjK->objs.addr_obj[i].max_addr.addr_v6.addr.addr16[1],
                               pObjK->objs.addr_obj[i].max_addr.addr_v6.addr.addr16[2],
                               pObjK->objs.addr_obj[i].max_addr.addr_v6.addr.addr16[3],
                               pObjK->objs.addr_obj[i].max_addr.addr_v6.addr.addr16[4],
                               pObjK->objs.addr_obj[i].max_addr.addr_v6.addr.addr16[5],
                               pObjK->objs.addr_obj[i].max_addr.addr_v6.addr.addr16[6],
                               pObjK->objs.addr_obj[i].max_addr.addr_v6.addr.addr16[7]);
                    }

                    break;

                case OBJ_TYPE_DATETIME:
                    LOG_EX(LOG_Info, "    repeat:       %d\n", pObjK->objs.dt_obj[i].rep_mode);
                    t = pObjK->objs.dt_obj[i].min_time;
                    pTm = localtime(&t);
                    memset(buf, 0, 256);
                    strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", pTm);
                    LOG_EX(LOG_Info, "    min time:     %ld[%s]\n", pObjK->objs.dt_obj[i].min_time, buf);
                    t = pObjK->objs.dt_obj[i].max_time;
                    pTm = localtime(&t);
                    memset(buf, 0, 256);
                    strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", pTm);
                    LOG_EX(LOG_Info, "    max time:     %ld[%s]\n", pObjK->objs.dt_obj[i].max_time, buf);
                    break;
            }
        }
    }
    pthread_mutex_unlock(&g_obj_lock);
}

int object_split_page(char *pSession, int type, char *outSession)
{
    if (pSession == NULL || strlen(pSession) == 0) {
        PCMHI_OBJECT pObj, pTmp;
        int sess_type = OBJ_TYPE_MAX;
        PSPLIT_PAGE pNew = (PSPLIT_PAGE) malloc(sizeof(SPLIT_PAGE));

        if (!pNew) {
            LOG_EX(LOG_Error, "Malloc memory error\n");
            return -RET_NOMEM;
        }

        memset(pNew, 0, sizeof(SPLIT_PAGE));
        create_session((unsigned char *) pNew->session, MAX_SESSION - 1);

        if (outSession) {
            strcpy(outSession, pNew->session);
        }

        HASH_ADD_STR(g_pSplitPage, session, pNew);

        if (type == 1) {
            sess_type = OBJ_TYPE_SERVER;
        } else if (type == 2) {
            sess_type = OBJ_TYPE_ADDR;
        } else if (type == 3) {
            sess_type = OBJ_TYPE_DATETIME;
        }

        pthread_mutex_lock(&g_obj_lock);
        HASH_ITER(hh, g_pObject, pObj, pTmp) {
            if (g_objItem[pObj->obj_index].type / 10 == sess_type
                || sess_type == OBJ_TYPE_MAX) {
                char *pStr = strdup(pObj->name);
                pNew->last_time = time(NULL);

                if (pNew->name_list == NULL) {
                    utarray_new(pNew->name_list, &ut_str_icd);
                }

                LOG_EX(LOG_Debug, "Add String: %s\n", pStr);
                utarray_push_back(pNew->name_list, &pStr);
            }
        }
        pthread_mutex_unlock(&g_obj_lock);
        return RET_OK;
    } else {
        LOG_EX(LOG_Error, "Input params error\n");
        return -RET_INPUTERR;
    }
}

#if 0
int get_page_items(char *pSession, int type, int start, int end)
{
    int ret = RET_OK;
    PSPLIT_PAGE p;
    int i, iCount = 0;
    char session[MAX_SESSION];

    if(pSession == NULL || strlen(pSession) == 0) {
        memset(session, 0, MAX_SESSION);
        ret = object_split_page(pSession, type, session);

        if(ret != RET_OK) {
            return ret;
        }

        pSession = session;
    }

    HASH_FIND_STR(g_pSplitPage, pSession, p);

    if(p == NULL) {
        LOG_EX(LOG_Debug, "Can't found session: %s\n", pSession);
        return -RET_NOTFOUND;
    }

    for(i = start; i < end && iCount < MAX_PAGE_ITEMS && iCount < utarray_len(p->name_list); i++) {
        char ** pStr = (char **)utarray_eltptr(p->name_list, i);
        LOG_EX(LOG_Debug, "%s[%03d]: %s\n", p->session, iCount++, *pStr);
    }

    return ret;
}
#endif

int object_add(PCMHI_OBJECT pObj, POBJECT_K pObjK)
{
    int i, pos;
    PCMHI_OBJECT p;

    if (!pObj || !pObjK) {
        LOG_EX(LOG_Error, "Input params error %p, %p\n", pObj, pObjK);
        return -RET_INPUTERR;
    }

    pthread_mutex_lock(&g_obj_lock);
    HASH_FIND_STR(g_pObject, pObj->name, p);
    pthread_mutex_unlock(&g_obj_lock);

    if (p != NULL) {
        LOG_EX(LOG_Error, "Item %s exists\n", pObj->name);
        return -RET_EXIST;
    }

    pos = get_free_pos();

    if (pos < 0) {
        LOG_EX(LOG_Error, "Share memory full\n");
        return -RET_NOMEM;
    }

    strcpy(pObjK->memTag, OBJ_MEM_TAG);

    for (i = 0; i < pObjK->ctx_num && i < MAX_OBJ_CONTENT; i++) {
        char *pStart = NULL, *pEnd = NULL;
        char *pSubStart = NULL, *pSubEnd = NULL;
        PSVR_OBJECT pSvr = &pObjK->objs.svr_obj[i];
        PADDR_OBJECT pAddr = &pObjK->objs.addr_obj[i];
        PDT_OBJECT pDt = &pObjK->objs.dt_obj[i];
        struct tm tm;

        switch (pObjK->type / 10) {
            case OBJ_TYPE_SERVER:
                split_params((char *) pSvr->str_val, &pStart, &pEnd, "-");

                if (!pcre_match(REGEX_SVR_PORT, pStart)) {
                    LOG_EX(LOG_Error, "Input %s format error\n", pStart);
                    return -RET_INPUTERR;
                } else {
                    int first;
                    first = strtoul(pStart, NULL, 10);
                    pSvr->min_port = first;
                    pSvr->max_port = 0;
                }

                if (pEnd && strlen(pEnd) > 0) {
                    int last;

                    if (!pcre_match(REGEX_SVR_PORT, pEnd)) {
                        LOG_EX(LOG_Error, "Input %s format error\n", pEnd);
                        return -RET_INPUTERR;
                    }

                    last = strtoul(pEnd, NULL, 10);

                    pSvr->max_port = last;
                }

                break;

            case OBJ_TYPE_ADDR:
                split_params((char *) pAddr->str_val, &pStart, &pEnd, "-");

                if (!pcre_match(REGEX_IP_ADDR, pStart)) {
                    LOG_EX(LOG_Error, "Input %s format error\n", pStart);
                    return -RET_INPUTERR;
                }

                split_params((char *) pStart, &pSubStart, &pSubEnd, "/");

                if (pSubEnd && strlen(pSubEnd) > 0) {
                    pAddr->net_mask = strtoul(pSubEnd, NULL, 10);
                }

                // IPv4 格式
                if (strchr(pStart, ':') == NULL) {
                    if (inet_pton(AF_INET, pSubStart, &pAddr->min_addr.addr_v4.ip4_addr) != 1) {
                        LOG_EX(LOG_Error, "%s convert to ip address error\n", pStart);
                        return -RET_INPUTERR;
                    }

                    pAddr->ip_version = IP_V4;
                } else {
                    if (inet_pton(AF_INET6, pSubStart, &pAddr->min_addr.addr_v6.addr.addr8) != 1) {
                        LOG_EX(LOG_Error, "%s convert to ip address error\n", pStart);
                        return -RET_INPUTERR;
                    }

                    pAddr->ip_version = IP_V6;
                }

                if (pEnd && strlen(pEnd) > 0) {
                    if (!pcre_match(REGEX_IP_ADDR, pEnd)) {
                        LOG_EX(LOG_Error, "Input %s format error\n", pEnd);
                        return -RET_INPUTERR;
                    }

                    if (pAddr->ip_version == IP_V4) {
                        if (inet_pton(AF_INET, pEnd, &pAddr->max_addr.addr_v4.ip4_addr) != 1) {
                            LOG_EX(LOG_Error, "%s convert to ip address error\n", pEnd);
                            return -RET_INPUTERR;
                        }
                    } else {
                        if (inet_pton(AF_INET6, pEnd, &pAddr->max_addr.addr_v6.addr.addr8) != 1) {
                            LOG_EX(LOG_Error, "%s convert to ip address error\n", pEnd);
                            return -RET_INPUTERR;
                        }
                    }
                }

                //LOG_EX(LOG_Info, "    value:        %s\n", pObjK->objs.addr_obj[j].str_val);
                break;

            case OBJ_TYPE_DATETIME:
                split_params((char *) pDt->str_val, &pStart, &pEnd, "-");

                if (!pcre_match(REGEX_DT, pStart)) {
                    LOG_EX(LOG_Error, "Input %s format error\n", pStart);
                    return -RET_INPUTERR;
                } else {
                    memset(&tm, 0, sizeof(struct tm));

                    // YYYY/MM/DD HH:MM 格式
                    if (strlen(pStart) > strlen("00:00")) {
                        strptime(pStart, "%Y/%m/%d %H:%M", &tm);
                    } else {
                        strptime(pStart, "%H:%M", &tm);
                    }

                    if (tm.tm_year < 119) {
                        tm.tm_year = 119;
                    }

                    if (tm.tm_mday < 1) {
                        tm.tm_mday = 1;
                    }

                    pDt->min_time = mktime(&tm);
                    pDt->max_time = 0;
                }

                if (pEnd && strlen(pEnd) > 0) {
                    if (!pcre_match(REGEX_DT, pEnd)) {
                        LOG_EX(LOG_Error, "Input %s format error\n", pEnd);
                        return -RET_INPUTERR;
                    }

                    memset(&tm, 0, sizeof(struct tm));

                    if (strlen(pEnd) > strlen("00:00")) {
                        strptime(pEnd, "%Y/%m/%d %H:%M", &tm);
                    } else {
                        strptime(pEnd, "%H:%M", &tm);
                    }

                    if (tm.tm_year < 119) {
                        tm.tm_year = 119;
                    }

                    if (tm.tm_mday < 1) {
                        tm.tm_mday = 1;
                    }

                    pDt->max_time = mktime(&tm);
                }

                //LOG_EX(LOG_Info, "    repeat:       %d\n", pObjK->objs.dt_obj[j].rep_mode);
                //LOG_EX(LOG_Info, "    value:        %s\n", pObjK->objs.dt_obj[j].str_val);
                break;
        }
    }

    memcpy(&g_objItem[pos], pObjK, sizeof(OBJECT_K));
    pObj->obj_index = pos;
    pthread_mutex_init(&pObj->lock, NULL);
    pthread_mutex_lock(&g_obj_lock);
    HASH_ADD_STR(g_pObject, name, pObj);
    pthread_mutex_unlock(&g_obj_lock);
    return RET_OK;
}

int object_del(const char *pName)
{
    int i;
    PCMHI_OBJECT p;

    if (!pName || strlen(pName) == 0) {
        return -RET_INPUTERR;
    }

    pthread_mutex_lock(&g_obj_lock);
    HASH_FIND_STR(g_pObject, pName, p);
    pthread_mutex_unlock(&g_obj_lock);

    if (p == NULL) {
        LOG_EX(LOG_Error, "Item %s not exists\n", pName);
        return -RET_NOTFOUND;
    }

    if (g_objItem[p->obj_index].ref_count > 0) {
        LOG_EX(LOG_Error, "Item %s used %d\n", p->name,
               g_objItem[p->obj_index].ref_count);
        return -RET_USED;
    }

    pthread_mutex_lock(&g_obj_lock);
    HASH_DEL(g_pObject, p);
    pthread_mutex_unlock(&g_obj_lock);

    for (i = 0; i < g_objItem[p->obj_index].ctx_num && i < MAX_OBJ_CONTENT; i++) {
        PSVR_OBJECT pSvr = &g_objItem[p->obj_index].objs.svr_obj[i];
        PADDR_OBJECT pAddr = &g_objItem[p->obj_index].objs.addr_obj[i];
        PDT_OBJECT pDt = &g_objItem[p->obj_index].objs.dt_obj[i];

        switch (g_objItem[p->obj_index].type / 10) {
            case OBJ_TYPE_SERVER:
                if (pSvr->str_val) {
                    free((void *) pSvr->str_val);
                }

                break;

            case OBJ_TYPE_ADDR:
                if (pAddr->str_val) {
                    free((void *) pAddr->str_val);
                }

                break;

            case OBJ_TYPE_DATETIME:
                if (pDt->str_val) {
                    free((void *) pDt->str_val);
                }

                break;
        }
    }

    memset(&g_objItem[p->obj_index], 0, sizeof(OBJECT_K));
    free(p);
    return RET_OK;
}

int object_mod(PCMHI_OBJECT pObj, POBJECT_K pObjK)
{
    int i;
    PCMHI_OBJECT p;

    if (!pObj || !pObjK) {
        LOG_EX(LOG_Error, "Input params error %p, %p\n", pObj, pObjK);
        return -RET_INPUTERR;
    }

    pthread_mutex_lock(&g_obj_lock);
    HASH_FIND_STR(g_pObject, pObj->name, p);
    pthread_mutex_unlock(&g_obj_lock);

    if (p == NULL) {
        LOG_EX(LOG_Error, "Item %s not exists\n", pObj->name);
        return -RET_EXIST;
    }

    memset(p->desc, 0, MAX_DESC);
    strncpy(p->desc, pObj->desc, MAX_DESC - 1);

    // 清理缓存的配置命令资源
    for (i = 0; i < g_objItem[p->obj_index].ctx_num && i < MAX_OBJ_CONTENT; i++) {
        PSVR_OBJECT pSvr = &g_objItem[p->obj_index].objs.svr_obj[i];
        PADDR_OBJECT pAddr = &g_objItem[p->obj_index].objs.addr_obj[i];
        PDT_OBJECT pDt = &g_objItem[p->obj_index].objs.dt_obj[i];

        switch (g_objItem[p->obj_index].type / 10) {
            case OBJ_TYPE_SERVER:
                if (pSvr->str_val) {
                    free((void *) pSvr->str_val);
                }

                break;

            case OBJ_TYPE_ADDR:
                if (pAddr->str_val) {
                    free((void *) pAddr->str_val);
                }

                break;

            case OBJ_TYPE_DATETIME:
                if (pDt->str_val) {
                    free((void *) pDt->str_val);
                }

                break;
        }
    }

    for (i = 0; i < pObjK->ctx_num && i < MAX_OBJ_CONTENT; i++) {
        char *pStart = NULL, *pEnd = NULL;
        char *pSubStart = NULL, *pSubEnd = NULL;
        PSVR_OBJECT pSvr = &pObjK->objs.svr_obj[i];
        PADDR_OBJECT pAddr = &pObjK->objs.addr_obj[i];
        PDT_OBJECT pDt = &pObjK->objs.dt_obj[i];
        struct tm tm;

        switch (pObjK->type / 10) {
            case OBJ_TYPE_SERVER:
                split_params((char *) pSvr->str_val, &pStart, &pEnd, "-");

                if (!pcre_match(REGEX_SVR_PORT, pStart)) {
                    LOG_EX(LOG_Error, "Input %s format error\n", pStart);
                    return -RET_INPUTERR;
                } else {
                    int first;
                    first = strtoul(pStart, NULL, 10);
                    pSvr->min_port = first;
                    pSvr->max_port = 0;
                }

                if (pEnd && strlen(pEnd) > 0) {
                    int last;

                    if (!pcre_match(REGEX_SVR_PORT, pEnd)) {
                        LOG_EX(LOG_Error, "Input %s format error\n", pEnd);
                        return -RET_INPUTERR;
                    }

                    //first = strtoul(pStart, NULL, 10);
                    last = strtoul(pEnd, NULL, 10);

                    pSvr->max_port = last;
                }

                break;

            case OBJ_TYPE_ADDR:
                split_params((char *) pAddr->str_val, &pStart, &pEnd, "-");

                if (!pcre_match(REGEX_IP_ADDR, pStart)) {
                    LOG_EX(LOG_Error, "Input %s format error\n", pStart);
                    return -RET_INPUTERR;
                }

                split_params((char *) pStart, &pSubStart, &pSubEnd, "/");

                if (pSubEnd && strlen(pSubEnd) > 0) {
                    pAddr->net_mask = strtoul(pSubEnd, NULL, 10);
                }

                // IPv4 格式
                if (strchr(pStart, ':') == NULL) {
                    if (inet_pton(AF_INET, pSubStart, &pAddr->min_addr.addr_v4.ip4_addr) != 1) {
                        LOG_EX(LOG_Error, "%s convert to ip address error\n", pStart);
                        return -RET_INPUTERR;
                    }

                    pAddr->ip_version = IP_V4;
                } else {
                    if (inet_pton(AF_INET6, pSubStart, &pAddr->min_addr.addr_v6.addr.addr8) != 1) {
                        LOG_EX(LOG_Error, "%s convert to ip address error\n", pStart);
                        return -RET_INPUTERR;
                    }

                    pAddr->ip_version = IP_V6;
                }

                if (pEnd && strlen(pEnd) > 0) {
                    if (!pcre_match(REGEX_IP_ADDR, pEnd)) {
                        LOG_EX(LOG_Error, "Input %s format error\n", pEnd);
                        return -RET_INPUTERR;
                    }

                    if (pAddr->ip_version == IP_V4) {
                        if (inet_pton(AF_INET, pEnd, &pAddr->max_addr.addr_v4.ip4_addr) != 1) {
                            LOG_EX(LOG_Error, "%s convert to ip address error\n", pEnd);
                            return -RET_INPUTERR;
                        }
                    } else {
                        if (inet_pton(AF_INET6, pEnd, &pAddr->max_addr.addr_v6.addr.addr8) != 1) {
                            LOG_EX(LOG_Error, "%s convert to ip address error\n", pEnd);
                            return -RET_INPUTERR;
                        }
                    }
                }

                //LOG_EX(LOG_Info, "    value:        %s\n", pObjK->objs.addr_obj[j].str_val);
                break;

            case OBJ_TYPE_DATETIME:
                split_params((char *) pDt->str_val, &pStart, &pEnd, "-");

                if (!pcre_match(REGEX_DT, pStart)) {
                    LOG_EX(LOG_Error, "Input %s format error\n", pStart);
                    return -RET_INPUTERR;
                } else {
                    memset(&tm, 0, sizeof(struct tm));

                    // YYYY/MM/DD HH:MM 格式
                    if (strlen(pStart) > strlen("00:00")) {
                        strptime(pStart, "%Y/%m/%d %H:%M", &tm);
                    } else {
                        strptime(pStart, "%H:%M", &tm);
                    }

                    if (tm.tm_year < 119) {
                        tm.tm_year = 119;
                    }

                    if (tm.tm_mday < 1) {
                        tm.tm_mday = 1;
                    }

                    pDt->min_time = mktime(&tm);
                    pDt->max_time = 0;
                }

                if (pEnd && strlen(pEnd) > 0) {
                    if (!pcre_match(REGEX_DT, pEnd)) {
                        LOG_EX(LOG_Error, "Input %s format error\n", pEnd);
                        return -RET_INPUTERR;
                    }

                    memset(&tm, 0, sizeof(struct tm));

                    if (strlen(pEnd) > strlen("00:00")) {
                        strptime(pEnd, "%Y/%m/%d %H:%M", &tm);
                    } else {
                        strptime(pEnd, "%H:%M", &tm);
                    }

                    if (tm.tm_year < 119) {
                        tm.tm_year = 119;
                    }

                    if (tm.tm_mday < 1) {
                        tm.tm_mday = 1;
                    }

                    pDt->max_time = mktime(&tm);
                }

                //LOG_EX(LOG_Info, "    repeat:       %d\n", pObjK->objs.dt_obj[j].rep_mode);
                //LOG_EX(LOG_Info, "    value:        %s\n", pObjK->objs.dt_obj[j].str_val);
                break;
        }
    }

    p->prio = pObj->prio;
    g_objItem[p->obj_index].ctx_num = pObjK->ctx_num;
    g_objItem[p->obj_index].type = pObjK->type;
    memcpy(&g_objItem[p->obj_index].objs, &pObjK->objs, sizeof(g_objItem[p->obj_index].objs));
    return RET_OK;
}

static const char *read_json_file(const char *pPath)
{
    FILE *pFile;
    unsigned char *pBuf;
    int f_size = 0;
    GET_FILE_SIZE(pPath, f_size);

    if (f_size <= 0) {
        LOG_EX(LOG_Error, "Get file %p size error: %d\n", pPath, f_size);
        return NULL;
    }

    pBuf = (unsigned char *) malloc(f_size + 1);

    if (!pBuf) {
        LOG_EX(LOG_Error, "Malloc %d bytes memory error: %d\n", f_size + 1);
        return NULL;
    }

    pFile = fopen(pPath, "r");

    if (!pFile) {
        LOG_EX(LOG_Error, "Open file %p size error\n", pPath);
        free(pBuf);
        return NULL;
    }

    fread(pBuf, 1, f_size, pFile);
    fclose(pFile);
    pBuf[f_size] = 0;
    return (const char *) pBuf;
}

static void test_del_object(void)
{
    int i, ret;
    const char *pRetJson;
    IFC_RET_MSG retCtx;
    PIFACE_DEL_OBJ pDel = NULL;
    PJSON_INTERFACE p = NULL;
    const char *pJson = read_json_file(DEL_JS_FILE);
    ret = Json2Struct(pJson, &p, JE_INTERFACE, FALSE);
    memset(&retCtx, 0, sizeof(IFC_RET_MSG));

    if (ret != RET_OK || p == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);
        free((void *) pJson);

        if (p) {
            if (p->msgContent) {
                free((void *) p->msgContent);
            }

            free(p);
        }

        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_DEL, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    LOG_EX(LOG_Info, "cmdId:        %d\n", p->cmdId);
    LOG_EX(LOG_Info, "ver:          %d\n", p->ver);
    LOG_EX(LOG_Info, "cryptoType:   %d\n", p->cryptoType);
    LOG_EX(LOG_Info, "timeStamp:    %d\n", p->timeStamp);
    LOG_EX(LOG_Info, "msgContent:   %s\n", p->msgContent);
    ret = Json2Struct(p->msgContent, &pDel, JE_OBJ_DEL, FALSE);

    if (ret != RET_OK || pDel == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);

        if (pDel) {
            free(pDel);
        }

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_DEL, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    } else {
        retCtx.n_items = pDel->n_obj;
    }

    for (i = 0; i < pDel->n_obj; i++) {
        ret = object_del(pDel->name[i]);

        if (ret != RET_OK && retCtx.ret_code == RET_OK) {
            retCtx.ret_code = ret;
        }

        retCtx.data[i].name = pDel->name[i];
        retCtx.data[i].ret_code = ret;
        retCtx.data[i].mesg = get_err_message(ret);
    }

    dump_object();
    retCtx.mesg = get_err_message(retCtx.ret_code);
    pRetJson = Struct2Json(&retCtx, JE_OBJ_DEL, FALSE, &ret);

    if (!pRetJson || ret != RET_OK) {
        LOG_EX(LOG_Error, "Json format error: %d\n", ret);

        if (pRetJson) {
            free((void *) pRetJson);
        }

        free(pDel);

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        return;
    }

    LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
    free((void *) pRetJson);
    free(pDel);

    if (p->msgContent) {
        free((void *) p->msgContent);
    }

    free(p);
    free((void *) pJson);
}

static void test_add_object(void)
{
    int i, ret;
    const char *pRetJson;
    IFC_RET_MSG retCtx;
    PJSON_INTERFACE p = NULL;
    PIFACE_ADD_OBJ pAdd = NULL;
    const char *pJson = read_json_file(ADD_JS_FILE);
    ret = Json2Struct(pJson, &p, JE_INTERFACE, FALSE);
    memset(&retCtx, 0, sizeof(IFC_RET_MSG));

    if (ret != RET_OK || p == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);
        free((void *) pJson);

        if (p) {
            if (p->msgContent) {
                free((void *) p->msgContent);
            }

            free(p);
        }

        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_ADD, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    LOG_EX(LOG_Info, "cmdId:        %d\n", p->cmdId);
    LOG_EX(LOG_Info, "ver:          %d\n", p->ver);
    LOG_EX(LOG_Info, "cryptoType:   %d\n", p->cryptoType);
    LOG_EX(LOG_Info, "timeStamp:    %d\n", p->timeStamp);
    LOG_EX(LOG_Info, "msgContent:   %s\n", p->msgContent);
    ret = Json2Struct(p->msgContent, &pAdd, JE_OBJ_ADD, FALSE);

    if (ret != RET_OK || pAdd == NULL || pAdd->pCtx == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);

        if (pAdd) {
            if (pAdd->pCtx) {
                free(pAdd->pCtx);
            }

            free(pAdd);
        }

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_ADD, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    } else {
        retCtx.n_items = pAdd->n_obj;
    }

    for (i = 0; i < pAdd->n_obj; i++) {
        LOG_EX(LOG_Debug, "%d: %s\n", i, pAdd->pCtx[i].pObj->name);
        ret = object_add(pAdd->pCtx[i].pObj, &pAdd->pCtx[i].objk);

        if (ret != RET_OK && retCtx.ret_code == RET_OK) {
            retCtx.ret_code = ret;
        }

        retCtx.data[i].name = pAdd->pCtx[i].pObj->name;
        retCtx.data[i].ret_code = ret;
        retCtx.data[i].mesg = get_err_message(ret);
    }

    for (i = 0; i < 100; i++) {
        PCMHI_OBJECT pObjItem = malloc(sizeof(CMHI_OBJECT));
        POBJECT_K pObjKItem = malloc(sizeof(OBJECT_K));

        if (pObjItem && pObjKItem) {
            memset(pObjKItem, 0, sizeof(OBJECT_K));
            memcpy(pObjItem, pAdd->pCtx[0].pObj, sizeof(CMHI_OBJECT));
            memcpy(pObjKItem, &pAdd->pCtx[0].objk, sizeof(OBJECT_K));
            sprintf(pObjItem->name, "%s_%02d", pAdd->pCtx[0].pObj->name, i);
            pObjKItem->type = 1;
            pObjKItem->ctx_num = 1;
            pObjKItem->objs.svr_obj[0].pro_type = 1;
            pObjKItem->objs.svr_obj[0].str_val = strdup("10010-10011");
            object_add(pObjItem, pObjKItem);
            free(pObjKItem);
        }
    }

    //dump_object();
    retCtx.mesg = get_err_message(retCtx.ret_code);
    pRetJson = Struct2Json(&retCtx, JE_OBJ_ADD, FALSE, &ret);

    if (!pRetJson || ret != RET_OK) {
        LOG_EX(LOG_Error, "Json format error: %d\n", ret);

        if (pRetJson) {
            free((void *) pRetJson);
        }

        if (pAdd->pCtx) {
            free(pAdd->pCtx);
        }

        free(pAdd);

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        return;
    }

    LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
    free((void *) pRetJson);

    if (pAdd->pCtx) {
        free(pAdd->pCtx);
    }

    free(pAdd);

    if (p->msgContent) {
        free((void *) p->msgContent);
    }

    free(p);
    free((void *) pJson);
}

static void test_mod_object(void)
{
    int i, ret;
    const char *pRetJson;
    IFC_RET_MSG retCtx;
    PJSON_INTERFACE p = NULL;
    PIFACE_ADD_OBJ pAdd = NULL;
    const char *pJson = read_json_file(MOD_JS_FILE);
    ret = Json2Struct(pJson, &p, JE_INTERFACE, FALSE);
    memset(&retCtx, 0, sizeof(IFC_RET_MSG));

    if (ret != RET_OK || p == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);
        free((void *) pJson);

        if (p) {
            if (p->msgContent) {
                free((void *) p->msgContent);
            }

            free(p);
        }

        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_MOD, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    LOG_EX(LOG_Info, "cmdId:        %d\n", p->cmdId);
    LOG_EX(LOG_Info, "ver:          %d\n", p->ver);
    LOG_EX(LOG_Info, "cryptoType:   %d\n", p->cryptoType);
    LOG_EX(LOG_Info, "timeStamp:    %d\n", p->timeStamp);
    LOG_EX(LOG_Info, "msgContent:   %s\n", p->msgContent);
    ret = Json2Struct(p->msgContent, &pAdd, JE_OBJ_MOD, FALSE);

    if (ret != RET_OK || pAdd == NULL || pAdd->pCtx == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);

        if (pAdd) {
            if (pAdd->pCtx) {
                for (i = 0; i < pAdd->n_obj; i++) {
                    free(pAdd->pCtx[i].pObj);
                }
                free(pAdd->pCtx);
            }

            free(pAdd);
        }

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_MOD, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    } else {
        retCtx.n_items = pAdd->n_obj;
    }

    for (i = 0; i < pAdd->n_obj; i++) {
        LOG_EX(LOG_Debug, "%d: %s\n", i, pAdd->pCtx[i].pObj->name);
        ret = object_mod(pAdd->pCtx[i].pObj, &pAdd->pCtx[i].objk);

        if (ret != RET_OK && retCtx.ret_code == RET_OK) {
            retCtx.ret_code = ret;
        }

        retCtx.data[i].name = pAdd->pCtx[i].pObj->name;
        retCtx.data[i].ret_code = ret;
        retCtx.data[i].mesg = get_err_message(ret);

        free(pAdd->pCtx[i].pObj);
    }

    dump_object();
    retCtx.mesg = get_err_message(retCtx.ret_code);
    pRetJson = Struct2Json(&retCtx, JE_OBJ_MOD, FALSE, &ret);

    if (!pRetJson || ret != RET_OK) {
        LOG_EX(LOG_Error, "Json format error: %d\n", ret);

        if (pRetJson) {
            free((void *) pRetJson);
        }

        if (pAdd->pCtx) {
            free(pAdd->pCtx);
        }

        free(pAdd);

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        return;
    }

    LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
    free((void *) pRetJson);

    if (pAdd->pCtx) {
        free(pAdd->pCtx);
    }

    free(pAdd);

    if (p->msgContent) {
        free((void *) p->msgContent);
    }

    free(p);
    free((void *) pJson);
}

static void test_strsep(char *pVal)
{
    char *pStart = NULL, *pEnd = NULL;
    split_params(pVal, &pStart, &pEnd, "-");

    if (pEnd) {
        LOG_EX(LOG_Debug, "[%s] Split to First = %s, Second = %s\n", pVal, pStart,
               pEnd);
    } else {
        LOG_EX(LOG_Debug, "[%s] Split to First = %s\n", pVal, pStart);
    }
}

static void test_regex(char *pVal)
{
    if (pcre_match(REGEX_IP_ADDR, pVal)) {
        LOG_EX(LOG_Debug, "[%s] ==> Match\n", pVal);
    } else {
        LOG_EX(LOG_Error, "[%s] ==> Not Match\n", pVal);
    }

    //LOG_EX(LOG_Debug, "Ret : [%s] ==> %d\n", pVal, pcre_match(REGEX_SVR_PORT, pVal));
}

static void test_ipaddr_format(char *pVal)
{
    int ret = 0;
    IP4_ADDR ip_v4;
    IP6_ADDR ip_v6;
    memset(&ip_v4, 0, sizeof(IP4_ADDR));
    memset(&ip_v6, 0, sizeof(IP6_ADDR));
    ret = pcre_match(REGEX_IP_ADDR, pVal);

    if (ret != TRUE) {
        LOG_EX(LOG_Error, "Verify ipadd format error\n");
    }

    if (strchr(pVal, ':') == NULL) {
        ret = inet_pton(AF_INET, pVal, &ip_v4.ip4_addr);
        print_hex_dump_bytes("IP", 0, &ip_v4, sizeof(IP4_ADDR));
    } else {
        ret = inet_pton(AF_INET6, pVal, ip_v6.addr.addr8);
        print_hex_dump_bytes("IP", 0, &ip_v6, sizeof(IP6_ADDR));
    }

    LOG_EX(LOG_Debug, "Convert %s to ip address ret: %d\n", pVal, ret);
}

static void test_str_time(char *pVal)
{
    struct tm tm;
    char buf[255];

    if (!pVal || strlen(pVal) == 0) {
        LOG_EX(LOG_Error, "Input params error\n");
        return;
    }

    memset(&tm, 0, sizeof(struct tm));
    strptime(pVal, "%H:%M", &tm);
    memset(buf, 0, sizeof(buf));
    LOG_EX(LOG_Debug, "year = %d, month = %d, day = %d\n", tm.tm_year, tm.tm_mon,
           tm.tm_mday);

    if (tm.tm_year < 119) {
        tm.tm_year = 119;
    }

    if (tm.tm_mday < 1) {
        tm.tm_mday = 1;
    }

    strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", &tm);
    LOG_EX(LOG_Debug, "asctime: %s / %d\n", buf, mktime(&tm));
    memset(&tm, 0, sizeof(struct tm));
    strptime(pVal, "%Y/%m/%d %H:%M", &tm);
    memset(buf, 0, sizeof(buf));
    strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", &tm);
    LOG_EX(LOG_Debug, "asctime: %s / %d\n", buf, mktime(&tm));
}

#if 0
static void test_random_string(char *pVal)
{
    int first;
    unsigned char *pBuf;

    if(!pVal || strlen(pVal) == 0) {
        first = 64;
    } else {
        first = strtoul(pVal, NULL, 10);
    }

    pBuf = malloc(first + 1);
    LOG_EX(LOG_Debug, "Make %d bytes\n", first);

    if(pBuf) {
        memset(pBuf, 0, first + 1);
        random_string(pBuf, first);
        free(pBuf);
    }
}
#endif

static void test_page_object(char *pVal)
{
    int i, ret;
    PSPLIT_PAGE pPage;
    PCMHI_OBJECT pObj;
    const char *pRetJson;
    IFC_RET_PAGE_MSG retCtx;
    int iCount = 0;
    PIFACE_QUERY_LIST pQuery = NULL;
    PJSON_INTERFACE p = NULL;
    const char *pJson = read_json_file(QUERY_JS_FILE);

    (void) pVal;

    ret = Json2Struct(pJson, &p, JE_INTERFACE, FALSE);
    memset(&retCtx, 0, sizeof(IFC_RET_PAGE_MSG));

    if (ret != RET_OK || p == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);
        free((void *) pJson);

        if (p) {
            if (p->msgContent) {
                free((void *) p->msgContent);
            }

            free(p);
        }

        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYLIST, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    LOG_EX(LOG_Info, "cmdId:        %d\n", p->cmdId);
    LOG_EX(LOG_Info, "ver:          %d\n", p->ver);
    LOG_EX(LOG_Info, "cryptoType:   %d\n", p->cryptoType);
    LOG_EX(LOG_Info, "timeStamp:    %d\n", p->timeStamp);
    LOG_EX(LOG_Info, "msgContent:   %s\n", p->msgContent);
    ret = Json2Struct(p->msgContent, &pQuery, JE_OBJ_QUERYLIST, FALSE);

    if (ret != RET_OK || pQuery == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);

        if (pQuery) {
            free(pQuery);
        }

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYLIST, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    if (strlen(pQuery->session) == 0) {
        memset(pQuery->session, 0, MAX_SESSION);
        ret = object_split_page("", pQuery->type, pQuery->session);

        if (ret != RET_OK) {
            LOG_EX(LOG_Error, "object_split_page error: %d\n", ret);

            free(pQuery);

            if (p->msgContent) {
                free((void *) p->msgContent);
            }

            free(p);
            free((void *) pJson);
            retCtx.ret_code = ret;
            retCtx.mesg = get_err_message(retCtx.ret_code);
            retCtx.n_items = 0;
            pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYLIST, FALSE, &ret);

            if (!pRetJson || ret != RET_OK) {
                LOG_EX(LOG_Error, "Json format error: %d\n", ret);
                return;
            }

            LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
            free((void *) pRetJson);
            return;
        }
    }

    HASH_FIND_STR(g_pSplitPage, pQuery->session, pPage);

    if (pPage == NULL) {
        LOG_EX(LOG_Debug, "Can't found session: %s\n", pQuery->session);

        free(pQuery);

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        retCtx.ret_code = -RET_NOTFOUND;
        retCtx.mesg = get_err_message(retCtx.ret_code);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYLIST, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    retCtx.ret_code = RET_OK;
    retCtx.mesg = get_err_message(retCtx.ret_code);
    retCtx.session = pQuery->session;
    retCtx.type = pQuery->type;

    if (pPage->name_list) {
        retCtx.tolItems = utarray_len(pPage->name_list);
    } else {
        retCtx.tolItems = 0;
    }

    if (pQuery->start > retCtx.tolItems) {
        retCtx.start = 0;
    } else {
        retCtx.start = pQuery->start;
    }

    retCtx.n_items = 0;
    pPage->last_time = time(NULL);

    for (i = retCtx.start; i < pQuery->end && iCount < MAX_PAGE_ITEMS && iCount < retCtx.tolItems; i++) {
        char **pStr = (char **) utarray_eltptr(pPage->name_list, i);
        pthread_mutex_lock(&g_obj_lock);
        HASH_FIND_STR(g_pObject, *pStr, pObj);
        pthread_mutex_unlock(&g_obj_lock);

        if (pObj) {
            retCtx.data[retCtx.n_items].name = pObj->name;
            retCtx.data[retCtx.n_items].desc = pObj->desc;
            retCtx.data[retCtx.n_items].ref_count = g_objItem[pObj->obj_index].ref_count;
            retCtx.data[retCtx.n_items].type = g_objItem[pObj->obj_index].type;
            retCtx.n_items++;
        }

        LOG_EX(LOG_Debug, "%s[%03d]: %s\n", pQuery->session, iCount++, *pStr);
    }

    retCtx.end = retCtx.start + iCount - 1;
    pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYLIST, FALSE, &ret);

    if (!pRetJson || ret != RET_OK) {
        LOG_EX(LOG_Error, "Json format error: %d\n", ret);
        return;
    }

    LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
    free((void *) pRetJson);

    if (p->msgContent) {
        free((void *) p->msgContent);
    }

    free(p);
    free((void *) pJson);
}

static void test_detail_object(void)
{
    int i, ret;
    const char *pRetJson;
    IFC_RET_DETAIL_MSG retCtx;
    PIFACE_DETAIL_OBJ pDetail = NULL;
    PJSON_INTERFACE p = NULL;
    const char *pJson = read_json_file(DETAIL_JS_FILE);
    ret = Json2Struct(pJson, &p, JE_INTERFACE, FALSE);
    memset(&retCtx, 0, sizeof(IFC_RET_DETAIL_MSG));

    if (ret != RET_OK || p == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);
        free((void *) pJson);

        if (p) {
            if (p->msgContent) {
                free((void *) p->msgContent);
            }

            free(p);
        }

        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYDETAIL, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    LOG_EX(LOG_Info, "cmdId:        %d\n", p->cmdId);
    LOG_EX(LOG_Info, "ver:          %d\n", p->ver);
    LOG_EX(LOG_Info, "cryptoType:   %d\n", p->cryptoType);
    LOG_EX(LOG_Info, "timeStamp:    %d\n", p->timeStamp);
    LOG_EX(LOG_Info, "msgContent:   %s\n", p->msgContent);
    ret = Json2Struct(p->msgContent, &pDetail, JE_OBJ_QUERYDETAIL, FALSE);

    if (ret != RET_OK || pDetail == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);

        if (pDetail) {
            free(pDetail);
        }

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYDETAIL, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    } else {
        retCtx.n_items = pDetail->n_obj;
    }

    retCtx.ret_code = RET_OK;

    for (i = 0; i < pDetail->n_obj; i++) {
        PCMHI_OBJECT pObj = NULL;
        pthread_mutex_lock(&g_obj_lock);
        HASH_FIND_STR(g_pObject, pDetail->name[i], pObj);
        pthread_mutex_unlock(&g_obj_lock);
        strncpy(retCtx.data[i].name, pDetail->name[i], MAX_NAME_LEN - 1);

        if (pObj) {
            retCtx.data[i].ret_code = RET_OK;
            retCtx.data[i].mesg = get_err_message(RET_OK);
            strncpy(retCtx.data[i].desc, pObj->desc, MAX_DESC - 1);
            retCtx.data[i].prio = pObj->prio;
            retCtx.data[i].pObjK = &g_objItem[pObj->obj_index];
        } else {
            retCtx.ret_code = -RET_NOTFOUND;
            retCtx.data[i].ret_code = -RET_NOTFOUND;
            retCtx.data[i].mesg = get_err_message(RET_NOTFOUND);
        }
    }

    retCtx.mesg = get_err_message(retCtx.ret_code);
    pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYDETAIL, FALSE, &ret);

    if (!pRetJson || ret != RET_OK) {
        LOG_EX(LOG_Error, "Json format error: %d\n", ret);

        if (pRetJson) {
            free((void *) pRetJson);
        }

        free(pDetail);

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        return;
    }

    LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
    free((void *) pRetJson);
    free(pDetail);

    if (p->msgContent) {
        free((void *) p->msgContent);
    }

    free(p);
    free((void *) pJson);
}

static void test_search_object(char *pVal)
{
    int i, ret;
    PCMHI_OBJECT pObj, pTmp;
    char regex_str[MAX_REGEX_LEN];
    IFC_RET_PAGE_MSG retCtx;
    int pos = 0;
    const char *pRetJson = NULL;
    PIFACE_SEARCH_OBJ pSearch = NULL;
    PJSON_INTERFACE p = NULL;
    int sess_type = OBJ_TYPE_MAX;
    PSPLIT_PAGE pNew = (PSPLIT_PAGE) malloc(sizeof(SPLIT_PAGE));
    const char *pJson = read_json_file(SEARCH_JS_FILE);

    (void) pVal;

    ret = Json2Struct(pJson, &p, JE_INTERFACE, FALSE);
    memset(&retCtx, 0, sizeof(IFC_RET_PAGE_MSG));

    if (ret != RET_OK || p == NULL || pNew == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);
        free((void *) pJson);

        if (p) {
            if (p->msgContent) {
                free((void *) p->msgContent);
            }

            free(p);
        }

        if (pNew == NULL) {
            retCtx.ret_code = -RET_NOMEM;
        } else {
            retCtx.ret_code = -RET_JSONERR;
            free(pNew);
        }

        retCtx.mesg = get_err_message(retCtx.ret_code);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_SEARCH, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    LOG_EX(LOG_Info, "cmdId:        %d\n", p->cmdId);
    LOG_EX(LOG_Info, "ver:          %d\n", p->ver);
    LOG_EX(LOG_Info, "cryptoType:   %d\n", p->cryptoType);
    LOG_EX(LOG_Info, "timeStamp:    %d\n", p->timeStamp);
    LOG_EX(LOG_Info, "msgContent:   %s\n", p->msgContent);
    ret = Json2Struct(p->msgContent, &pSearch, JE_OBJ_SEARCH, FALSE);

    if (ret != RET_OK || pSearch == NULL) {
        LOG_EX(LOG_Error, "Decode json error: %d\n", ret);
        free(pNew);

        if (pSearch) {
            free(pSearch);
        }

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        retCtx.ret_code = -RET_JSONERR;
        retCtx.mesg = get_err_message(RET_JSONERR);
        retCtx.n_items = 0;
        pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYLIST, FALSE, &ret);

        if (!pRetJson || ret != RET_OK) {
            LOG_EX(LOG_Error, "Json format error: %d\n", ret);
            return;
        }

        LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
        free((void *) pRetJson);
        return;
    }

    memset(regex_str, 0, MAX_REGEX_LEN);

    if (strlen(pSearch->key) == 0) {
        regex_str[0] = '.';
        regex_str[1] = '*';
    } else if (pSearch->regex) {
        strncpy(regex_str, pSearch->key, MAX_REGEX_LEN - 1);
    } else {
        for (i = 0; i < strlen(pSearch->key); i++) {
            if (pSearch->key[i] == '*') {
                regex_str[pos++] = '.';
                regex_str[pos++] = '*';
            } else {
                regex_str[pos++] = pSearch->key[i];
            }
        }
    }

    if (pSearch->type == 1) {
        sess_type = OBJ_TYPE_SERVER;
    } else if (pSearch->type == 2) {
        sess_type = OBJ_TYPE_ADDR;
    } else if (pSearch->type == 3) {
        sess_type = OBJ_TYPE_DATETIME;
    }

    retCtx.n_items = 0;
    retCtx.tolItems = 0;

    pthread_mutex_lock(&g_obj_lock);
    HASH_ITER(hh, g_pObject, pObj, pTmp) {
        if (g_objItem[pObj->obj_index].type / 10 == sess_type
            || sess_type == OBJ_TYPE_MAX) {
            if (pcre_match_str(regex_str, pObj->name) == TRUE) {
                char *pStr = strdup(pObj->name);
                pNew->last_time = time(NULL);

                if (pNew->name_list == NULL) {
                    utarray_new(pNew->name_list, &ut_str_icd);
                }

                utarray_push_back(pNew->name_list, &pStr);
                retCtx.tolItems++;

                if (retCtx.n_items < MAX_PAGE_ITEMS) {
                    retCtx.data[retCtx.n_items].name = pObj->name;
                    retCtx.data[retCtx.n_items].desc = pObj->desc;
                    retCtx.data[retCtx.n_items].ref_count = g_objItem[pObj->obj_index].ref_count;
                    retCtx.data[retCtx.n_items].type = g_objItem[pObj->obj_index].type;
                    retCtx.n_items++;
                }

                LOG_EX(LOG_Debug, "%s is match %s\n", pObj->name, regex_str);
            }
        }
    }
    pthread_mutex_unlock(&g_obj_lock);

    if (retCtx.tolItems > MAX_PAGE_ITEMS) {
        create_session((unsigned char *) pNew->session, MAX_SESSION - 1);
        HASH_ADD_STR(g_pSplitPage, session, pNew);
        retCtx.session = pNew->session;
    } else {
        retCtx.session = "";
        free(pNew);
    }

    retCtx.ret_code = RET_OK;
    retCtx.mesg = get_err_message(retCtx.ret_code);
    retCtx.start = 0;
    retCtx.end = retCtx.n_items > 0 ? retCtx.n_items - 1 : 0;

    pRetJson = Struct2Json(&retCtx, JE_OBJ_QUERYLIST, FALSE, &ret);

    if (!pRetJson || ret != RET_OK) {
        LOG_EX(LOG_Error, "Json format error: %d\n", ret);

        if (pRetJson) {
            free((void *) pRetJson);
        }

        free(pSearch);

        if (p->msgContent) {
            free((void *) p->msgContent);
        }

        free(p);
        free((void *) pJson);
        return;
    }

    LOG_EX(LOG_Debug, "Respons:\n%s\n", pRetJson);
    free((void *) pRetJson);
    free(pSearch);

    if (p->msgContent) {
        free((void *) p->msgContent);
    }

    free(p);
    free((void *) pJson);
}

static void test_configm_object(char* pVal)
{
    char* output = NULL;
    int output_len;
    int cmd = strtoul(pVal, 0, 10);
    const char *pJson = read_json_file(SEARCH_JS_FILE);

    web_config_exec_sync(cmd, OBJECT_CONFIG,
                         (void*)pJson, strlen(pJson) + 1, &output, &output_len);

    if(output) {
        free(output);
    }

    free((void*)pJson);
}

/**
 * @brief  应用程序主函数
 * @param  argc       输入参数个数
 * @param  argv       输入参数详细内容
 * @return 0
 */
int main(int argc, char **argv)
{
    int c, optidx = 0;
    static const struct option long_opts[] = {
            {"help",       no_argument,       NULL, 'h'},
            {"version",    no_argument,       NULL, 'v'},
            // TODO 添加其它需要处理的参数配置
            {"interface",  no_argument,       NULL, 'a'},
            {"regex",      required_argument, NULL, 'b'},
            {"split_str",  required_argument, NULL, 'c'},
            {"ip_addr",    required_argument, NULL, 'd'},
            {"str_time",   required_argument, NULL, 'e'},
            {"page_split", optional_argument, NULL, 'f'},
            {"detail",     optional_argument, NULL, 'g'},
            {"search",     optional_argument, NULL, 'i'},
            {"config",     optional_argument, NULL, 'j'},
            {NULL, 0,                         NULL, 0}
    };
    IHW_InitLOG("obj", NULL, TRUE);
    LOG_EX(LOG_Debug, "OBJECT_K = %u bytes\n", sizeof(OBJECT_K));
    LOG_EX(LOG_Debug, "DT_OBJECT = %u bytes\n", sizeof(DT_OBJECT));
    LOG_EX(LOG_Debug, "SVR_OBJECT = %u bytes\n", sizeof(SVR_OBJECT));
    LOG_EX(LOG_Debug, "ADDR_OBJECT = %u bytes\n", sizeof(ADDR_OBJECT));
    LOG_EX(LOG_Debug, "time_t = %u bytes\n", sizeof(time_t));
    LOG_EX(LOG_Debug, "g_objItem[0].objs = %u bytes\n", sizeof(g_objItem[0].objs));
    LOG_EX(LOG_Debug, "DT_OBJECT = %u bytes\n", sizeof(DT_OBJECT) * MAX_OBJ_CONTENT);
    LOG_EX(LOG_Debug, "SVR_OBJECT = %u bytes\n", sizeof(SVR_OBJECT) * MAX_OBJ_CONTENT);
    LOG_EX(LOG_Debug, "ADDR_OBJECT = %u bytes\n", sizeof(ADDR_OBJECT) * MAX_OBJ_CONTENT);

    while ((c = getopt_long(argc, argv, "ab:c:d:e:f::i::j::ghv", long_opts, &optidx)) != -1) {
        switch (c) {
            case 'v':
                LOG_EX(LOG_Info, "User demo version: %s(%s)\n", sGATE_GIT_TAGS, sGATE_GIT_VERS);
                break;

            case '?':
            case 'h':
                LOG_EX2(LOG_Info, "Usage: %s [-h] [-v] ...\n", argv[0]);
                LOG_EX2(LOG_Info, "options:\n");
                LOG_EX2(LOG_Info, "\t-v, --version show program version\n");
                LOG_EX2(LOG_Info, "\t-h, --help    print this message\n");
                LOG_EX2(LOG_Info, "\t-i, --interface    test object add interface\n");
                break;

                //TODO 添加其它必要处理参数过程
            case 'a':
                test_add_object();
                test_del_object();
                test_mod_object();
                break;

            case 'b':
                test_regex(optarg);
                break;

            case 'c':
                test_strsep(optarg);
                break;

            case 'd':
                test_ipaddr_format(optarg);
                break;

            case 'e':
                test_str_time(optarg);
                break;

            case 'f':
                test_add_object();
                test_page_object(optarg);
                break;

            case 'g':
                test_add_object();
                test_detail_object();
                break;

            case 'i':
                test_add_object();
                test_search_object(optarg);
                break;

            case 'j':
                test_configm_object(optarg);
                break;
        }
    }

    while (TRUE) {
        sleep(1);
    }

    return 0;
}