#include "common.h"

int print_to_ubus(struct json_object *parsed_response, struct ubus_context *ctx, struct ubus_request_data *req)
{
	struct blob_buf bb;

	memset(&bb, 0, sizeof(bb));
	blob_buf_init(&bb, 0);
	json_to_blob(parsed_response, &bb);
	ubus_send_reply(ctx, req, bb.head);
	blob_buf_free(&bb);

	json_object_put(parsed_response);
	return 0;
}

void json_to_blob(struct json_object *response, struct blob_buf *bb)
{
	void *arr, *obj;
	int i;

	json_object_object_foreach(response, key, val) {
		int val_type = json_object_get_type(val);

		switch (val_type) {
		case json_type_int:
			blobmsg_add_u32(bb, key, json_object_get_int(val));
			break;
		case json_type_double:
			blobmsg_add_double(bb, key, json_object_get_double(val));
			break;
		case json_type_string:
			blobmsg_add_string(bb, key, json_object_get_string(val));
			break;
		case json_type_array:
			arr = blobmsg_open_array(bb, key);
			for (i = 0; i < json_object_array_length(val); i++) {
				// add open table?
				json_to_blob(json_object_array_get_idx(val, i), bb);
				// add close table?
			}
			blobmsg_close_array(bb, arr);
			break;
		case json_type_object:
			obj = blobmsg_open_table(bb, key);
			json_to_blob(val, bb);
			blobmsg_close_table(bb, obj);
			break;
		}
	}
}

struct json_object *get_json_string_object_by_key(json_object *json_obj, char *string)
{
	json_object_iter iterator;
	json_object *string_object = NULL;
	enum json_type type;

	type = json_object_get_type(json_obj);
	if (type == json_type_object) {
		//search the key from the json object
		json_object_object_foreachC(json_obj, iterator) {
			printf("iteratorKey is :%s\n", iterator.key);
			if (strcmp(string, (char *)iterator.key) == 0) {
				string_object = json_object_object_get(json_obj,iterator.key);
				printf("Input string value: %s\n", (char *)json_object_get_string(iterator.val));
				break;
			}
		}
	}
	return string_object;
}

void xml_to_json(xmlNode *anode, json_object *jobj)
{
	xmlNodePtr cur_node = NULL;
	json_object *cur_jstr = NULL;

	for (cur_node = anode; cur_node; cur_node = cur_node->next) {
		//debug_print("child address: %p\n", cur_node);
		//debug_print("next addres: %p\n", cur_node->next);
		//debug_print("root child content: %s\n", (uint8_t *)xmlNodeGetContent(cur_node));

		if (cur_node->type == XML_ELEMENT_NODE) {
			if (xmlChildElementCount(cur_node) == 0) {
				cur_jstr = json_object_new_string((char *)xmlNodeGetContent(cur_node));
				debug_print("xmlNodeGet name: %s\n", (char *)cur_node->name);
				json_object_object_add(jobj, (char *)cur_node->name, cur_jstr);
			}
		}

		xml_to_json(cur_node->children, jobj);
	}
}

//free memory...
struct json_object *xml_to_json_converter(struct write_result *result)
{
	json_object *jobj;
	xmlDocPtr doc_ptr = NULL;
	xmlNode *origin_node = NULL;

	doc_ptr = xmlParseMemory(result->data, result->pos);
	if (!doc_ptr)
		goto fail_doc_ptr;
	debug_print("data from xml: %s\n", result->data);

	origin_node = xmlDocGetRootElement(doc_ptr);
	if (!origin_node)
		goto fail_origin_node;

	jobj = json_object_new_object();
	xml_to_json(origin_node, jobj);

	debug_print("Json object from xml: %s\n", json_object_to_json_string(jobj));

	if (doc_ptr)
		xmlFreeDoc(doc_ptr);

	return jobj;

fail_origin_node:
	if (doc_ptr)
		xmlFreeDoc(doc_ptr);
fail_doc_ptr:
	return NULL;

}

int isdigits(const char *str)
{
	while (*str) {
		if (isdigit(*str++) == 0)
			return false;
	}

	return true;
}

int validate_puk_format(char *puk)
{
	if (!isdigits(puk)) {
		debug_print("Please enter digits only!\n");
		goto fail;
	} else if (strlen(puk) != 8) {
		debug_print("Please enter 8 digits!\n");
		goto fail;
	}

	return 0;
fail:
	return -1;
}

int validate_pin_format(char *pin)
{
	if (!isdigits(pin)) {
		debug_print("Please enter digits only!\n");
		goto fail;
	} else if (strlen(pin) > 8 || strlen(pin) < 4) {
		debug_print("Please enter between 4 to 8 digits!\n");
		goto fail;
	} else if (atoi(pin) == 0) {
		debug_print("0000 is not a valid pin! Lowest available is 0001\n");
		goto fail;
	}

	return 0;
fail:
	return -1;
}

int pin_status(struct blob_buf *bb, struct device *dev)
{
	struct json_object *response, *rv_json;
	const char *rv;
	int pin_status;

	response = mobile_get_pin_status(dev);
	if (!response) {
		debug_print("no response from get_pin_status!\n");
		goto fail_response;
	}

	json_object_object_get_ex(response, "pin_status", &rv_json);
	if (!rv_json) {
		debug_print("no pin_status available in response!\n");
		goto fail_result;
	}

	rv = json_object_get_string(rv_json);
	if (strncmp(rv, "0", 1) == 0)
		blobmsg_add_string(bb, "Failure", "Pin disabled");
	else
		blobmsg_add_string(bb, "Failure", "Pin enabled");

	pin_status = atoi(rv);
	json_object_put(response);
	return pin_status;
fail_response:
fail_result:
	json_object_put(response);
	return -1;
}

int check_response(struct json_object *response)
{
	struct json_object *rv_json;

	json_object_object_get_ex(response, "result", &rv_json);
	if (!rv_json) {
		debug_print("no result available in response!\n");
		goto fail;
	}

	if (strncmp(json_object_get_string(rv_json), "failure", strlen("failure")) == 0)
		goto fail;

	return 0;
fail:
	return -1;
}

void remove_newline(char *input)
{
	char *pos;

	pos = strchr(input, '\n');
	if (!pos)
		return;

	*pos = '\0';
}