/**
 * 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
 *
 * XSECEnv := Configuration class - used by the other classes to retrieve
 *            information on the environment they are working under
 *
 * $Id: XSECEnv.cpp 1833341 2018-06-11 16:25:41Z scantor $
 *
 */

// XSEC Includes
#include <xsec/dsig/DSIGConstants.hpp>
#include <xsec/framework/XSECEnv.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xsec/framework/XSECURIResolver.hpp>

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

#include <xercesc/util/XMLUniDefs.hpp>

struct XSECEnv::IdAttributeStruct {
	bool		m_useNamespace;		/* Was this defined with a namespace? */
	XMLCh		* mp_namespace;		/* Namespace of attribute */
	XMLCh		* mp_name;			/* Name of attribute */
};

XERCES_CPP_NAMESPACE_USE


// --------------------------------------------------------------------------------
//           Default prefix strings
// --------------------------------------------------------------------------------

const XMLCh s_default11Prefix[] = {

	chLatin_d,
	chLatin_s,
    chDigit_1,
    chDigit_1,
	chNull

};

const XMLCh s_defaultECPrefix[] = {

	chLatin_e,
	chLatin_c,
	chNull

};

const XMLCh s_defaultXPFPrefix[] = {

	chLatin_x,
	chLatin_p,
	chLatin_f,
	chNull

};

const XMLCh s_defaultXENCPrefix[] = {

	chLatin_x,
	chLatin_e,
	chLatin_n,
	chLatin_c,
	chNull

};

const XMLCh s_defaultXENC11Prefix[] = {

	chLatin_x,
	chLatin_e,
	chLatin_n,
	chLatin_c,
    chDigit_1,
    chDigit_1,
	chNull

};

#ifdef XSEC_XKMS_ENABLED
const XMLCh s_defaultXKMSPrefix[] = {

	chLatin_x,
	chLatin_k,
	chLatin_m,
	chLatin_s,
	chNull

};
#endif

// --------------------------------------------------------------------------------
//           Default Id names
// --------------------------------------------------------------------------------

const XMLCh s_Id[] = {

	chLatin_I,
	chLatin_d,
	chNull

};

const XMLCh s_id[] = {

	chLatin_i,
	chLatin_d,
	chNull

};


// --------------------------------------------------------------------------------
//           Env
// --------------------------------------------------------------------------------

// Constructors and Destructors

XSECEnv::XSECEnv(DOMDocument *doc) {

	mp_doc = doc;

	mp_prefixNS = XMLString::replicate(DSIGConstants::s_unicodeStrEmpty);
    mp_11PrefixNS = XMLString::replicate(s_default11Prefix);
	mp_ecPrefixNS = XMLString::replicate(s_defaultECPrefix);
	mp_xpfPrefixNS = XMLString::replicate(s_defaultXPFPrefix);
	mp_xencPrefixNS = XMLString::replicate(s_defaultXENCPrefix);
    mp_xenc11PrefixNS = XMLString::replicate(s_defaultXENC11Prefix);
#ifdef XSEC_XKMS_ENABLED
	mp_xkmsPrefixNS = XMLString::replicate(s_defaultXKMSPrefix);
#endif
	m_prettyPrintFlag = true;

	mp_URIResolver = NULL;

	// Set up our formatter
	XSECnew(mp_formatter, XSECSafeBufferFormatter("UTF-8",XMLFormatter::NoEscapes, 
												XMLFormatter::UnRep_CharRef));

	// Set up IDs
	m_idByAttributeNameFlag = false;		// Now off by default.
	// Register "Id" and "id" as valid Attribute names
	registerIdAttributeName(s_Id);
	registerIdAttributeName(s_id);

}

XSECEnv::XSECEnv(const XSECEnv & theOther) {

	mp_doc = theOther.mp_doc;

	mp_prefixNS = XMLString::replicate(theOther.mp_prefixNS);
    mp_11PrefixNS = XMLString::replicate(theOther.mp_11PrefixNS);
	mp_ecPrefixNS = XMLString::replicate(theOther.mp_ecPrefixNS);
	mp_xpfPrefixNS = XMLString::replicate(theOther.mp_xpfPrefixNS);
	mp_xencPrefixNS = XMLString::replicate(theOther.mp_xencPrefixNS);
    mp_xenc11PrefixNS = XMLString::replicate(s_defaultXENC11Prefix);
#ifdef XSEC_XKMS_ENABLED
	mp_xkmsPrefixNS = XMLString::replicate(theOther.mp_xkmsPrefixNS);
#endif
	m_prettyPrintFlag = theOther.m_prettyPrintFlag;

	if (theOther.mp_URIResolver != NULL)
		mp_URIResolver = theOther.mp_URIResolver->clone();
	else
		mp_URIResolver = NULL;

	// Set up our formatter
	XSECnew(mp_formatter, XSECSafeBufferFormatter("UTF-8",XMLFormatter::NoEscapes, 
												XMLFormatter::UnRep_CharRef));

	// Set up IDs
	m_idByAttributeNameFlag = theOther.m_idByAttributeNameFlag;

	for (int i = 0; i < theOther.getIdAttributeNameListSize() ; ++i) {
		registerIdAttributeName(theOther.getIdAttributeNameListItem(i));
	}

}

XSECEnv::~XSECEnv() {

	if (mp_formatter != NULL) {
		delete mp_formatter;
	}

	if (mp_prefixNS != NULL) {
		XSEC_RELEASE_XMLCH(mp_prefixNS);
	}

    if (mp_11PrefixNS != NULL) {
        XSEC_RELEASE_XMLCH(mp_11PrefixNS);
    }

	if (mp_ecPrefixNS != NULL) {
		XSEC_RELEASE_XMLCH(mp_ecPrefixNS);
	}
	
	if (mp_xpfPrefixNS != NULL) {
		XSEC_RELEASE_XMLCH(mp_xpfPrefixNS);
	}

	if (mp_xencPrefixNS != NULL) {
		XSEC_RELEASE_XMLCH(mp_xencPrefixNS);
	}

	if (mp_xenc11PrefixNS != NULL) {
		XSEC_RELEASE_XMLCH(mp_xenc11PrefixNS);
	}

#ifdef XSEC_XKMS_ENABLED
	if (mp_xkmsPrefixNS != NULL) {
		XSEC_RELEASE_XMLCH(mp_xkmsPrefixNS);
	}
#endif

	if (mp_URIResolver != NULL) {
		delete mp_URIResolver;
	}

	// Clean up Id attribute names
	IdNameVectorType::iterator it;

	for (it = m_idAttributeNameList.begin(); it != m_idAttributeNameList.end(); it++) {
		IdAttributeType * i = *it;
		if (i->mp_namespace != NULL)
			XSEC_RELEASE_XMLCH((i->mp_namespace));
		if (i->mp_name)
			XSEC_RELEASE_XMLCH((i->mp_name));

		delete *it;
	}

	m_idAttributeNameList.empty();


}

// --------------------------------------------------------------------------------
//           Set and Get Resolvers
// --------------------------------------------------------------------------------


void XSECEnv::setURIResolver(XSECURIResolver * resolver) {

	if (mp_URIResolver != 0)
		delete mp_URIResolver;

	mp_URIResolver = resolver->clone();

}

XSECURIResolver * XSECEnv::getURIResolver(void) const {

	return mp_URIResolver;

}

// --------------------------------------------------------------------------------
//           Set and Get Prefixes
// --------------------------------------------------------------------------------

void XSECEnv::setDSIGNSPrefix(const XMLCh * prefix) {

	if (mp_prefixNS != NULL)
		XSEC_RELEASE_XMLCH(mp_prefixNS);

	mp_prefixNS = XMLString::replicate(prefix);

}

void XSECEnv::setDSIG11NSPrefix(const XMLCh * prefix) {

	if (mp_11PrefixNS != NULL)
		XSEC_RELEASE_XMLCH(mp_11PrefixNS);

	mp_11PrefixNS = XMLString::replicate(prefix);

}

void XSECEnv::setECNSPrefix(const XMLCh * prefix) {

	if (mp_ecPrefixNS != NULL)
		XSEC_RELEASE_XMLCH(mp_ecPrefixNS);

	mp_ecPrefixNS = XMLString::replicate(prefix);

}

void XSECEnv::setXPFNSPrefix(const XMLCh * prefix) {

	if (mp_xpfPrefixNS != NULL)
		XSEC_RELEASE_XMLCH(mp_xpfPrefixNS);

	mp_xpfPrefixNS = XMLString::replicate(prefix);

}

void XSECEnv::setXENCNSPrefix(const XMLCh * prefix) {

	if (mp_xencPrefixNS != NULL)
		XSEC_RELEASE_XMLCH(mp_xencPrefixNS);

	mp_xencPrefixNS = XMLString::replicate(prefix);

}

void XSECEnv::setXENC11NSPrefix(const XMLCh * prefix) {

	if (mp_xenc11PrefixNS != NULL)
		XSEC_RELEASE_XMLCH(mp_xenc11PrefixNS);

	mp_xenc11PrefixNS = XMLString::replicate(prefix);

}

#ifdef XSEC_XKMS_ENABLED
void XSECEnv::setXKMSNSPrefix(const XMLCh * prefix) {

	if (mp_xkmsPrefixNS != NULL)
		XSEC_RELEASE_XMLCH(mp_xkmsPrefixNS);

	mp_xkmsPrefixNS = XMLString::replicate(prefix);

}
#endif

// --------------------------------------------------------------------------------
//           Id Attribute Names Handling
// --------------------------------------------------------------------------------

void XSECEnv::setIdByAttributeName(bool flag) {

	m_idByAttributeNameFlag = flag;

}

bool XSECEnv::getIdByAttributeName(void) const {

	return m_idByAttributeNameFlag;

}

bool XSECEnv::isRegisteredIdAttributeName(const XMLCh * name) const {

	int sz = (int) m_idAttributeNameList.size();

	for (int i = 0; i < sz; ++i) {
		if (!m_idAttributeNameList[i]->m_useNamespace &&
			strEquals(m_idAttributeNameList[i]->mp_name, name))
			return true;
	}

	return false;

}

void XSECEnv::registerIdAttributeName(const XMLCh * name) {

	if (isRegisteredIdAttributeName(name))
		return;

	IdAttributeType * iat;

	iat = new IdAttributeType;
	m_idAttributeNameList.push_back(iat);

	iat->m_useNamespace = false;
	iat->mp_namespace = NULL;
	iat->mp_name = XMLString::replicate(name);

}

bool XSECEnv::deregisterIdAttributeName(const XMLCh * name) {

	IdNameVectorType::iterator it;

	for (it = m_idAttributeNameList.begin(); it != m_idAttributeNameList.end(); it++) {
		if (!((*it)->m_useNamespace) && strEquals((*it)->mp_name, name)) {

			// Remove this item
			XSEC_RELEASE_XMLCH(((*it)->mp_name));
			delete *it;
			m_idAttributeNameList.erase(it);
			return true;
		}
	}

	return false;
}

bool XSECEnv::isRegisteredIdAttributeNameNS(const XMLCh * ns, const XMLCh * name) const {

	int sz = (int) m_idAttributeNameList.size();

	for (int i = 0; i < sz; ++i) {
		if (m_idAttributeNameList[i]->m_useNamespace &&
			strEquals(m_idAttributeNameList[i]->mp_namespace, ns) &&
			strEquals(m_idAttributeNameList[i]->mp_name, name))
			return true;
	}

	return false;

}

void XSECEnv::registerIdAttributeNameNS(const XMLCh * ns, const XMLCh * name) {

	if (isRegisteredIdAttributeNameNS(ns, name))
		return;

	IdAttributeType * iat;

	iat = new IdAttributeType;
	m_idAttributeNameList.push_back(iat);

	iat->m_useNamespace = true;
	iat->mp_namespace = XMLString::replicate(ns);;
	iat->mp_name = XMLString::replicate(name);

}

bool XSECEnv::deregisterIdAttributeNameNS(const XMLCh * ns, const XMLCh * name) {

	IdNameVectorType::iterator it;

	for (it = m_idAttributeNameList.begin(); it != m_idAttributeNameList.end(); it++) {
		if (((*it)->m_useNamespace) && 
			strEquals((*it)->mp_namespace, ns) &&
			strEquals((*it)->mp_name, name)) {

			// Remove this item
			XSEC_RELEASE_XMLCH(((*it)->mp_name));
			delete *it;
			m_idAttributeNameList.erase(it);
			return true;
		}
	}

	return false;
}

int XSECEnv::getIdAttributeNameListSize() const {

	return (int) m_idAttributeNameList.size();

}

const XMLCh * XSECEnv::getIdAttributeNameListItem(int index) const {

	if (index >= 0 && index < (int) m_idAttributeNameList.size())
		return m_idAttributeNameList[index]->mp_name;

	return NULL;

}

const XMLCh * XSECEnv::getIdAttributeNameListItemNS(int index) const {

	if (index >= 0 && index < (int) m_idAttributeNameList.size())
		return m_idAttributeNameList[index]->mp_namespace;

	return NULL;

}

bool XSECEnv::getIdAttributeNameListItemIsNS(int index) const {

	if (index >= 0 && index < (int) m_idAttributeNameList.size())
		return m_idAttributeNameList[index]->m_useNamespace;

	return false;

}

// --------------------------------------------------------------------------------
//           Set and Get Resolvers
// --------------------------------------------------------------------------------

void XSECEnv::doPrettyPrint(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * node) const {

	// Very simple
	if (m_prettyPrintFlag)
		node->appendChild(mp_doc->createTextNode(DSIGConstants::s_unicodeStrNL));

}

