/**
 * 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
 *
 * DSIGTransformXPathFilter := Class that performs XPath Filter 
 *                             transforms
 *
 * Author(s): Berin Lautenbach
 *
 * $Id: DSIGTransformXPathFilter.cpp 1833341 2018-06-11 16:25:41Z scantor $
 *
 */

#include <xsec/dsig/DSIGSignature.hpp>
#include <xsec/dsig/DSIGTransformXPathFilter.hpp>
#include <xsec/dsig/DSIGXPathFilterExpr.hpp>
#include <xsec/framework/XSECEnv.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xsec/transformers/TXFMXPathFilter.hpp>
#include <xsec/transformers/TXFMChain.hpp>

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

#include <xercesc/dom/DOMNode.hpp>

XERCES_CPP_NAMESPACE_USE

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

DSIGTransformXPathFilter::DSIGTransformXPathFilter(const XSECEnv * env, DOMNode * node) :
DSIGTransform(env, node),
m_loaded(false) {

}


DSIGTransformXPathFilter::DSIGTransformXPathFilter(const XSECEnv * env) :
DSIGTransform(env),
m_loaded(false) {

}


DSIGTransformXPathFilter::~DSIGTransformXPathFilter() {

    for (exprVectorType::iterator i = m_exprs.begin(); i != m_exprs.end(); ++i) {
        delete (*i);
    }
}


void DSIGTransformXPathFilter::appendTransformer(TXFMChain * input) {

    if (m_loaded == false) {
        throw XSECException(XSECException::XPathFilterError,
            "DSIGTransformXPathFilter::appendTransform - load not yet called");
    }

#ifndef XSEC_HAVE_XPATH
    throw XSECException(XSECException::UnsupportedFunction,
        "XPath transforms are not supported in this build of the XSEC library");
#else
    TXFMXPathFilter *xpf;
    // XPath transform
    XSECnew(xpf, TXFMXPathFilter(mp_txfmNode->getOwnerDocument()));
    input->appendTxfm(xpf);

    // These can throw, but the TXFMXPathFilter is now owned by the chain, so will
    // be cleaned up down the calling stack.

    xpf->evaluateExprs(&m_exprs);

#endif /* NO_XPATH */

}

// --------------------------------------------------------------------------------
//           Create a blank transform
// --------------------------------------------------------------------------------


DOMElement * DSIGTransformXPathFilter::createBlankTransform(DOMDocument* parentDoc) {

    safeBuffer str;
    const XMLCh * prefix;
    DOMElement *ret;
    DOMDocument *doc = mp_env->getParentDocument();

    prefix = mp_env->getDSIGNSPrefix();

    // Create the transform node
    makeQName(str, prefix, "Transform");
    ret = doc->createElementNS(DSIGConstants::s_unicodeStrURIDSIG, str.rawXMLChBuffer());
    ret->setAttributeNS(NULL,DSIGConstants::s_unicodeStrAlgorithm, DSIGConstants::s_unicodeStrURIXPF);

    mp_txfmNode = ret;

    m_loaded = true;

    return ret;
}

DSIGXPathFilterExpr* DSIGTransformXPathFilter::appendFilter(
        DSIGXPathFilterExpr::XPathFilterType filterType,
        const XMLCh* filterExpr) {

    DSIGXPathFilterExpr * e;

    XSECnew(e, DSIGXPathFilterExpr(mp_env));

    DOMNode * elt = e->setFilter(filterType, filterExpr);
    m_exprs.push_back(e);

    mp_txfmNode->appendChild(elt);
    mp_env->doPrettyPrint(mp_txfmNode);

    return e;

}

// --------------------------------------------------------------------------------
//           Load from XML
// --------------------------------------------------------------------------------

void DSIGTransformXPathFilter::load() {

    if (mp_txfmNode == NULL) {
        throw XSECException(XSECException::XPathFilterError,
            "DSIGTransformXPathFilter::load called on NULL node");
    }

    // Very simple - go through each child.  If it's an XPath child
    // Create the DSIGXPathFilterExpr object

    DOMNode * n = mp_txfmNode->getFirstChild();

    while (n != NULL) {
        if (n->getNodeType() == DOMNode::ELEMENT_NODE &&
            strEquals(getXPFLocalName(n), "XPath")) {

            DSIGXPathFilterExpr * xpf;
            XSECnew(xpf, DSIGXPathFilterExpr(mp_env, n));

            // Add it to the vector prior to load to ensure deleted if
            // anything throws an exception

            m_exprs.push_back(xpf);

            xpf->load();
        }

        n = n->getNextSibling();
    }

    m_loaded = true;
}

// --------------------------------------------------------------------------------
//           Retrieve expression information
// --------------------------------------------------------------------------------

unsigned int DSIGTransformXPathFilter::getExprNum() const {
    return (unsigned int) m_exprs.size();
}


DSIGXPathFilterExpr* DSIGTransformXPathFilter::expr(unsigned int n) const {

    if (n < m_exprs.size())
        return m_exprs[n];

    return NULL;
}
