/*
 * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
 * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "XPathStep.h"

#include "Attr.h"
#include "Document.h"
#include "ElementInlines.h"
#include "HTMLElement.h"
#include "NodeTraversal.h"
#include "XMLNSNames.h"
#include "XPathParser.h"
#include "XPathUtil.h"

namespace WebCore {
namespace XPath {

Step::Step(Axis axis, NodeTest nodeTest)
    : m_axis(axis)
    , m_nodeTest(WTFMove(nodeTest))
{
}

Step::Step(Axis axis, NodeTest nodeTest, Vector<std::unique_ptr<Expression>> predicates)
    : m_axis(axis)
    , m_nodeTest(WTFMove(nodeTest))
    , m_predicates(WTFMove(predicates))
{
}

Step::~Step() = default;

void Step::optimize()
{
    // Evaluate predicates as part of node test if possible to avoid building unnecessary NodeSets.
    // E.g., there is no need to build a set of all "foo" nodes to evaluate "foo[@bar]", we can check the predicate while enumerating.
    // This optimization can be applied to predicates that are not context node list sensitive, or to first predicate that is only context position sensitive, e.g. foo[position() mod 2 = 0].
    Vector<std::unique_ptr<Expression>> remainingPredicates;
    for (auto& predicate : m_predicates) {
        if ((!predicateIsContextPositionSensitive(*predicate) || m_nodeTest.m_mergedPredicates.isEmpty()) && !predicate->isContextSizeSensitive() && remainingPredicates.isEmpty())
            m_nodeTest.m_mergedPredicates.append(WTFMove(predicate));
        else
            remainingPredicates.append(WTFMove(predicate));
    }
    m_predicates = WTFMove(remainingPredicates);
}

void optimizeStepPair(Step& first, Step& second, bool& dropSecondStep)
{
    dropSecondStep = false;

    if (first.m_axis != Step::DescendantOrSelfAxis)
        return;

    if (first.m_nodeTest.m_kind != Step::NodeTest::AnyNodeTest)
        return;

    if (!first.m_predicates.isEmpty())
        return;

    if (!first.m_nodeTest.m_mergedPredicates.isEmpty())
        return;

    ASSERT(first.m_nodeTest.m_data.isEmpty());
    ASSERT(first.m_nodeTest.m_namespaceURI.isEmpty());

    // Optimize the common case of "//" AKA /descendant-or-self::node()/child::NodeTest to /descendant::NodeTest.
    if (second.m_axis != Step::ChildAxis)
        return;

    if (!second.predicatesAreContextListInsensitive())
        return;

    first.m_axis = Step::DescendantAxis;
    first.m_nodeTest = WTFMove(second.m_nodeTest);
    first.m_predicates = WTFMove(second.m_predicates);
    first.optimize();
    dropSecondStep = true;
}

bool Step::predicatesAreContextListInsensitive() const
{
    for (auto& predicate : m_predicates) {
        if (predicateIsContextPositionSensitive(*predicate) || predicate->isContextSizeSensitive())
            return false;
    }

    for (auto& predicate : m_nodeTest.m_mergedPredicates) {
        if (predicateIsContextPositionSensitive(*predicate) || predicate->isContextSizeSensitive())
            return false;
    }

    return true;
}

void Step::evaluate(Node& context, NodeSet& nodes) const
{
    EvaluationContext& evaluationContext = Expression::evaluationContext();
    evaluationContext.position = 0;

    nodesInAxis(context, nodes);

    // Check predicates that couldn't be merged into node test.
    for (auto& predicate : m_predicates) {
        NodeSet newNodes;
        if (!nodes.isSorted())
            newNodes.markSorted(false);

        for (unsigned j = 0; j < nodes.size(); j++) {
            Node* node = nodes[j];

            evaluationContext.node = node;
            evaluationContext.size = nodes.size();
            evaluationContext.position = j + 1;
            if (evaluatePredicate(*predicate))
                newNodes.append(node);
        }

        nodes = WTFMove(newNodes);
    }
}

#if ASSERT_ENABLED
static inline Node::NodeType primaryNodeType(Step::Axis axis)
{
    switch (axis) {
        case Step::AttributeAxis:
            return Node::ATTRIBUTE_NODE;
        default:
            return Node::ELEMENT_NODE;
    }
}
#endif // ASSERT_ENABLED

// Evaluate NodeTest without considering merged predicates.
inline bool nodeMatchesBasicTest(Node& node, Step::Axis axis, const Step::NodeTest& nodeTest)
{
    switch (nodeTest.m_kind) {
        case Step::NodeTest::TextNodeTest:
            return node.nodeType() == Node::TEXT_NODE || node.nodeType() == Node::CDATA_SECTION_NODE;
        case Step::NodeTest::CommentNodeTest:
            return node.nodeType() == Node::COMMENT_NODE;
        case Step::NodeTest::ProcessingInstructionNodeTest: {
            const AtomString& name = nodeTest.m_data;
            return node.nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node.nodeName() == name);
        }
        case Step::NodeTest::AnyNodeTest:
            return true;
        case Step::NodeTest::NameTest: {
            const AtomString& name = nodeTest.m_data;
            const AtomString& namespaceURI = nodeTest.m_namespaceURI;

            if (axis == Step::AttributeAxis) {
                ASSERT(node.isAttributeNode());

                // In XPath land, namespace nodes are not accessible on the attribute axis.
                if (node.namespaceURI() == XMLNSNames::xmlnsNamespaceURI)
                    return false;

                if (name == starAtom())
                    return namespaceURI.isEmpty() || node.namespaceURI() == namespaceURI;

                return node.localName() == name && node.namespaceURI() == namespaceURI;
            }

            // Node test on the namespace axis is not implemented yet, the caller has a check for it.
            ASSERT(axis != Step::NamespaceAxis);

            // For other axes, the principal node type is element.
            ASSERT(primaryNodeType(axis) == Node::ELEMENT_NODE);
            if (!is<Element>(node))
                return false;

            if (name == starAtom())
                return namespaceURI.isEmpty() || namespaceURI == node.namespaceURI();

            if (node.document().isHTMLDocument()) {
                if (is<HTMLElement>(node)) {
                    // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace. Names are compared case-insensitively.
                    return equalIgnoringASCIICase(downcast<HTMLElement>(node).localName(), name) && (namespaceURI.isNull() || namespaceURI == node.namespaceURI());
                }
                // An expression without any prefix shouldn't match no-namespace nodes (because HTML5 says so).
                return downcast<Element>(node).hasLocalName(name) && namespaceURI == node.namespaceURI() && !namespaceURI.isNull();
            }
            return downcast<Element>(node).hasLocalName(name) && namespaceURI == node.namespaceURI();
        }
    }
    ASSERT_NOT_REACHED();
    return false;
}

inline bool nodeMatches(Node& node, Step::Axis axis, const Step::NodeTest& nodeTest)
{
    if (!nodeMatchesBasicTest(node, axis, nodeTest))
        return false;

    EvaluationContext& evaluationContext = Expression::evaluationContext();

    // Only the first merged predicate may depend on position.
    ++evaluationContext.position;

    for (auto& predicate : nodeTest.m_mergedPredicates) {
        // No need to set context size - we only get here when evaluating predicates that do not depend on it.
        evaluationContext.node = &node;
        if (!evaluatePredicate(*predicate))
            return false;
    }

    return true;
}

// Result nodes are ordered in axis order. Node test (including merged predicates) is applied.
void Step::nodesInAxis(Node& context, NodeSet& nodes) const
{
    ASSERT(nodes.isEmpty());
    switch (m_axis) {
        case ChildAxis:
            if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;
            for (Node* node = context.firstChild(); node; node = node->nextSibling()) {
                if (nodeMatches(*node, ChildAxis, m_nodeTest))
                    nodes.append(node);
            }
            return;
        case DescendantAxis:
            if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;
            for (Node* node = context.firstChild(); node; node = NodeTraversal::next(*node, &context)) {
                if (nodeMatches(*node, DescendantAxis, m_nodeTest))
                    nodes.append(node);
            }
            return;
        case ParentAxis:
            if (context.isAttributeNode()) {
                Element* node = static_cast<Attr&>(context).ownerElement();
                if (node && nodeMatches(*node, ParentAxis, m_nodeTest))
                    nodes.append(node);
            } else {
                ContainerNode* node = context.parentNode();
                if (node && nodeMatches(*node, ParentAxis, m_nodeTest))
                    nodes.append(node);
            }
            return;
        case AncestorAxis: {
            Node* node = &context;
            if (context.isAttributeNode()) {
                node = static_cast<Attr&>(context).ownerElement();
                if (!node)
                    return;
                if (nodeMatches(*node, AncestorAxis, m_nodeTest))
                    nodes.append(node);
            }
            for (node = node->parentNode(); node; node = node->parentNode()) {
                if (nodeMatches(*node, AncestorAxis, m_nodeTest))
                    nodes.append(node);
            }
            nodes.markSorted(false);
            return;
        }
        case FollowingSiblingAxis:
            if (context.isAttributeNode())
                return;
            for (Node* node = context.nextSibling(); node; node = node->nextSibling()) {
                if (nodeMatches(*node, FollowingSiblingAxis, m_nodeTest))
                    nodes.append(node);
            }
            return;
        case PrecedingSiblingAxis:
            if (context.isAttributeNode())
                return;
            for (Node* node = context.previousSibling(); node; node = node->previousSibling()) {
                if (nodeMatches(*node, PrecedingSiblingAxis, m_nodeTest))
                    nodes.append(node);
            }
            nodes.markSorted(false);
            return;
        case FollowingAxis:
            if (context.isAttributeNode()) {
                Node* node = static_cast<Attr&>(context).ownerElement();
                if (!node)
                    return;
                while ((node = NodeTraversal::next(*node))) {
                    if (nodeMatches(*node, FollowingAxis, m_nodeTest))
                        nodes.append(node);
                }
            } else {
                for (Node* parent = &context; !isRootDomNode(parent); parent = parent->parentNode()) {
                    for (Node* node = parent->nextSibling(); node; node = node->nextSibling()) {
                        if (nodeMatches(*node, FollowingAxis, m_nodeTest))
                            nodes.append(node);
                        for (Node* child = node->firstChild(); child; child = NodeTraversal::next(*child, node)) {
                            if (nodeMatches(*child, FollowingAxis, m_nodeTest))
                                nodes.append(child);
                        }
                    }
                }
            }
            return;
        case PrecedingAxis: {
            Node* node;
            if (context.isAttributeNode()) {
                node = static_cast<Attr&>(context).ownerElement();
                if (!node)
                    return;
            } else
                node = &context;
            while (ContainerNode* parent = node->parentNode()) {
                for (node = NodeTraversal::previous(*node); node != parent; node = NodeTraversal::previous(*node)) {
                    if (nodeMatches(*node, PrecedingAxis, m_nodeTest))
                        nodes.append(node);
                }
                node = parent;
            }
            nodes.markSorted(false);
            return;
        }
        case AttributeAxis: {
            if (!is<Element>(context))
                return;

            Element& contextElement = downcast<Element>(context);

            // Avoid lazily creating attribute nodes for attributes that we do not need anyway.
            if (m_nodeTest.m_kind == NodeTest::NameTest && m_nodeTest.m_data != starAtom()) {
                auto attr = contextElement.getAttributeNodeNS(m_nodeTest.m_namespaceURI, m_nodeTest.m_data);
                if (attr && attr->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis.
                    if (nodeMatches(*attr, AttributeAxis, m_nodeTest)) // Still need to check merged predicates.
                        nodes.append(WTFMove(attr));
                }
                return;
            }
            
            if (!contextElement.hasAttributes())
                return;

            for (const Attribute& attribute : contextElement.attributesIterator()) {
                auto attr = contextElement.ensureAttr(attribute.name());
                if (nodeMatches(attr.get(), AttributeAxis, m_nodeTest))
                    nodes.append(WTFMove(attr));
            }
            return;
        }
        case NamespaceAxis:
            // XPath namespace nodes are not implemented yet.
            return;
        case SelfAxis:
            if (nodeMatches(context, SelfAxis, m_nodeTest))
                nodes.append(&context);
            return;
        case DescendantOrSelfAxis:
            if (nodeMatches(context, DescendantOrSelfAxis, m_nodeTest))
                nodes.append(&context);
            if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;
            for (Node* node = context.firstChild(); node; node = NodeTraversal::next(*node, &context)) {
                if (nodeMatches(*node, DescendantOrSelfAxis, m_nodeTest))
                    nodes.append(node);
            }
            return;
        case AncestorOrSelfAxis: {
            if (nodeMatches(context, AncestorOrSelfAxis, m_nodeTest))
                nodes.append(&context);
            Node* node = &context;
            if (context.isAttributeNode()) {
                node = static_cast<Attr&>(context).ownerElement();
                if (!node)
                    return;
                if (nodeMatches(*node, AncestorOrSelfAxis, m_nodeTest))
                    nodes.append(node);
            }
            for (node = node->parentNode(); node; node = node->parentNode()) {
                if (nodeMatches(*node, AncestorOrSelfAxis, m_nodeTest))
                    nodes.append(node);
            }
            nodes.markSorted(false);
            return;
        }
    }
    ASSERT_NOT_REACHED();
}

}
}
