#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#ifndef PRId64
    #error PRId64 is NOT defined
#endif

#include "ace/Init_ACE.h"
#include "vn_client_internal.h"
#include "vn_json.h"

class va_client_ini : public ACE_Cleanup
{
public:
    static ACE_THR_FUNC_RETURN event_loop(void *arg) 
    {
        ACE_Reactor *reactor = static_cast<ACE_Reactor *>(arg);
        reactor->owner(ACE_OS::thr_self());	
        reactor->run_reactor_event_loop();
        return 0;
    }

    va_client_ini()
    {
        curl_global_init(CURL_GLOBAL_ALL);
        ACE::init();

        ACE_TP_Reactor *tp_reactor(new ACE_TP_Reactor);
        delete ACE_Reactor::instance(new ACE_Reactor(tp_reactor));

        ACE_Object_Manager::instance()->at_exit(this);

        ACE_Thread_Manager::instance()->spawn_n
            (1, event_loop, ACE_Reactor::instance());

    }

    ~va_client_ini()
    {
        ACE_Reactor::instance()->end_reactor_event_loop();
    }

    static va_client_ini *vci;
};

va_client_ini *va_client_ini::vci = new va_client_ini;

vn_client_context::vn_client_context()
{
    curl_share = curl_share_init();
    curl_share_setopt(curl_share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
    curl_pool = VN_Resource_Pool<CURL>::open(16);
    cfg = (vn_client_config_t *)vn_malloc(sizeof(vn_client_config_t), NULL);
}

vn_client_context::~vn_client_context()
{
    VN_Resource_Pool<CURL>::close(curl_pool);
    curl_share_setopt(curl_share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE);
    curl_share_cleanup(curl_share);
    vn_free(cfg);
}


///////////////////////////////////
VN_Client_Result_Handler::VN_Client_Result_Handler(const VN_Client_Context_Ptr &c, const VN_Resource<CURL> &r, const VN_Asynch_Result_Ptr &a)
    : VN_CURL_Result_Handler(a), client_context_ptr_(c), resource_(r)
{
}

/*virtual*/ VN_Client_Result_Handler::~VN_Client_Result_Handler()
{
}

vn_client_context *VN_Client_Result_Handler::client_context()
{
    return client_context_ptr_.get();
}

/*virtual*/ void VN_Client_Result_Handler::parse(vn_result_t *r)
{
    char *url = 0;
    char *content_type = 0;
    curl_easy_getinfo(resource_, CURLINFO_EFFECTIVE_URL, &url);

    if (!url)
    {
        fprintf(stderr, "URL is empty\n");
        return;
    }

    curl_easy_getinfo(resource_, CURLINFO_CONTENT_TYPE, &content_type);

    fprintf(stderr, "VN_Client_Result_Handler::parse(): %s (%s), data=%s\n", url, content_type, data_.c_str());

    if(!content_type)
    {
        fprintf(stderr, "content_type is null\n");
        vn_result_set_error(r, E_VN_INTERNAL_ERROR, (char*)"Content-Type is null in response to the request '%s'", url);
        return;
    }

    vn_json_t *js = 0;
    do
    {
        if (strstr(content_type, "json"))
        {
            js = vn_json_parse(data_.c_str());
            if (!js)
            {
                vn_result_set_error(r, E_VN_INTERNAL_ERROR, (char*)"JSON parse failed: %s", data_.c_str());
                break;
            }

            int err = 0;
            const char* err_str = "";
            if(vn_json_get_type(js) == VN_JSON_OBJECT) {
                vn_json_t *code = vn_json_get_object_item(js, "code");
                //assert(code);
                if(code)
                    err = vn_json_get_int(code);
                vn_json_t *error = vn_json_get_object_item(js, "error");
                //assert(error);
                if(error)
                    err_str = vn_json_get_string(error);
            }

            if ((err && err != 200) && strlen(err_str) > 0) {
                vn_result_set_error(r, E_VN_INTERNAL_ERROR, "Error with code=%d occured: %s", err, err_str);
                break;
            } else if(strlen(err_str) > 0) {
                vn_result_set_error(r, E_VN_INTERNAL_ERROR, "%s", err_str);
                break;
            } else if(err && err != 200) {
                vn_result_set_error(r, E_VN_INTERNAL_ERROR, "Error with code=%d occured", err);
                break;
            }
        } else {
            vn_result_set_error(r, E_VN_INTERNAL_ERROR, (char*)"The response to the request '%s' is not JSON: %s", url, data_.c_str());
            break;
        }

        if (strstr(url, PATH_LOGIN_INFO.c_str()))
        {
            vn_json_t *li = vn_json_get_object_item(js, "loginInfo");
            assert(li);
            vn_json_t *item = vn_json_get_object_item(li, "encryptionKey");
            assert(item);

            char *enc_key = vn_json_get_string(item);
            assert(enc_key);

            // item = vn_json_get_object_item(li, "loginTTL");
            // assert(item);        
            // int loginTTL = vn_json_get_int(item);
            
            r->kvl = vn_kv_list_create(1);
            r->kvl[0]->key = vn_malloc(strlen("encryptionKey") + 1, NULL);
            strcpy((char*)r->kvl[0]->key, "encryptionKey");
            r->kvl[0]->value = vn_malloc(strlen(enc_key) + 1, NULL);
            strcpy((char*)r->kvl[0]->value, enc_key);
        }
        else if (strstr(url, PATH_LOGIN.c_str()))
        {
            r->kvl = vn_kv_list_create(1);
            r->kvl[0]->key = vn_malloc(strlen("DEFAULT_ROLE") + 1, NULL);
            strcpy((char*)r->kvl[0]->key, "DEFAULT_ROLE");

            vn_json_t *role = NULL;
            vn_json_t *info = vn_json_get_object_item(js, "info");
            if(info) {
                role = vn_json_get_object_item(info, "role");
                if(role)
                    role = vn_json_get_object_item(role, "obj");
            }
            
            if(!role)
                role = vn_json_get_object_item(js, "DEFAULT_ROLE");
            if (role)
            {
                char* def_role = vn_json_get_string(role);
                r->kvl[0]->value = vn_malloc(strlen(def_role)+1, NULL);
                strcpy((char*)r->kvl[0]->value, def_role);
            }
        }
        else if (strstr(url, PATH_GET_RESOURCE_TREE.c_str()))
        {
            vn_json_t *role = vn_json_get_object_item(js, "role");
            assert(role && vn_json_get_type(role) == VN_JSON_OBJECT);

            char* def_role = vn_json_get_string(vn_json_get_object_item(role, "obj"));

            vn_json_t *roles = vn_json_get_object_item(js, "roles");
            assert(roles && vn_json_get_type(roles) == VN_JSON_OBJECT);

            const char k_name[] = "name", k_sets[] = "sets", k_objs[] = "objects", k_descr[] = "description",
                    *additional_attrs[] = {"otype", "subtype", "protected", "permission", "credentials"};
            int i = 0;
            for (vn_json_t *role = vn_json_child(roles); role != 0; role = vn_json_next(role), i++);
            fprintf(stderr, "roles size=%d\n", i);
            r->kvl = vn_kv_list_create(i);

            i = 0;
            for (vn_json_t *role = vn_json_child(roles); role != 0; role = vn_json_next(role), i++)
            {
                char* role_str = vn_json_get_string(vn_json_get_object_item(role, "obj"));
                r->kvl[i]->key = vn_malloc(strlen(role_str)+1, NULL);
                strcpy((char*)r->kvl[i]->key, role_str);

                bool b_def_role = !strcmp(def_role, (char*)r->kvl[i]->key);
                vn_kv_t **r_kvl = b_def_role ? vn_kv_list_create(4)
                                             : vn_kv_list_create(2);
                r->kvl[i]->value = r_kvl;

                const char *k_attrs[] = {k_name, k_descr};
                size_t k=0;
                for (; k < sizeof(k_attrs)/sizeof(char*); k++)
                {
                    r_kvl[k]->key = vn_malloc(strlen(k_attrs[k])+1, NULL);
                    strcpy((char*)r_kvl[k]->key, k_attrs[k]);

                    char *value = vn_json_get_string(vn_json_get_object_item(role, k_attrs[k]));
                    r_kvl[k]->value = vn_malloc(strlen(value)+1, NULL);
                    strcpy((char*)r_kvl[k]->value, value);
                }

                if (!b_def_role)
                    continue;

                r_kvl[k]->key = vn_malloc(sizeof(k_sets), NULL);
                strcpy((char*)r_kvl[k]->key, k_sets);

                r_kvl[k+1]->key = vn_malloc(sizeof(k_objs), NULL);
                strcpy((char*)r_kvl[k+1]->key, k_objs);

                vn_json_t *sets = vn_json_get_object_item(js, k_sets);
                assert(sets && vn_json_get_type(sets) == VN_JSON_OBJECT);

                vn_json_t *objs = vn_json_get_object_item(js, k_objs);
                assert(objs && vn_json_get_type(objs) == VN_JSON_OBJECT);

                int j = 0;
                for (vn_json_t *set = vn_json_child(sets); set != 0; set = vn_json_next(set), j++);
                fprintf(stderr, "sets size=%d\n", j);
                vn_kv_t **s_kvl = vn_kv_list_create(j);
                r_kvl[k++]->value = s_kvl;

                j = 0;
                for (vn_json_t *set = vn_json_child(sets); set != 0; set = vn_json_next(set), j++)
                {
                    char* set_str = vn_json_get_string(vn_json_get_object_item(set, "obj"));
                    s_kvl[j]->key = vn_malloc(strlen(set_str)+1, NULL);
                    strcpy((char*)s_kvl[j]->key, set_str);

                    vn_kv_t **s_attr_kvl = vn_kv_list_create(2);
                    s_kvl[j]->value = s_attr_kvl;

                    s_attr_kvl[0]->key = vn_malloc(sizeof(k_name), NULL);
                    strcpy((char*)s_attr_kvl[0]->key, k_name);
                    char* value = vn_json_get_string(vn_json_get_object_item(set, k_name));
                    s_attr_kvl[0]->value = vn_malloc(strlen(value)+1, NULL);
                    strcpy((char*)s_attr_kvl[0]->value, value);

                    s_attr_kvl[1]->key = vn_malloc(sizeof(k_objs), NULL);
                    strcpy((char*)s_attr_kvl[1]->key, k_objs);

                    vn_json_t *objects = vn_json_get_object_item(set, k_objs);
                    assert(objects && vn_json_get_type(objects) == VN_JSON_ARRAY);

                    fprintf(stderr, "[%d] set name=%s, id=%s\n", j, value, (char*)s_kvl[j]->key);

                    vn_kv_t **o_list_kvl = vn_kv_list_create(vn_json_get_array_size(objects));
                    int n = 0;
                    for (vn_json_t *obj = vn_json_child(objects); obj != 0; obj = vn_json_next(obj), n++)
                    {
                        char* obj_str = vn_json_get_string(obj);
                        vn_json_t *o = vn_json_get_object_item(objs, obj_str);
                        char* obj_name_str = vn_json_get_string(vn_json_get_object_item(o, k_name));
                        o_list_kvl[n]->key = vn_malloc(strlen(obj_name_str)+1, NULL);
                        strcpy((char*)o_list_kvl[n]->key, obj_name_str);

                        o_list_kvl[n]->value = vn_malloc(strlen(obj_str)+1, NULL);
                        strcpy((char*)o_list_kvl[n]->value, obj_str);
                        fprintf(stderr, "OBJ[%s]=%s\n", obj_str, obj_name_str);
                    }
                    s_attr_kvl[1]->value = o_list_kvl;
                }

                j = 0;
                for (vn_json_t *obj = vn_json_child(objs); obj != 0; obj = vn_json_next(obj), j++);
                fprintf(stderr, "objects size=%d\n", j);
                vn_kv_t **o_kvl = vn_kv_list_create(j);
                r_kvl[k]->value = o_kvl;

                j = 0;
                for (vn_json_t *obj = vn_json_child(objs); obj != 0; obj = vn_json_next(obj), j++)
                {
                    char* obj_name_str = vn_json_get_string(vn_json_get_object_item(obj, "obj"));
                    o_kvl[j]->key = vn_malloc(strlen(obj_name_str)+1, NULL);
                    strcpy((char*)o_kvl[j]->key, obj_name_str);

                    vn_json_t *attr = vn_json_get_object_item(obj, "attributes");
                    assert(attr && vn_json_get_type(attr) == VN_JSON_OBJECT);

                    vn_kv_t **o_attr_kvl = vn_kv_list_create(vn_json_get_array_size(attr) + sizeof(additional_attrs)/sizeof(char*));
                    int n = 0;
                    for (vn_json_t *a = vn_json_child(attr); a != 0; a = vn_json_next(a), n++)
                    {
                        o_attr_kvl[n]->key   = vn_malloc(strlen(vn_json_get_name(a))+1, NULL);
                        o_attr_kvl[n]->value = vn_malloc(strlen(vn_json_get_string(a))+1, NULL);

                        strcpy((char*)o_attr_kvl[n]->key, vn_json_get_name(a));
                        strcpy((char*)o_attr_kvl[n]->value, vn_json_get_string(a));
                    }

                    //fprintf(stderr, "obj=%d\n", *((unsigned*)o_kvl[j]->key));
                    for (size_t k = 0; k < sizeof(additional_attrs)/sizeof(char*); k++, n++)
                    {
                        o_attr_kvl[n]->key = vn_malloc(strlen(additional_attrs[k]) + 1, NULL);
                        strcpy((char*)o_attr_kvl[n]->key, additional_attrs[k]);

                        vn_json_t *json = vn_json_get_object_item(obj, additional_attrs[k]);
                        if (json)
                        {
                            char *value = vn_json_get_string(json);
                            o_attr_kvl[n]->value = vn_malloc(strlen(value) + 1, NULL);
                            strcpy((char*)o_attr_kvl[n]->value, value);
                            //fprintf(stderr, "%s=%s, ", additional_attrs[k], value);
                        }
                        else
                        {
                            o_attr_kvl[n]->value = vn_malloc(1, NULL);
                            o_attr_kvl[n]->value = NULL;
                        }
                    }
                    //fprintf(stderr, "\n");

                    o_kvl[j]->value = o_attr_kvl;
                }
            }
        }
        else if (strstr(url, PATH_GET_OBJECTS.c_str()))
        {
            vn_json_t *list = vn_json_get_object_item(js, "list");
            assert(list && vn_json_get_type(list) == VN_JSON_ARRAY);

            r->kvl = vn_kv_list_create(vn_json_get_array_size(list));

            const char *additional_attrs[] = {"otype", "subtype", "protected", "permission", "credentials"};
            int i = 0;
            for (vn_json_t *obj = vn_json_child(list); obj != 0; obj = vn_json_next(obj), i++)
            {
                const char* o = vn_json_get_string(vn_json_get_object_item(obj, "obj"));
                r->kvl[i]->key = vn_malloc(strlen(o)+1, NULL);
                strcpy((char*)r->kvl[i]->key, o);

                vn_json_t *attr = vn_json_get_object_item(obj, "attributes");
                assert(attr && vn_json_get_type(attr) == VN_JSON_OBJECT);

                vn_kv_t **kvl = vn_kv_list_create(vn_json_get_array_size(attr) + sizeof(additional_attrs)/sizeof(char*));
                int j = 0;
                for (vn_json_t *a = vn_json_child(attr); a != 0; a = vn_json_next(a), j++)
                {
                    kvl[j]->key   = vn_malloc(strlen(vn_json_get_name(a))+1, NULL);
                    kvl[j]->value = vn_malloc(strlen(vn_json_get_string(a))+1, NULL);

                    strcpy((char*)kvl[j]->key, vn_json_get_name(a));
                    strcpy((char*)kvl[j]->value, vn_json_get_string(a));                        
                }
        
                //fprintf(stderr, "obj=%d\n", *((unsigned*)r->kvl[i]->key));
                for (size_t k = 0; k < sizeof(additional_attrs)/sizeof(char*); k++, j++)
                {
                    kvl[j]->key = vn_malloc(strlen(additional_attrs[k]) + 1, NULL);
                    strcpy((char*)kvl[j]->key, additional_attrs[k]);

                    vn_json_t *js = vn_json_get_object_item(obj, additional_attrs[k]);
                    if (js)
                    {
                        char *value = vn_json_get_string(js);
                        kvl[j]->value = vn_malloc(strlen(value) + 1, NULL);
                        strcpy((char*)kvl[j]->value, value);
                        //fprintf(stderr, "%s=%s, ", additional_attrs[k], value);
                    }
                    else
                        kvl[j]->value = vn_malloc(1, NULL);
                }
                //fprintf(stderr, "\n");

                r->kvl[i]->value = kvl;
            }
        }
        else if (strstr(url, PATH_GET_SETS.c_str()) || strstr(url, PATH_GET_ROLES.c_str()))
        {
            vn_json_t *list = vn_json_get_object_item(js, "list");
            assert(list && vn_json_get_type(list) == VN_JSON_ARRAY);

            r->kvl = vn_kv_list_create(vn_json_get_array_size(list));
            int i = 0;
            for (vn_json_t *obj = vn_json_child(list); obj != 0; obj = vn_json_next(obj), i++)
            {
                const char* objid = vn_json_get_string(vn_json_get_object_item(obj, "obj"));
                const char* name  = vn_json_get_string(vn_json_get_object_item(obj, "name"));

                r->kvl[i]->key = vn_malloc(strlen(objid)+1, NULL);
                strcpy((char*)r->kvl[i]->key, objid);

                r->kvl[i]->value = vn_malloc(strlen(name)+1, NULL);
                strcpy((char*)r->kvl[i]->value, name);
            }
        }
        else if (strstr(url, PATH_GET_EVENTS.c_str()))
        {
            const char *additional_attrs[] = {"objId", "length", "tagList"};
            const char *t_attrs[] = {"from", "when", "to"};
            const char *i_attrs[] = {"source", "priority", "lastModified"};
            const char *s_attrs[] = {"eventId", "message", "note", "bgColor"};

            r->kvl = vn_kv_list_create(vn_json_get_array_size(js));
            int i = 0;
            for (vn_json_t *obj = vn_json_child(js); obj != 0; obj = vn_json_next(obj), i++)
            {
                r->kvl[i]->key = vn_malloc(sizeof(unsigned), NULL);
                *((unsigned*)r->kvl[i]->key) = atoi(vn_json_get_string(vn_json_get_object_item(obj, "eventid")));

                vn_kv_t **kvl = vn_kv_list_create((sizeof(t_attrs) + sizeof(i_attrs) + sizeof(s_attrs) + sizeof(additional_attrs))/sizeof(char*));
                int j = 0;
                for (size_t k = 0; k < sizeof(s_attrs)/sizeof(char*); k++, j++)
                {
                    kvl[j]->key = vn_malloc(strlen(s_attrs[k]) + 1, NULL);
                    strcpy((char*)kvl[j]->key, s_attrs[k]);

                    vn_json_t *o = vn_json_get_object_item(obj, s_attrs[k]);
                    if(o) {
                        const char *value = vn_json_get_string(o);
                        if(!value)
                            value = "";
                        kvl[j]->value = vn_malloc(strlen(value) + 1, NULL);
                        strcpy((char*)kvl[j]->value, value);
                        //fprintf(stderr, "%s=%s, ", additional_attrs[k], value);
                    }
                    else
                        kvl[j]->value = vn_malloc(1, NULL);
                }

                struct tm ptm;
                for (size_t k = 0; k < sizeof(t_attrs)/sizeof(char*); k++, j++)
                {
                    kvl[j]->key = vn_malloc(strlen(t_attrs[k]) + 1, NULL);
                    strcpy((char*)kvl[j]->key, t_attrs[k]);

                    vn_json_t *o = vn_json_get_object_item(obj, t_attrs[k]);
                    if(o) {
                        time_t ts = vn_json_get_double(o)/1000;
                        ACE_OS::localtime_r(&ts, &ptm);
                        char t[20] = {"\0"};
                        size_t len = strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", &ptm);
                        if(!len)
                            t[0] = '\0';

                        kvl[j]->value = vn_malloc(len + 1, NULL);
                        strcpy((char*)kvl[j]->value, t);
                        //fprintf(stderr, "%s=%s, ", additional_attrs[k], value);
                    }
                    else
                        kvl[j]->value = vn_malloc(1, NULL);
                }

                for (size_t k = 0; k < sizeof(i_attrs)/sizeof(char*); k++, j++)
                {
                    kvl[j]->key = vn_malloc(strlen(i_attrs[k]) + 1, NULL);
                    strcpy((char*)kvl[j]->key, i_attrs[k]);

                    vn_json_t *prop = vn_json_get_object_item(obj, i_attrs[k]);
                    if(prop && vn_json_get_type(prop) == VN_JSON_NUMBER) {
                        char p[20] = {"\0"};
                        sprintf(p, "%" PRId64, (int64_t)vn_json_get_double(prop));
                        kvl[j]->value = vn_malloc(strlen(p) + 1, NULL);
                        strcpy((char*)kvl[j]->value, p);
                    } else if(prop && vn_json_get_type(prop) == VN_JSON_STRING) {
                        char* p = vn_json_get_string(prop);
                        kvl[j]->value = vn_malloc(strlen(p) + 1, NULL);
                        strcpy((char*)kvl[j]->value, p);
                    } else
                        kvl[j]->value = vn_malloc(1, NULL);
                }

                vn_json_t *from = vn_json_get_object_item(obj, t_attrs[0]),
                          *to   = vn_json_get_object_item(obj, t_attrs[2]);
                time_t duration = from && to ? (vn_json_get_double(to) - vn_json_get_double(from))/1000 : 0;
                ptm.tm_hour = duration/3600;
                duration %= 3600;
                ptm.tm_min = duration/60;
                ptm.tm_sec = duration%60;

                char t[9] = {"\0"};
                size_t len = strftime(t, sizeof(t), "%H:%M:%S", &ptm);
                if(!len)
                    t[0] = '\0';

                // objId
                kvl[j]->key = vn_malloc(strlen(additional_attrs[0]) + 1, NULL);
                strcpy((char*)kvl[j]->key, additional_attrs[0]);
                vn_json_t* object = vn_json_get_object_item(obj, "object");
                vn_json_t* objId = object ? vn_json_get_object_item(object, additional_attrs[0]) : NULL;
                const char* objid = objId ? vn_json_get_string(objId) : "";
                kvl[j]->value = vn_malloc(strlen(objid) + 1, NULL);
                strcpy((char*)kvl[j++]->value, objid);

                // duration
                kvl[j]->key = vn_malloc(strlen(additional_attrs[1]) + 1, NULL);
                strcpy((char*)kvl[j]->key, additional_attrs[1]);
                kvl[j]->value = vn_malloc(len + 1, NULL);
                strcpy((char*)kvl[j++]->value, t);

                // tagList as string
                kvl[j]->key = vn_malloc(strlen(additional_attrs[2]) + 1, NULL);
                strcpy((char*)kvl[j]->key, additional_attrs[2]);
                vn_json_t* tags = vn_json_get_object_item(obj, additional_attrs[2]);
                std::string tagList;
                if(tags && vn_json_get_type(tags) == VN_JSON_ARRAY) {
                    int n = 0;
                    char t[16] = {"\0"};
                    for (vn_json_t *tag = vn_json_child(tags); tag != 0; tag = vn_json_next(tag), n++) {
                        sprintf(t, "%s%d", n ? "," : "", vn_json_get_int(tag));
                        tagList += t;
                    }
                }
                kvl[j]->value = vn_malloc(tagList.size() + 1, NULL);
                strcpy((char*)kvl[j]->value, tagList.c_str());

                r->kvl[i]->value = kvl;
            }
        }
        else if (strstr(url, PATH_GET_MOBILE_MEDIA_URL.c_str()))
        {
            //vn_json_t *result = vn_json_get_object_item(js, "result");
            //assert(result && vn_json_get_type(result) == VN_JSON_OBJECT);
            
            //vn_json_t *jauthid = vn_json_get_object_item(result, "authid");
            //assert(jauthid);

            vn_json_t *jurl = vn_json_get_object_item(js, "url");
            assert(jurl);

            std::string url = std::string(vn_json_get_string(jurl));
            /*                  + (jauthid ? "&authorizationid=" + std::string(vn_json_get_string(jauthid)) : "");*/

            r->kvl = vn_kv_list_create(1);
            r->kvl[0]->value = vn_malloc(url.size() + 1, NULL);
            strcpy((char*)r->kvl[0]->value, url.c_str());
        }
        else if (strstr(url, PATH_GET_SNAPSHOT.c_str()))
        {
            if (data_.empty())
            {
                vn_result_set_error(r, E_VN_INTERNAL_ERROR, "Server return no data");
                break;
            }

            r->kvl = vn_kv_list_create(1);
            r->kvl[0]->key   = vn_malloc(sizeof(unsigned), NULL);
            r->kvl[0]->value = vn_malloc(data_.size(), NULL);

            *((unsigned*)r->kvl[0]->key) = data_.size();

            memcpy(r->kvl[0]->value, data_.data(), data_.size());

        }
        else if (strstr(url, PATH_ADD_OBJECT.c_str()))
        {
            if (data_.empty())
            {
                vn_result_set_error(r, E_VN_INTERNAL_ERROR, "Server return no data");
                break;
            }

            vn_json_t *objid = vn_json_get_object_item(js, "obj");
            if (objid)
            {
                r->kvl = vn_kv_list_create(1);
                r->kvl[0]->key = vn_malloc(strlen("objid")+1, NULL);
                strcpy((char*)r->kvl[0]->key, "objid");
                r->kvl[0]->value = vn_malloc(sizeof(int), NULL);
                *((int*)r->kvl[0]->value) = atoi(vn_json_get_string(objid));
            }
        }
        else if (strstr(url, PATH_SEND_PTZ_COMMAND.c_str()))
        {
            fprintf(stderr, "PTZ data: %s\n", data_.c_str());
        }
        else if (strstr(url, PATH_EVENT.c_str()))
        {
            fprintf(stderr, "event do-action: %s\n", data_.c_str());
        }
        else if(strstr(url, PATH_GET_USERS.c_str()))
        {
            fprintf(stderr, "Users info: %s\n", data_.c_str());
        }
        else if(strstr(url, PATH_GET_SERVER_INFO.c_str()))
        {
            fprintf(stderr, "Server info: %s\n", data_.c_str());

            vn_json_t *section = vn_json_get_object_item(js, "section");
            assert(section && vn_json_get_type(section) == VN_JSON_OBJECT);
            vn_json_t *info = vn_json_get_object_item(section, "info");
            assert(info && vn_json_get_type(info) == VN_JSON_OBJECT);

            int i = 0;
            for (vn_json_t *obj = vn_json_child(info); obj != 0; obj = vn_json_next(obj), i++);
            fprintf(stderr, "info size=%d\n", i);

            r->kvl = vn_kv_list_create(i);

            i = 0;
            for (vn_json_t *obj = vn_json_child(info); obj != 0; obj = vn_json_next(obj), i++)
            {
                const char *k = vn_json_get_name(obj);
                const char *v = vn_json_get_string(obj);
                if (!v)
                    v = "";

                r->kvl[i]->key = vn_malloc(strlen(k)+1, NULL);
                r->kvl[i]->value = vn_malloc(strlen(v)+1, NULL);

                strcpy((char*)r->kvl[i]->key, k);
                strcpy((char*)r->kvl[i]->value, v);
            }
        }
    } while (0);

    if (js)
        vn_json_destroy(js);
}
