#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include <libxml/parser.h>
#include "tango_cache_xml.h"

bool parse_uploadID_xml(const char *content, int len, char **uploadID)
{
	xmlDoc *pdoc;
	xmlNode *pcur;
	
	if((pdoc = xmlParseMemory(content, len)) == NULL)
	{
		return false;
	}
	if((pcur = xmlDocGetRootElement(pdoc)) == NULL)
	{
		xmlFreeDoc(pdoc);
		return false;
	}

	while(pcur->type != XML_ELEMENT_NODE)
		pcur = pcur->next;
	if(xmlStrcmp(pcur->name, (const xmlChar *)"InitiateMultipartUploadResult"))
	{
		xmlFreeDoc(pdoc);
		return false;
	}
	pcur = pcur->children;
	while(pcur != NULL)
	{
		if(pcur->type != XML_ELEMENT_NODE || xmlStrcmp(pcur->name, (const xmlChar *)"UploadId"))
		{
			pcur = pcur->next;
			continue;
		}
		*uploadID = (char *)xmlNodeGetContent(pcur);
		xmlFreeDoc(pdoc);
		return true;
	}

	xmlFreeDoc(pdoc);
	return false;
}

void construct_complete_xml(struct tango_cache_ctx *ctx, char **xml, int *len)
{
	struct multipart_etag_list *etag;
	xmlDoc *pdoc;
	xmlNode *root, *child;
	char number[20];

	pdoc = xmlNewDoc((const xmlChar *)"1.0");
	root = xmlNewNode(NULL, (const xmlChar *)"CompleteMultipartUpload");
	/*Big data deletion of this field parsing, shielding this field**/
	//xmlNewProp(root, (const xmlChar *)"xmlns",(const xmlChar *)"http://s3.amazonaws.com/doc/2006-03-01/");
	xmlDocSetRootElement(pdoc, root);

	TAILQ_FOREACH(etag, &ctx->put.etag_head, node)
	{
		sprintf(number, "%u", etag->part_number);
		child = xmlNewChild(root, NULL, (const xmlChar*)"Part", NULL);
		xmlNewChild(child, NULL, (const xmlChar*)"ETag", (const xmlChar*)etag->etag);
		xmlNewChild(child, NULL, (const xmlChar*)"PartNumber", (const xmlChar*)number);
	}
	
	xmlDocDumpFormatMemory(pdoc, (xmlChar **)xml, len, 1);
	xmlFreeDoc(pdoc);
}

static void fill_multidelete_xml_errcode(xmlNode *error, char *out, int size)
{
	xmlChar *errcode;
	xmlNode *child = error->children;

	while(child != NULL)
	{
		if(child->type != XML_ELEMENT_NODE || xmlStrcmp(child->name, (const xmlChar *)"Message"))
		{
			child = child->next;
			continue;
		}
		errcode = xmlNodeGetContent(child);
		snprintf(out, size, "%s", (char *)errcode);
		xmlFree(errcode);
		break;
	}
}

bool parse_multidelete_xml(const char *xml, int len, u_int32_t *errnum, char *errstr, int size)
{
	xmlDoc *pdoc;
	xmlNode *pcur;
	int errornum=0;
	
	if((pdoc = xmlParseMemory(xml, len)) == NULL)
	{
		return false;
	}
	if((pcur = xmlDocGetRootElement(pdoc)) == NULL)
	{
		xmlFreeDoc(pdoc);
		return false;
	}

	while(pcur->type != XML_ELEMENT_NODE)
		pcur = pcur->next;
	if(xmlStrcmp(pcur->name, (const xmlChar *)"DeleteResult"))
	{
		xmlFreeDoc(pdoc);
		return false;
	}
	pcur = pcur->children;
	while(pcur != NULL)
	{
		if(pcur->type != XML_ELEMENT_NODE || xmlStrcmp(pcur->name, (const xmlChar *)"Error"))
		{
			pcur = pcur->next;
			continue;
		}
		if(errornum == 0)
		{
			fill_multidelete_xml_errcode(pcur, errstr, size);
		}
		errornum++;
		pcur = pcur->next;
	}
	*errnum = errornum;

	xmlFreeDoc(pdoc);
	return true;
}

void construct_multiple_delete_xml(const char *bucket, char *key[], u_int32_t num, int is_hash, char **xml, size_t *len)
{
	xmlDoc *pdoc;
	xmlNode *root, *child;
	int xmllen;

	pdoc = xmlNewDoc((const xmlChar *)"1.0");
	root = xmlNewNode(NULL, (const xmlChar *)"Delete");
	xmlDocSetRootElement(pdoc, root);

	xmlNewChild(root, NULL, (const xmlChar*)"Quiet", (const xmlChar*)"true");

	if(is_hash)
	{
		char hashkey[72], sha256[72];
		for(u_int32_t i=0; i<num; i++)
		{
			child = xmlNewChild(root, NULL, (const xmlChar*)"Object", NULL);			
			caculate_sha256(key[i], strlen(key[i]), sha256, 72);
			snprintf(hashkey, 256, "%c%c_%c%c_%s", sha256[0], sha256[1], sha256[2], sha256[3], sha256+4);
			xmlNewChild(child, NULL, (const xmlChar*)"Key", (const xmlChar*)hashkey);
		}
	}
	else
	{
		for(u_int32_t i=0; i<num; i++)
		{
			child = xmlNewChild(root, NULL, (const xmlChar*)"Object", NULL);
			xmlNewChild(child, NULL, (const xmlChar*)"Key", (const xmlChar*)key[i]);
		}
	}
	xmlDocDumpFormatMemoryEnc(pdoc, (xmlChar **)xml, &xmllen, "UTF-8", 1);
	xmlFreeDoc(pdoc);
	*len = xmllen;
}

