/*
 * D4AsyncUtil.cc
 *
 *  Created on: Feb 18, 2014
 *      Author: ndp
 */

#include "config.h"

#include <sstream>

#include "XMLWriter.h"

#include "Error.h"
#include "InternalErr.h"
#include "util.h"

#include "D4AsyncUtil.h"
#include "DapXmlNamespaces.h"

namespace libdap {

const string D4AsyncUtil::STYLESHEET_REFERENCE_KEY = "DAP.Async.StyleSheet.Ref";

D4AsyncUtil::D4AsyncUtil()  {}

D4AsyncUtil::~D4AsyncUtil() {}

/**
 * @brief Print the AsyncRequired response to the.
 * Print the AsyncRequired in XML form.
 * @param xml Print to this XMLWriter instance
 */
void D4AsyncUtil::writeD4AsyncRequired(XMLWriter &xml, long expectedDelay, long responseLifetime, string *stylesheet_ref) {

	// ------ AsynchronousResponse Element and Attributes - BEGIN

	/*
	int	xmlTextWriterWriteAttributeNS	(xmlTextWriterPtr writer,
						 const xmlChar * prefix,
						 const xmlChar * name,
						 const xmlChar * namespaceURI,
						 const xmlChar * content)
	*/

	if(stylesheet_ref){
		string href = "href='" + *stylesheet_ref +"'";
		if(xmlTextWriterStartPI(xml.get_writer(), (const xmlChar*) "xml-stylesheet") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not start XML Processing Instruction.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) "type='text/xsl'") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) " ") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) href.c_str()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterEndPI(xml.get_writer()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not Close XML Processing Instruction.");
	}

	DapXmlNamspaces dapns;
	if (xmlTextWriterStartElementNS(xml.get_writer(),
			(const xmlChar*)"dap",
			(const xmlChar*) "AsynchronousResponse",
			(const xmlChar*) dapns.getDapNamespaceString(DAP_4_0).c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write AsynchronousResponse element");
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "status", (const xmlChar *) "required") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'status'");


	// ------ expectedDelay Element and Attributes
	if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dap:expectedDelay") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write expectedDelay element");
	ostringstream oss;
	oss << expectedDelay;
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "seconds", (const xmlChar*) oss.str().c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'status'");
	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end expectedDelay element");
	// ------ expectedDelay Element and Attributes - END


	// ------ responseLifetime Element and Attributes
	if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dap:responseLifetime") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write expectedDelay element");
	ostringstream oss2;
	oss2 << responseLifetime;
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "seconds", (const xmlChar*) oss2.str().c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'seconds'");
	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end responseLifetime element");
	// ------ responseLifetime Element and Attributes - END


	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end AsynchronousResponse element");
	// ------ AsynchronousResponse Element and Attributes - END
}


/**
 * @brief Print the AsyncRequired response to the.
 * Print the AsyncRequired in XML form.
 * @param xml Print to this XMLWriter instance
 */
void D4AsyncUtil::writeD4AsyncAccepted(XMLWriter &xml, long expectedDelay, long responseLifetime, string asyncResourceUrl, string *stylesheet_ref)  {

	// ------ AsynchronousResponse Element and Attributes - BEGIN
	DapXmlNamspaces dapns;

	if(stylesheet_ref){
		string href = "href='" + *stylesheet_ref +"'";
		if(xmlTextWriterStartPI(xml.get_writer(), (const xmlChar*) "xml-stylesheet") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not start XML Processing Instruction.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) "type='text/xsl'") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) " ") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) href.c_str()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterEndPI(xml.get_writer()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not Close XML Processing Instruction.");
	}

	if (xmlTextWriterStartElementNS(xml.get_writer(),
			(const xmlChar*)"dap",
			(const xmlChar*) "AsynchronousResponse",
			(const xmlChar*) dapns.getDapNamespaceString(DAP_4_0).c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write AsynchronousResponse element");
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "status", (const xmlChar *) "accepted") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'status'");


	// ------ expectedDelay Element and Attributes
	if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dap:expectedDelay") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write expectedDelay element");
	ostringstream oss;
	oss << expectedDelay;
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "seconds", (const xmlChar*) oss.str().c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'seconds'");
	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end expectedDelay element");
	// ------ expectedDelay Element and Attributes - END


	// ------ responseLifetime Element and Attributes
	if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dap:responseLifetime") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write expectedDelay element");
	ostringstream oss2;
	oss2 << responseLifetime;
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "seconds", (const xmlChar*) oss2.str().c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'seconds'");
	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end responseLifetime element");
	// ------ responseLifetime Element and Attributes - END


	// ------ link Element and Attributes
	if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dap:link") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write expectedDelay element");

	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) asyncResourceUrl.c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'href'");
	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end link element");
	// ------ link Element and Attributes - END


	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end AsynchronousResponse element");
	// ------ AsynchronousResponse Element and Attributes - END
}

/**
 * @brief Print the AsyncRequired response to the.
 * Print the AsyncRequired in XML form.
 * @param xml Print to this XMLWriter instance
 */
void D4AsyncUtil::writeD4AsyncPending(XMLWriter &xml, string *stylesheet_ref)  {

	// ------ AsynchronousResponse Element and Attributes - BEGIN
	DapXmlNamspaces dapns;


	if(stylesheet_ref){
		string href = "href='" + *stylesheet_ref +"'";
		if(xmlTextWriterStartPI(xml.get_writer(), (const xmlChar*) "xml-stylesheet") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not start XML Processing Instruction.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) "type='text/xsl'") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) " ") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) href.c_str()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterEndPI(xml.get_writer()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not Close XML Processing Instruction.");
	}

	if (xmlTextWriterStartElementNS(xml.get_writer(),
			(const xmlChar*)"dap",
			(const xmlChar*) "AsynchronousResponse",
			(const xmlChar*) dapns.getDapNamespaceString(DAP_4_0).c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write AsynchronousResponse element");
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "status", (const xmlChar *) "pending") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'status'");

	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end AsynchronousResponse element");
	// ------ AsynchronousResponse Element and Attributes - END
}


/**
 * @brief Print the AsyncRequired response to the.
 * Print the AsyncRequired in XML form.
 * @param xml Print to this XMLWriter instance
 */
void D4AsyncUtil::writeD4AsyncResponseGone(XMLWriter &xml, string *stylesheet_ref)  {

	// ------ AsynchronousResponse Element and Attributes - BEGIN
	DapXmlNamspaces dapns;


	if(stylesheet_ref){
		string href = "href='" + *stylesheet_ref +"'";
		if(xmlTextWriterStartPI(xml.get_writer(), (const xmlChar*) "xml-stylesheet") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not start XML Processing Instruction.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) "type='text/xsl'") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) " ") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) href.c_str()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterEndPI(xml.get_writer()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not Close XML Processing Instruction.");
	}

	if (xmlTextWriterStartElementNS(xml.get_writer(),
			(const xmlChar*)"dap",
			(const xmlChar*) "AsynchronousResponse",
			(const xmlChar*) dapns.getDapNamespaceString(DAP_4_0).c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write AsynchronousResponse element");
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "status", (const xmlChar *) "gone") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'status'");

	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end AsynchronousResponse element");
	// ------ AsynchronousResponse Element and Attributes - END
}


/**
 * @brief Print the AsyncRequired response to the.
 * Print the AsyncRequired in XML form.
 * @param xml Print to this XMLWriter instance
 */
void D4AsyncUtil::writeD4AsyncResponseRejected(XMLWriter &xml, RejectReasonCode code, string description, string *stylesheet_ref) {

	// ------ AsynchronousResponse Element and Attributes - BEGIN
	DapXmlNamspaces dapns;


	if(stylesheet_ref){
		string href = "href='" + *stylesheet_ref +"'";
		if(xmlTextWriterStartPI(xml.get_writer(), (const xmlChar*) "xml-stylesheet") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not start XML Processing Instruction.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) "type='text/xsl'") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) " ") < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) href.c_str()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not write Processing Instruction content.");
		if(xmlTextWriterEndPI(xml.get_writer()) < 0)
			throw InternalErr(__FILE__, __LINE__, "Could not Close XML Processing Instruction.");
	}

	if (xmlTextWriterStartElementNS(xml.get_writer(),
			(const xmlChar*)"dap",
			(const xmlChar*) "AsynchronousResponse",
			(const xmlChar*) dapns.getDapNamespaceString(DAP_4_0).c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write AsynchronousResponse element");
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "status", (const xmlChar *) "rejected") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'status'");

	// ------ reason Element and Attributes
	if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dap:reason") < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write reason element");
	if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "code", (const xmlChar*) getRejectReasonCodeString(code).c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write attribute for 'code'");
	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end reason element");
	// ------ reason Element and Attributes - END


	// ------ description Element and Attributes
	if (xmlTextWriterWriteElement(xml.get_writer(), (const xmlChar*) "dap:description", (const xmlChar*) description.c_str()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not write description element");

	// ------ description Element and Attributes - END

	if (xmlTextWriterEndElement(xml.get_writer()) < 0)
		throw InternalErr(__FILE__, __LINE__, "Could not end AsynchronousResponse element");
	// ------ AsynchronousResponse Element and Attributes - END


}

string D4AsyncUtil::getRejectReasonCodeString(RejectReasonCode code){

	string codeStr;
	switch(code){
	case TIME:
		codeStr = "time";
		break;

	case UNAVAILABLE:
		codeStr = "unavailable";
		break;

	case PRIVILEGES:
		codeStr = "privileges";
		break;

	case OTHER:
		codeStr = "other";
		break;

	default:
		throw InternalErr(__FILE__, __LINE__, "D4AsyncUtil::getRejectReasonCodeString() - Unrecognized reject_reason_code.");
	}

	return codeStr;
}

// Unused paramters generate warnings, so I removed/commented them below. jhrg 3/12/14
void D4AsyncUtil::writeD2AsyncRequired(XMLWriter &/*xml*/, long /*expectedDelay*/, long /*responseLifetime*/)  {
	throw InternalErr(__FILE__, __LINE__, "DAP2 Doesn't handle Async.");
}

void D4AsyncUtil::writeD2AsyncAccepted(XMLWriter &, long , long , string /*asyncResourceUrl*/)  {
	throw InternalErr(__FILE__, __LINE__, "DAP2 Doesn't handle Async.");
}


void D4AsyncUtil::writeD2AsyncPending(XMLWriter &)  {
	throw InternalErr(__FILE__, __LINE__, "DAP2 Doesn't handle Async.");
}

void D4AsyncUtil::writeD2AsyncResponseGone(XMLWriter &)  {
	throw InternalErr(__FILE__, __LINE__, "DAP2 Doesn't handle Async.");
}

void D4AsyncUtil::writeD2AsyncResponseRejected(XMLWriter &, RejectReasonCode /*code*/, string /*description*/)  {
	throw InternalErr(__FILE__, __LINE__, "DAP2 Doesn't handle Async.");
}

} /* namespace libdap */
