/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * XSEC
 *
 * XKMSRequestAbstractTypeImpl := Implementation class for XKMS Request messages
 *
 * $Id: XKMSRequestAbstractTypeImpl.cpp 1833340 2018-06-11 15:40:13Z scantor $
 *
 */

// XSEC Includes

#include <xsec/framework/XSECDefs.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xsec/framework/XSECEnv.hpp>


#ifdef XSEC_XKMS_ENABLED

#include "../../utils/XSECDOMUtils.hpp"

#include "XKMSRequestAbstractTypeImpl.hpp"
#include "XKMSRespondWithImpl.hpp"
#include "XKMSResponseMechanismImpl.hpp"

#include <xsec/xkms/XKMSConstants.hpp>

#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMNodeList.hpp>

XERCES_CPP_NAMESPACE_USE

// --------------------------------------------------------------------------------
//           Construct/Destruct
// --------------------------------------------------------------------------------

XKMSRequestAbstractTypeImpl::XKMSRequestAbstractTypeImpl(
	const XSECEnv * env) :
m_msg(env)
{
	mp_originalRequestIdAttr = NULL;
	mp_responseLimitAttr = NULL;
}

XKMSRequestAbstractTypeImpl::XKMSRequestAbstractTypeImpl(
	const XSECEnv * env, 
	DOMElement * node) :
m_msg(env, node)
{
	mp_originalRequestIdAttr = NULL;
	mp_responseLimitAttr = NULL;
}

XKMSRequestAbstractTypeImpl::~XKMSRequestAbstractTypeImpl() {

	RespondWithVectorType::iterator i;

	for (i = m_respondWithList.begin(); i != m_respondWithList.end(); ++i) {
		delete (*i);
	}

	ResponseMechanismVectorType::iterator j;

	for (j = m_responseMechanismList.begin(); j != m_responseMechanismList.end(); ++j) {
		delete (*j);
	}
};

// --------------------------------------------------------------------------------
//           Load
// --------------------------------------------------------------------------------

void XKMSRequestAbstractTypeImpl::load(void) {

	if (m_msg.mp_messageAbstractTypeElement == NULL) {

		// Attempt to load an empty element
		throw XSECException(XSECException::RequestAbstractTypeError,
			"XKMSRequestAbstractType::load - called on empty DOM");

	}

	// Get any respond with elements
	DOMNodeList * nl = m_msg.mp_messageAbstractTypeElement->getElementsByTagNameNS(
		XKMSConstants::s_unicodeStrURIXKMS,
		XKMSConstants::s_tagRespondWith);

	if (nl != NULL) {

		XKMSRespondWithImpl * rw;
		for (unsigned int i = 0; i < nl->getLength() ; ++ i) {

			XSECnew(rw, XKMSRespondWithImpl(m_msg.mp_env, (DOMElement *) nl->item(i)));
			rw->load();
			m_respondWithList.push_back(rw);

		}

	}

	// Get any ResponseMechanism elements
	nl = m_msg.mp_messageAbstractTypeElement->getElementsByTagNameNS(
		XKMSConstants::s_unicodeStrURIXKMS,
		XKMSConstants::s_tagResponseMechanism);

	if (nl != NULL) {

		XKMSResponseMechanismImpl * rm;
		for (unsigned int i = 0; i < nl->getLength() ; ++ i) {

			XSECnew(rm, XKMSResponseMechanismImpl(m_msg.mp_env, (DOMElement *) nl->item(i)));
			rm->load();
			m_responseMechanismList.push_back(rm);

		}

	}

	mp_originalRequestIdAttr = 
		m_msg.mp_messageAbstractTypeElement->getAttributeNodeNS(NULL, XKMSConstants::s_tagOriginalRequestId);

	mp_responseLimitAttr = 
		m_msg.mp_messageAbstractTypeElement->getAttributeNodeNS(NULL, XKMSConstants::s_tagResponseLimit);
	
		
	m_msg.load();

}

// --------------------------------------------------------------------------------
//           Create from scratch
// --------------------------------------------------------------------------------

DOMElement * XKMSRequestAbstractTypeImpl::createBlankRequestAbstractType(
		const XMLCh * tag,
		const XMLCh * service,
		const XMLCh * id) {

	return m_msg.createBlankMessageAbstractType(tag, service, id);

}

// --------------------------------------------------------------------------------
//           Get/Set interface methods
// --------------------------------------------------------------------------------

const XMLCh * XKMSRequestAbstractTypeImpl::getOriginalRequestId(void) const {

	if (mp_originalRequestIdAttr != NULL)
		return mp_originalRequestIdAttr->getNodeValue();

	return NULL;
}

void XKMSRequestAbstractTypeImpl::setOriginalRequestId(const XMLCh * id) {
	
	if (m_msg.mp_messageAbstractTypeElement == NULL) {

		// Attempt update when not initialised
		throw XSECException(XSECException::MessageAbstractTypeError,
			"XKMSRequestAbstractType::setOriginalRequestId - called on non-initialised structure");

	}

	m_msg.mp_messageAbstractTypeElement->setAttributeNS(NULL, XKMSConstants::s_tagOriginalRequestId, id);
	mp_originalRequestIdAttr = 
		m_msg.mp_messageAbstractTypeElement->getAttributeNodeNS(NULL, XKMSConstants::s_tagOriginalRequestId);

}

unsigned int XKMSRequestAbstractTypeImpl::getResponseLimit(void) const {

	if (mp_responseLimitAttr == NULL)
		return 0;

	unsigned int ret;

	if (!XMLString::textToBin(mp_responseLimitAttr->getValue(), ret))
		return 0;

	return ret;
}

void XKMSRequestAbstractTypeImpl::setResponseLimit(unsigned int limit) {

	if (m_msg.mp_messageAbstractTypeElement == NULL) {

		// Attempt update when not initialised
		throw XSECException(XSECException::MessageAbstractTypeError,
			"XKMSRequestAbstractType::setResponseLimit - called on non-initialised structure");

	}

	/* Convert the number to a string */
	XMLCh limitStr[10];
	XMLString::binToText(limit, limitStr, 9, 10);

	m_msg.mp_messageAbstractTypeElement->setAttributeNS(NULL, XKMSConstants::s_tagResponseLimit, limitStr);
	mp_responseLimitAttr = 
		m_msg.mp_messageAbstractTypeElement->getAttributeNodeNS(NULL, XKMSConstants::s_tagResponseLimit);

}

// --------------------------------------------------------------------------------
//           RespondWith handling
// --------------------------------------------------------------------------------

int XKMSRequestAbstractTypeImpl::getRespondWithSize(void) {

	return (int) m_respondWithList.size();

}

XKMSRespondWith * XKMSRequestAbstractTypeImpl::getRespondWithItem(int item) {

	if (item < 0 || item >= (int) m_respondWithList.size()) {

		throw XSECException(XSECException::RequestAbstractTypeError,
			"XKMSRequestAbstractTypeImpl::getRespondWithItem - item out of range");

	}

	return m_respondWithList[item];

}

const XMLCh * XKMSRequestAbstractTypeImpl::getRespondWithItemStr(int item) {

	if (item < 0 || item >= (int) m_respondWithList.size()) {

		throw XSECException(XSECException::RequestAbstractTypeError,
			"XKMSRequestAbstractTypeImpl::getRespondWithItem - item out of range");

	}

	return m_respondWithList[item]->getRespondWithString();

}

void XKMSRequestAbstractTypeImpl::appendRespondWithItem(XKMSRespondWith * item) {

}

void XKMSRequestAbstractTypeImpl::appendRespondWithItem(const XMLCh * item) {

	XKMSRespondWithImpl * rw;
	XSECnew(rw, XKMSRespondWithImpl(m_msg.mp_env));

	// Create the RespondWith object
	DOMElement * elt = rw->createBlankRespondWith(item);

	// Add to the item
	DOMElement * c = findFirstElementChild(m_msg.mp_messageAbstractTypeElement);
	while (c != NULL) {

		if (!strEquals(getXKMSLocalName(c), XKMSConstants::s_tagResponseMechanism))
			break;

	}

	if (c != NULL) {
		m_msg.mp_messageAbstractTypeElement->insertBefore(elt, c);
		if (m_msg.mp_env->getPrettyPrintFlag()) {
			m_msg.mp_messageAbstractTypeElement->insertBefore(
				m_msg.mp_env->getParentDocument()->createTextNode(DSIGConstants::s_unicodeStrNL), c);
		}
	}
	else {
		m_msg.mp_messageAbstractTypeElement->appendChild(elt);
		m_msg.mp_env->doPrettyPrint(m_msg.mp_messageAbstractTypeElement);
	}

	// Add to the list
	m_respondWithList.push_back(rw);

}


// --------------------------------------------------------------------------------
//           ResponseMechanism handling
// --------------------------------------------------------------------------------

int XKMSRequestAbstractTypeImpl::getResponseMechanismSize(void) {

	return (int) m_responseMechanismList.size();

}

XKMSResponseMechanism * XKMSRequestAbstractTypeImpl::getResponseMechanismItem(int item) {

	if (item < 0 || item >= (int) m_responseMechanismList.size()) {

		throw XSECException(XSECException::RequestAbstractTypeError,
			"XKMSRequestAbstractTypeImpl::getResponseMechanismItem - item out of range");

	}

	return m_responseMechanismList[item];

}

const XMLCh * XKMSRequestAbstractTypeImpl::getResponseMechanismItemStr(int item) {

	if (item < 0 || item >= (int) m_responseMechanismList.size()) {

		throw XSECException(XSECException::RequestAbstractTypeError,
			"XKMSRequestAbstractTypeImpl::getResponseMechanismItem - item out of range");

	}

	return m_responseMechanismList[item]->getResponseMechanismString();

}

void XKMSRequestAbstractTypeImpl::appendResponseMechanismItem(XKMSResponseMechanism * item) {

}

void XKMSRequestAbstractTypeImpl::appendResponseMechanismItem(const XMLCh * item) {

	XKMSResponseMechanismImpl * rw;
	XSECnew(rw, XKMSResponseMechanismImpl(m_msg.mp_env));

	// Create the ResponseMechanism object
	DOMElement * elt = rw->createBlankResponseMechanism(item);

	// Add to the item
	DOMElement * c = findFirstElementChild(m_msg.mp_messageAbstractTypeElement);
	while (c != NULL) {

		if (!strEquals(getXKMSLocalName(c), XKMSConstants::s_tagResponseMechanism))
			break;

		c = findNextElementChild(c);

	}

	if (c != NULL) {
		m_msg.mp_messageAbstractTypeElement->insertBefore(elt, c);
		if (m_msg.mp_env->getPrettyPrintFlag()) {
			m_msg.mp_messageAbstractTypeElement->insertBefore(
				m_msg.mp_env->getParentDocument()->createTextNode(DSIGConstants::s_unicodeStrNL), c);
		}
	}
	else {
		m_msg.mp_messageAbstractTypeElement->appendChild(elt);
		m_msg.mp_env->doPrettyPrint(m_msg.mp_messageAbstractTypeElement);
	}

	// Add to the list
	m_responseMechanismList.push_back(rw);

}

void XKMSRequestAbstractTypeImpl::removeResponseMechanismItem(int item) {

	if (item < 0 || item >= (int) m_responseMechanismList.size()) {

		throw XSECException(XSECException::RequestAbstractTypeError,
			"XKMSRequestAbstractTypeImpl::getResponseMechanismItem - item out of range");

	}

	XKMSResponseMechanism *rm = m_responseMechanismList[item];
	DOMNode * m = rm->getElement();
	m->getParentNode()->removeChild(m);
	m->release();

	// Now clean up our structure.
	ResponseMechanismVectorType::iterator i;
	int j = 0;
	i = m_responseMechanismList.begin();
	while (j < item) {
		j++;
		i++;
	}
	m_responseMechanismList.erase(i);

}

#endif /* XSEC_XKMS_ENABLED */
