#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "json_packet.h"
#include "kpacket.h"

#include "hlog.h"

#define json_simple_free_size(json) (json->cap - json_simple_len(json))

static uint32_t json_simple_suffix(json_simple *json){
    uint32_t free_size = json_simple_free_size(json);
    if ( free_size > 1 ) {
        *json->pos = '}';
       *(json->pos+1) = '\0';
        return OK;
    }
    return NG;
}

json_simple json_simple_init(char *pos, uint16_t cap){
    json_simple json;
    json.buf = pos;
    json.cap = cap;
    json.pos = pos;
   *json.pos = '{';
    json.pos++;
    json_simple_suffix(&json);
    return json;
}


#define json_snprintf(json, fmt, key, val) ({\
     uint32_t free_size = json_simple_free_size(json);\
     uint32_t n = snprintf(json->pos, free_size, fmt, key, val);\
     uint32_t ret;\
     if ( n < free_size ) {\
        json->pos += n;\
        ret = json_simple_suffix(json);\
    } else ret = NG;\
    ret;\
})

uint32_t json_simple_add_int(json_simple *json, char *key, int32_t val){
    return json_snprintf(json, json->pos - json->buf > 2 ? ",\"%s\":%d" : "\"%s\":%d", key, val);
}

uint32_t json_simple_add_str(json_simple *json, char *key, char *val){
    return json_snprintf(json, json->pos - json->buf > 2 ? ",\"%s\":\"%s\"" : "\"%s\":\"%s\"", key, val);
}

const char  *json_simple_tostring(json_simple *json){
    return json->buf;
}

const uint32_t json_simple_len(json_simple *json){
    return json->pos - json->buf + 2;
}

void json_simple_test(){
    char tmp_buf[512];
    TLV *tlv = (TLV *)tmp_buf;
    json_simple json = json_simple_init(tlv->V, sizeof(tmp_buf) - sizeof(TLV));
    tlv->T = 0x01; /*cmd*/
    json_simple_add_int(&json, "cmd", tlv->T);
    json_simple_add_str(&json, "udid", "my_uuid");
    json_simple_add_str(&json, "wakeup_type", "pir");
    tlv->L = json_simple_len(&json);
    hlogd(">>> %s json_simple_tostring:%s %u", __func__, json_simple_tostring(&json), json_simple_len(&json));
}

uint8_t json_pkt_parse(json_pkt *packet, const char *str, const char *cmd_sign){
	json_pkt_reset(packet);
	if ((packet->json = cJSON_Parse(str)) == NULL){
		hloge("%s error:%s", __func__, str);
		return 0;
	}
	if (cmd_sign){
		const uint16_t cmd = json_pkt_get_int(packet, cmd_sign, 0);
		json_pkt_setcmd(packet, cmd);
	}
	return 1;
}

void json_pkt_reset(json_pkt *packet){
	if (packet->json){
		cJSON *json = packet->json;
		cJSON_Delete(json);
	}
	memset(packet, 0, sizeof(json_pkt));
}

void json_pkt_setcmd(json_pkt *packet, const uint16_t cmd){
	packet->cmd = cmd;
}

uint8_t json_pkt_isValid(json_pkt *packet){
	return packet && packet->json!=NULL && packet->cmd!=-1;
}
//the following functions will act to mJson
void json_pkt_add_int(json_pkt *packet, const char *key, const int val){
	if (json_pkt_get_item(packet, key))	
		cJSON_Delete_itemFromObject(packet->json, key);
	if (packet->json == NULL)
		packet->json = cJSON_CreateObject();
	cJSON_AddNumberToObject(packet->json, key, val);
}
void json_pkt_add_str(json_pkt *packet, const char *key, const char *val){
	if (json_pkt_get_string(packet, key, NULL) == val){
		//__log("%s  same:%s", __func__, val);
		return;
	}
	if (json_pkt_get_item(packet, key))
		cJSON_Delete_itemFromObject(packet->json, key); 
	if (packet->json == NULL)
		packet->json = cJSON_CreateObject();
	cJSON_Add_stringToObject(packet->json, key, val);
}
void json_pkt_add_item(json_pkt *packet, const char *key, cJSON *val){
	if (json_pkt_get_item(packet, key) == val){
		return;
	}
	if (json_pkt_get_item(packet, key))
		cJSON_Delete_itemFromObject(packet->json, key);
	if (packet->json == NULL)
		packet->json = cJSON_CreateObject();
	cJSON_Add_itemToObject(packet->json, key, val);
}
void json_pkt_add_item_int(json_pkt *packet, const char *item, const char *key, const int val){
	if (packet->json == NULL)
		packet->json = cJSON_CreateObject();
	cJSON *json_item = json_pkt_get_item(packet, item);
	if (!json_item){
		json_item = cJSON_CreateObject();
		cJSON_Add_itemToObject(packet->json, item, json_item);
	}
	cJSON_AddNumberToObject(json_item, key, val);
}
void json_pkt_add_item_str(json_pkt *packet, const char *item, const char *key, const char *val){
	if (packet->json == NULL)
		packet->json = cJSON_CreateObject();
	cJSON *json_item = json_pkt_get_item(packet, item);
	if (!json_item){
		json_item = cJSON_CreateObject();
		cJSON_Add_itemToObject(packet->json, item, json_item);
	}
	cJSON_Add_stringToObject(json_item, key, val);
}
void json_pkt_remove(json_pkt *packet, const char *key){
	if (json_pkt_get_item(packet, key))
		cJSON_Delete_itemFromObject(packet->json, key);
	else
		hloge("%s not found item:%s",__func__, key);
}
cJSON *json_pkt_detach(json_pkt *packet, const char *key){
	if (json_pkt_get_item(packet, key))
		return cJSON_Detach_itemFromObject(packet->json, key);
	return NULL;
}
cJSON * json_pkt_get_item(json_pkt *packet, const char *key){
	return packet->json == NULL?NULL:cJSON_GetObject_item(packet->json, key);
}
const char *json_pkt_get_string(json_pkt *packet, const char *key, const	char *defaultVal){
	return cJSON_get_string(packet->json, key, defaultVal); 
}
int json_pkt_get_int(json_pkt *packet, const char *key, const	int defaultVal){
	return json_pkt_get_item_int(packet, packet->json, key, defaultVal);
}
uint8_t json_pkt_get_bool(json_pkt *packet, const char *key,const uint8_t defaultVal){
	return cJSON_get_bool(packet->json, key, defaultVal);
}
float json_pkt_get_float(json_pkt *packet, const char *key, const double defaultVal){
	 double value = cJSON_getDouble(packet->json, key, defaultVal);
    if (value == defaultVal) {
        //add for compitable
        cJSON * json = json_pkt_get_item(packet, key);
        if (json && (json->type == cJSON_True || json->type == cJSON_False)) {
            return json->valuedouble;
        }
    }
    return value;
}

int json_pkt_get_item_int(json_pkt *packet, cJSON * item, const char *key, const int defaultVal){
 int value = cJSON_get_int(item, key, defaultVal);
    if (value == defaultVal) {
        //add for compitable
        cJSON * json = json_pkt_get_item(packet, key);
        if (json && (json->type == cJSON_True || json->type == cJSON_False)) {
            return json->valueint;
        }
    }
    return value;
}
int json_pkt_get_intArray(json_pkt *packet, const char *key, int *array, const int size){
	cJSON * list = json_pkt_get_item(packet, key);
	if (list){
		int s = cJSON_GetArraySize(list);
		int i=0;
		for(; i<size && i<s;i++){
			cJSON *item = cJSON_GetArray_item(list, i);
			array[i] = item->valueint;
		}
		return s>size?size:s;
	}
	return 0;
}
//convert current packet->mJson object to string and append to mPacketBuffer, and do not call twice.
char *json_pkt_toJson_string(json_pkt *packet){
	if (packet->json){
		char* buffer = cJSON_PrintUnformatted(packet->json);
		return buffer;
	}
	return NULL;
}
/*
int json_pkt_printf(json_pkt *packet, const char *format, ...){
	int result;
	va_list ap;
	va_start(ap, format);
	result = packet->mPacketBuffer.vprintf(format, ap);
	va_end(ap);
	return result;
}*/
