/*
 * 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.
 */
#if !defined(XALAN_XSLTENGINEIMPL_HEADER_GUARD)
#define XALAN_XSLTENGINEIMPL_HEADER_GUARD



// Base include file.  Must be first.
#include "XSLTDefinitions.hpp"



// Base class
#include "XSLTProcessor.hpp"




// Standard library headers
#include <cassert>



#include <xalanc/XalanDOM/XalanDOMString.hpp>



#if defined(XALAN_AUTO_PTR_REQUIRES_DEFINITION)
#include <xalanc/XPath/XPathProcessor.hpp>
#endif



#include <xalanc/Include/XalanMemMgrAutoPtr.hpp>
#include <xalanc/Include/XalanMap.hpp>



#include <xalanc/PlatformSupport/AttributeListImpl.hpp>
#include <xalanc/PlatformSupport/DOMStringHelper.hpp>
#include <xalanc/PlatformSupport/PrefixResolver.hpp>



#include <xalanc/DOMSupport/XalanNamespacesStack.hpp>



#include <xalanc/XPath/Function.hpp>



#include <xalanc/XPath/XPathConstructionContextDefault.hpp>



#include "OutputContextStack.hpp"
#include "ProblemListenerDefault.hpp"
#include "ResultNamespacesStack.hpp"
#include "StylesheetExecutionContext.hpp"
#include "XSLTProcessorException.hpp"
#include "XalanParamHolder.hpp"



XALAN_DECLARE_XERCES_CLASS(InputSource)
XALAN_DECLARE_XERCES_CLASS(DocumentHandler)



XALAN_CPP_NAMESPACE_BEGIN



typedef XERCES_CPP_NAMESPACE_QUALIFIER InputSource      InputSourceType;
typedef XERCES_CPP_NAMESPACE_QUALIFIER DocumentHandler  DocumentHandlerType;

XALAN_USING_XERCES(InputSource)
XALAN_USING_XERCES(DocumentHandler)



// Forward declarations...
class DOMSupport;
class GenerateEvent;
class PrintWriter;
class StylesheetConstructionContext;
class StylesheetRoot;
class XalanAttr;
class XalanSourceTreeDocument;
class XalanText;
class XMLParserLiaison;
class XObject;
class XPathEnvSupport;
class XPathFactory;
class XPathProcessor;
class XSLTResultTarget;



/**
 * It's the responsibility of the XSLTEngineImpl class, collaborating with the
 * XML parser liaison, the DOM, and the XPath engine, to transform a source
 * tree of nodes into a result tree according to instructions and templates
 * specified by a stylesheet tree.  The process method is the primary
 * public entry points.
 * 
 * 
 * If you reuse the processor instance, you should call reset() between calls.
 *
 */

class XALAN_XSLT_EXPORT XSLTEngineImpl : public XSLTProcessor, public PrefixResolver
{
public:

    struct LessXalanDOMStringPointers
    {
        bool
        operator()(
                const XalanDOMString*   theLHS,
                const XalanDOMString*   theRHS) const
        {
            if (theLHS == 0 && theRHS != 0)
            {
                return true;
            }
            else if (theRHS == 0)
            {
                return false;
            }
            else
            {
                return theLHS->compare(*theRHS) < 0 ? true : false;
            }
        }
    };

    typedef XalanVector<const Locator*>         LocatorStack;
    typedef XalanVector<TraceListener*>         TraceListenerVectorType;
    typedef XalanVector<const XalanDOMString*>  XalanDOMStringPointerVectorType;

    typedef XalanVector<bool>                           BoolVectorType;

    struct FindStringPointerFunctor
    {
        FindStringPointerFunctor(const XalanDOMString&  theString) :
            m_string(theString)
        {
        }

        bool
        operator()(const XalanDOMString*    theString) const
        {
            assert(theString != 0);

            return *theString == m_string;
        }

    private:

        const XalanDOMString&   m_string;
    };

    typedef XalanMemMgrAutoPtr<XPathProcessor>              XPathProcessorPtrType;
    typedef Function::XObjectArgVectorType                  XObjectArgVectorType;
    typedef StylesheetExecutionContext::ParamVectorType     ParamVectorType;
    typedef XPathConstructionContext::GetCachedString       CCGetCachedString;
    typedef XPathExecutionContext::GetCachedString          ECGetCachedString;

    typedef XalanMap<XalanDOMString, XalanParamHolder>      ParamMapType;

    // Public members
    //---------------------------------------------------------------------

    /**
     * Construct an XSL processor that can call back to a XML processor, so it
     * can handle included files, and the like. You must create a new instance
     * of the XSLTEngineImpl class each time you run a transformation.
     *
     * @param XMLParserLiaison liaison to an object that can help with a
     *                         specific parser implementation
     * @param xpathEnvSupport  An XPathEnvSupport instance
     * @param domSupport       A DOMSupport instance for the DOM being used
     * @param xobjectFactory   object responsible for XObject objects
     * @param xpathFactory     object responsible for XPath objects
     */
    XSLTEngineImpl(
            MemoryManager&  theManager,
            XMLParserLiaison&   parserLiaison,
            XPathEnvSupport&    xpathEnvSupport,
            DOMSupport&         domSupport,
            XObjectFactory&     xobjectFactory,
            XPathFactory&       xpathFactory);

    virtual
    ~XSLTEngineImpl();

    MemoryManager&
    getMemoryManager() const
    {
        return m_xpathConstructionContext.getMemoryManager();
    }

    MemoryManager&
    getMemoryManager()
    {
        return m_xpathConstructionContext.getMemoryManager();
    }

    /**
     * Perform initialization of statics -- must be called before any
     * processing occurs.  See class XSLTInit.
     */
    static void
    initialize(MemoryManager&   theManager);

    /**
     * Perform termination of statics.  See class XSLTInit.
     */
    static void
    terminate();

    // These methods are inherited from XSLTProcessor ...

    virtual void
    problem(
            eSource                 source,
            eClassification         classification,
            const XalanDOMString&   msg,
            const Locator*          locator,
            const XalanNode*        sourceNode);

    virtual void
    problem(
            eSource                 source,
            eClassification         classification,
            const XalanDOMString&   msg,
            const XalanNode*        sourceNode);

    virtual void
    process(
            const XSLTInputSource&          inputSource, 
            const XSLTInputSource&          stylesheetSource,
            XSLTResultTarget&               outputTarget,
            StylesheetConstructionContext&  constructionContext,
            StylesheetExecutionContext&     executionContext);

    virtual void
    process(
            const XSLTInputSource&          inputSource,
            XSLTResultTarget&               outputTarget,
            StylesheetExecutionContext&     executionContext);

    virtual StylesheetRoot*
    processStylesheet(
            const XSLTInputSource&          stylesheetSource,
            StylesheetConstructionContext&  constructionContext);

    virtual StylesheetRoot*
    processStylesheet(
            const XalanDOMString&           xsldocURLString,
            StylesheetConstructionContext&  constructionContext);

    virtual XalanNode*
    getSourceTreeFromInput(const XSLTInputSource&   inputSource);

    virtual void
    resolveTopLevelParams(StylesheetExecutionContext&   executionContext);

    virtual XMLParserLiaison&
    getXMLParserLiaison() const;

    virtual void
    getUniqueNamespaceValue(XalanDOMString&     theValue);

    virtual void
    setStylesheetParam( 
                    const XalanDOMString&   key,
                    const XalanDOMString&   expression);

    virtual void
    setStylesheetParam(
            const XalanDOMString&   key,
            XObjectPtr              value);

    virtual void
    clearStylesheetParams();

    virtual FormatterListener*
    getFormatterListener() const;

    virtual void
    setFormatterListener(FormatterListener* flistener);

    // Trace-related functions...

    virtual size_type
    getTraceListeners() const;

    virtual void
    addTraceListener(TraceListener*     tl);

    virtual void
    removeTraceListener(TraceListener*  tl);

    virtual void
    fireGenerateEvent(const GenerateEvent&  ge);
      
    virtual void
    fireTraceEvent(const TracerEvent&   te);

    virtual void
    fireSelectEvent(const SelectionEvent&   se);

    virtual bool
    getTraceSelects() const;

    virtual void
    setTraceSelects(bool    b);

    void
    traceSelect(
            StylesheetExecutionContext&     executionContext,
            const ElemTemplateElement&      theTemplate,
            const NodeRefListBase&          nl,
            const XPath*                    xpath) const;

    virtual void
    setQuietConflictWarnings(bool   b);

    virtual void
    setDiagnosticsOutput(PrintWriter*   pw);


    // Inherited from PrefixResolver...

    /**
     * Retrieve a namespace corresponding to a prefix.  This assumes that 
     * the PrevixResolver hold's its own namespace context, or is a namespace
     * context itself.
     *
     * @param prefix Prefix to resolve
     * @return namespace that prefix resolves to, or null if prefix is not found
     */
    virtual const XalanDOMString*
    getNamespaceForPrefix(const XalanDOMString&     prefix) const;

    /**
     * Retrieve the base URI for the resolver.
     * 
     * @return URI string
     */
    virtual const XalanDOMString&
    getURI() const;

    /**
     * Read in the XML file, either producing a Document or calling SAX events,
     * and register the document in a table.  If the document has already been
     * read in, it will not be reparsed.
     *
     * @param urlString location of the XML
     * @param docHandler pointer to SAX event handler
     * @param docToRegister if using a SAX event handler, the object to register in the source docs table. 
     * @return document object, which represents the parsed XML
     * @exception SAXException
     */
    XalanDocument*
    parseXML(
            const XalanDOMString&   urlString,
            DocumentHandler*        docHandler,
            XalanDocument*          docToRegister,
            ErrorHandler*           theErrorHandler = 0);

    /**
     * Read in the XML file, either producing a Document or calling SAX events,
     * and register the document in a table.  If the document has already been
     * read in, it will not be reparsed.
     *
     * @param inputSource location of the XML
     * @param docHandler pointer to SAX event handler
     * @param docToRegister if using a SAX event handler, the object to register in the source docs table. 
     * @return document object, which represents the parsed XML
     * @exception SAXException
     */
    XalanDocument*
    parseXML(
            const InputSource&  inputSource,
            DocumentHandler*    docHandler,
            XalanDocument*      docToRegister,
            ErrorHandler*       theErrorHandler = 0);

    /**
     * Reset the state of the XSL processor by reading in a new XSL stylesheet
     * from a processing instruction.
     *
     * @param xslURLString        valid URI to an XSL stylesheet
     * @param fragBase            base of tree if URI represents document
     *                            fragment
     * @param xmlBaseIdent        base identifier for stylesheet URI
     * @param isRoot              true if stylesheet is root of tree
     * @param constructionContext context for construction of object
     * @return pointer to stylesheet
     */
    Stylesheet*
    getStylesheetFromPIURL(
            const XalanDOMString&           xslURLString,
            XalanNode&                      fragBase,
            const XalanDOMString&           xmlBaseIdent,
            bool                            isRoot,
            StylesheetConstructionContext&  constructionContext);

    /**
     * Flush the pending element.
     */
    void
    flushPending();

    /**
     * Add a namespace declaration to the namespace stack
     *
     * @param prefix       namespace prefix
     * @param namespaceVal value of namespace
     */
    void
    addResultNamespaceDecl(
            const XalanDOMString&   prefix, 
            const XalanDOMString&   namespaceVal)
    {
        addResultNamespaceDecl(
            prefix,
            namespaceVal.c_str(),
            namespaceVal.length());
    }

    /**
     * Add a namespace declaration to the namespace stack
     *
     * @param prefix namespace prefix
     * @param namespaceVal value of namespace
     * @param len length of namespace
     */
    void
    addResultNamespaceDecl(
            const XalanDOMString&   prefix, 
            const XalanDOMChar*     namespaceVal,
            size_type               len)
    {
        m_resultNamespacesStack.addDeclaration(
            prefix,
            namespaceVal,
            len);
    }

    /**
     * Add attribute to attribute list, and if it is a namespace, add it to the
     * namespaces stack.
     *
     * @param attList attribute list added to
     * @param aname   name of attribute
     * @param value   value of attribute
     * @param fromCopy true if the attribute is being copied from the source tree
     * @param locator The Locator for reporting errors.
     */
    void
    addResultAttribute(
            AttributeListImpl&      attList,
            const XalanDOMString&   aname,
            const XalanDOMString&   value,
            bool                    fromCopy = false,
            const Locator*          locator = 0)
    {
        addResultAttribute(
            attList,
            aname,
            value.c_str(),
            fromCopy,
            locator);
    }

    /**
     * Add attribute to attribute list, and if it is a namespace, add it to the
     * namespaces stack.
     *
     * @param attList attribute list added to
     * @param aname name of attribute
     * @param value value of attribute
     * @param fromCopy true if the attribute is being copied from the source tree
     * @param locator The Locator for reporting errors.
     */
    void
    addResultAttribute(
            AttributeListImpl&      attList,
            const XalanDOMString&   aname,
            const XalanDOMChar*     value,
            bool                    fromCopy = false,
            const Locator*          locator = 0)
    {
        addResultAttribute(
            attList,
            aname,
            value,
            length(value),
            fromCopy,
            locator);
    }

    /**
     * Add attribute to attribute list, and if it is a namespace, add it to the
     * namespaces stack.
     *
     * @param attList attribute list added to
     * @param aname name of attribute
     * @param value value of attribute
     * @param theLength The length of the value
     * @param fromCopy true if the attribute is being copied from the source tree
     * @param locator The Locator for reporting errors.
     */
    void
    addResultAttribute(
            AttributeListImpl&      attList,
            const XalanDOMString&   aname,
            const XalanDOMChar*     value,
            size_type               theLength,
            bool                    fromCopy = false,
            const Locator*          locator = 0);

    /**
     * Add attribute to pending attributes list, and if it is a namespace, add
     * it to the namespaces stack.
     *
     * @param aname name of attribute
     * @param value value of attribute
     * @param fromCopy true if the attribute is being copied from the source tree
     * @param locator The Locator for reporting errors.
     */
    void
    addResultAttribute(
            const XalanDOMString&       aname,
            const XalanDOMChar*         value,
            bool                        fromCopy = false,
            const Locator*              locator = 0)
    {
        assert(m_outputContextStack.empty() == false);

        addResultAttribute(
                getPendingAttributesImpl(),
                aname,
                value,
                fromCopy,
                locator);
    }

    /**
     * Add attribute to pending attributes list, and if it is a namespace, add
     * it to the namespaces stack.
     *
     * @param aname   name of attribute
     * @param value   value of attribute
     * @param fromCopy true if the attribute is being copied from the source tree
     * @param locator The Locator for reporting errors.
     */
    void
    addResultAttribute(
            const XalanDOMString&   aname,
            const XalanDOMString&   value,
            bool                    fromCopy = false,
            const Locator*          locator = 0)
    {
        assert(m_outputContextStack.empty() == false);

        addResultAttribute(
                getPendingAttributesImpl(),
                aname,
                value,
                fromCopy,
                locator);
    }

    /**
     * Report an error copying a duplicate namespace node.
     *
     * @param theName The name of the node.
     */
    void
    reportDuplicateNamespaceNodeError(
            const XalanDOMString&   theName,
            const Locator*          locator);

    void
    setDocumentLocator(const Locator*   locator);

    void
    startDocument();

    void
    endDocument();
    
    void
    startElement(
            const XalanDOMChar*     name,
            AttributeListType&      atts);

    void
    endElement(const XalanDOMChar*  name);

    void
    characters (
            const XalanDOMChar*     ch,
            size_type               length);

    void
    ignorableWhitespace(
            const XalanDOMChar*     ch,
            size_type               length);

    void
    processingInstruction(
            const XalanDOMChar*     target,
            const XalanDOMChar*     data);

    void
    resetDocument();

    /**
     * Receive notification of character data.
     *
     * @param ch     pointer to characters from the XML document
     * @param start  startng offset in 'ch' array
     * @param length number of characters to read from the array 
     */
    void
    characters(
            const XalanDOMChar*     ch,
            size_type               start,
            size_type               length);

    /**
     * Send character data from the node to the result tree.
     *
     * @param node The node to send.
     */
    void
    characters(const XalanNode&     node);

    /**
     * Send character data from an XObject to the result tree.
     *
     * @param node The xobject to send.
     */
    void
    characters(const XObjectPtr&    xobject);

    /**
     * Receive notification of the beginning of an element with an empty
     * attribute list
     *
     * @param name element type name
     */
    void
    startElement(const XalanDOMChar*    name);

    /**
     * Receive notification of character data. If available, when the
     * disable-output-escaping attribute is used, output raw text without
     * escaping.
     *
     * @param ch pointer to characters from the XML document
     * @param start start position in the array
     * @param length number of characters to read from the array
     */
    void
    charactersRaw(
            const XalanDOMChar*     ch,
            size_type               start,
            size_type               length);

    /**
     * Send raw character data from the node to the result tree.
     *
     * @param node The node to send.
     */
    void
    charactersRaw(const XalanNode&  node);

    /**
     * Send raw character data from an XObject to the result tree.
     *
     * @param node The xobject to send.
     */
    void
    charactersRaw(const XObjectPtr&     xobject);

    /**
     * Called when a Comment is to be constructed.
     *
     * @param   data    pointer to comment data
     */
    void
    comment(const XalanDOMChar*     data);

    /**
     * Receive notification of a entityReference.
     *
     * @param data pointer to characters from the XML document
     * @exception SAXException
     */
    void
    entityReference(const XalanDOMChar*     data);

    /**
     * Receive notification of cdata.
     *
     * @param ch     pointer to characters from the XML document
     * @param start  start position in the array
     * @param length number of characters to read from the array
     */
    void
    cdata(
            const XalanDOMChar*     ch,
            size_type               start,
            size_type               length);

    /**
     * Clone a node to the result tree
     *
     * @param node      node to clone
     * @param cloneTextNodesOnly    if true, only text nodes will be cloned
     * @param locator   the Locator for the event, if any.
     */
    void
    cloneToResultTree(
            const XalanNode&    node,
            bool                cloneTextNodesOnly,
            const Locator*      locator);

    /**
     * Clone a node to the result tree
     *
     * @param node                  node to clone
     * @param nodeType              the type of the node
     * @param overrideStrip         false if white space stripping should be done
     * @param shouldCloneAttributes true if attributes should be cloned
     * @param cloneTextNodesOnly    if true, only text nodes will be cloned
     * @param locator               the Locator for the event, if any.
     */
    void
    cloneToResultTree(
            const XalanNode&        node,
            XalanNode::NodeType     nodeType,
            bool                    overrideStrip,
            bool                    shouldCloneAttributes,
            bool                    cloneTextNodesOnly,
            const Locator*          locator);

   /**
    * Output an object to the result tree by doing the right conversions.
    *
    * @param value the XObject to output
    * @param outputTextNodesOnly if true, only text nodes will be copied
    * @param locator                the Locator for the event, if any.
    */
    void
    outputToResultTree(
            const XObject&      value,
            bool                outputTextNodesOnly,
            const Locator*      locator);

    /**
     * Given a result tree fragment, walk the tree and output it to the result
     * stream.
     *
     * @param theTree result tree fragment
     * @param outputTextNodesOnly if true, only text nodes will be copied
     * @param locator the Locator for the event, if any.
     */
    void
    outputResultTreeFragment(
            const XObject&      theTree,
            bool                outputTextNodesOnly,
            const Locator*      locator)
    {
        outputResultTreeFragment(
            theTree.rtree(),
            outputTextNodesOnly,
            locator);
    }

    /**
     * Given a result tree fragment, walk the tree and output it to the result
     * stream.
     *
     * @param theTree result tree fragment
     * @param outputTextNodesOnly if true, only text nodes will be copied
     * @param locator the Locator for the event, if any.
     */
    void
    outputResultTreeFragment(
            const XalanDocumentFragment&    theTree,
            bool                            outputTextNodesOnly,
            const Locator*                  locator);

    /**
     * Retrieve the root stylesheet.
     * 
     * @return pointer to root stylesheet
     */
    virtual const StylesheetRoot*
    getStylesheetRoot() const;

    /**
     * Set the root stylesheet.
     * 
     * @param theStylesheet pointer to new root stylesheet
     */
    virtual void
    setStylesheetRoot(const StylesheetRoot*     theStylesheet);

    /**
     * Set the execution context.
     * 
     * @param theExecutionContext pointer to new execution context.
     */
    virtual void
    setExecutionContext(StylesheetExecutionContext*     theExecutionContext);

    /**
     * Retrieve the URI for the current XSL namespace, for example,
     * "http://www.w3.org/1999/XSL/Transform"
     * 
     * @return URI string
     */
    static const XalanDOMString&
    getXSLNameSpaceURL()
    {
        return s_XSLNameSpaceURL;
    }

    /**
     * Special Xalan namespace for built-in extensions.
     *
     * @return Xalan namespace for extensions
     */
    static const XalanDOMString&
    getXalanXSLNameSpaceURL()
    {
        return s_XalanNamespaceURL;
    }

    /**
     * Whether to warn about pattern match conflicts.
     *
     * @return true to not warn about pattern match conflicts
     */
    bool
    getQuietConflictWarnings() const
    {
        return m_quietConflictWarnings;
    }

    /**
     * Retrieve the result namespace corresponding to a prefix.
     * 
     * @param prefix prefix for namespace
     * @return string for namespace URI
     */
    const XalanDOMString*
    getResultNamespaceForPrefix(const XalanDOMString&   prefix) const;

    /**
     * Retrieve the result prefix corresponding to a namespace.
     * 
     * @param theNamespace namespace for prefix
     * @return string for namespace prefix
     */
    const XalanDOMString*
    getResultPrefixForNamespace(const XalanDOMString&   theNamespace) const;

    /**
     * Determine whether or not a prefix is in use on the pending element or
     * the pending attributes.
     * 
     * @param thePrefix prefix for namespace
     *
     * @return true if the prefix is in use, false if not.
     */
    bool
    isPendingResultPrefix(const XalanDOMString&     thePrefix) const;

    /**
     * Evaluate an xpath string and return the result as a numberic score.
     *
     * @param str              string to evaluate
     * @param context          context node
     * @param executionContext current execution context
     * @return score number, higher representing better match
     */
    double
    evalMatchPatternStr(
            const XalanDOMString&   str,
            XalanNode*              context,
            XPathExecutionContext&  executionContext);

    /**
     * Create and initialize an xpath and return it.
     *
     * @param str      string for XPath
     * @param resolver resolver for namespace resolution
     * @return pointer to XPath created
     */
    const XPath*
    createMatchPattern(
            const XalanDOMString&   str,
            const PrefixResolver&   resolver);

    /**
     * Return the xpath created by createXPath() or
     * createMatchPattern().
     *
     * @param xpath    The XPath to return.
     */
    void
    returnXPath(const XPath*    xpath);

    /**
     * Copy XMLNS: attributes in if not already in scope.
     *
     * @param src                 source node
     */
    void
    copyNamespaceAttributes(const XalanNode&    src);

    /**
     * Evaluate an xpath string and return the result.
     *
     * @param str              string to evaluate
     * @param executionContext current execution context
     * @return pointer to XObject result
     */
    const XObjectPtr
    evalXPathStr(
            const XalanDOMString&   str,
            XPathExecutionContext&  executionContext);

    /**
     * Evaluate an xpath string and return the result.
     * 
     * @param str              string to evaluate
     * @param contextNode      context node
     * @param prefixResolver prefix resolver to use
     * @param executionContext current execution context
     * @return pointer to XObject result
     */
    const XObjectPtr
    evalXPathStr(
            const XalanDOMString&   str,
            XalanNode*              contextNode,
            const PrefixResolver&   prefixResolver,
            XPathExecutionContext&  executionContext);

    /**
     * Evaluate an xpath string and return the result.
     * 
     * @param str              string to evaluate
     * @param contextNode      context node
     * @param prefixResolver prefix resolver to use
     * @param executionContext current execution context
     * @return pointer to XObject result
     */
    const XObjectPtr
    evalXPathStr(
            const XalanDOMString&   str,
            XalanNode*              contextNode,
            const XalanElement&     prefixResolver,
            XPathExecutionContext&  executionContext);

    /**
     * Copy an attribute to an AttributeListImpl.
     *
     * @param attrName The name of the attribute
     * @param attrValue The value of the attribute
     * @param attrList The attribute list added to
     */
    void
    copyAttributeToTarget(
            const XalanDOMString&   attrName,
            const XalanDOMString&   attrValue,
            AttributeListImpl&      attrList);

    /**
     * Get the factory for making xpaths.
     *
     * @return XPath factory object
     */
    XPathFactory&
    getXPathFactory()
    {
        return m_xpathFactory;
    }

    /**
     * Get the XPath processor object.
     *
     * @return XPathProcessor interface being used
     */
    XPathProcessor&
    getXPathProcessor()
    {
        return *m_xpathProcessor.get();
    }

    /**
     * Reset the state.  This needs to be called after a process() call 
     * is invoked, if the processor is to be used again.
     */
    virtual void
    reset();

    /**
     * Retrieve the XPath environment support object
     *
     * @return XPath environment support object
     */
    XPathEnvSupport&
    getXPathEnvSupport()
    {
        return m_xpathEnvSupport;
    }

    /**
     * Set the problem listener property. The XSL class can have a single
     * listener that can be informed of errors and warnings, and can normally
     * control if an exception is thrown or not (or the problem listeners can
     * throw their own RuntimeExceptions).
     *
     * @param l pointer to ProblemListener interface
     */
    void
    setProblemListener(ProblemListener*     l)
    {
        m_problemListener = l;
    }

    /**
     * Get the problem listener property. The XSL class can have a single
     * listener that can be informed of errors and warnings, and can normally
     * control if an exception is thrown or not (or the problem listeners can
     * throw their own RuntimeExceptions).
     *
     * @return pointer to ProblemListener interface
     */
    ProblemListener*
    getProblemListener() const
    {
        return m_problemListener;
    }

    /*
     * Push a new output context using the provided FormatterListener.
     *
     * @param A pointer to the FormatterListener instance for the new context.
     */
    void
    pushOutputContext(FormatterListener*    theListener)
    {
        m_outputContextStack.pushContext(theListener);
    }

    /*
     * Pop the current output context.
     */
    void
    popOutputContext()
    {
        m_outputContextStack.popContext();
    }

    /*
     * See if there is a pending start document event waiting.
     * @return true if there is a start document event waiting.
     */
    bool
    getHasPendingStartDocument() const
    {
        return getHasPendingStartDocumentImpl();
    }

    /*
     * Set the pending start document event state.
     * @param the new value
     */
    void
    setHasPendingStartDocument(bool b)
    {
        setHasPendingStartDocumentImpl(b);
    }

    /*
     * See if a pending start document event must be flushed.
     * @return true if the event must be flushed.
     */
    bool
    getMustFlushPendingStartDocument() const
    {
        return getMustFlushPendingStartDocumentImpl();
    }

    /*
     * Set the pending start document event flush state.
     * @param the new value
     */
    void
    setMustFlushPendingStartDocument(bool   b)
    {
        setMustFlushPendingStartDocumentImpl(b);
    }

    /**
     * Get the list of attributes yet to be processed
     * 
     * @return attribute list
     */
    const AttributeListType&
    getPendingAttributes() const
    {
        return getPendingAttributesImpl();
    }

    /**
     * Set the list of attributes yet to be processed
     * 
     * @param pendingAttributes The attribute list
     */
    void
    setPendingAttributes(const AttributeListType&   pendingAttributes)
    {
        getPendingAttributesImpl() = pendingAttributes;
    }

    /**
     * Replace the contents of a pending attribute.
     * 
     * @param theName           name of attribute
     * @param theNewType        type of attribute
     * @param theNewValue       new value of attribute
     */
    void
    replacePendingAttribute(
            const XalanDOMChar*     theName,
            const XalanDOMChar*     theNewType,
            const XalanDOMChar*     theNewValue)
    {
        // Remove the old attribute, then add the new one.  AttributeListImpl::addAttribute()
        // does this for us.
        getPendingAttributesImpl().addAttribute(theName, theNewType, theNewValue);
    }

    bool
    isElementPending() const
    {
        return !getPendingElementNameImpl().empty();
    }

    /**
     * Retrieve name of the pending element currently being processed.
     * 
     * @return element name
     */
    const XalanDOMString&
    getPendingElementName() const
    {
        return getPendingElementNameImpl();
    }

    /**
     * Changes the currently pending element name.
     * 
     * @param elementName new name of element
     */
    void
    setPendingElementName(const XalanDOMString&     elementName)
    {
        setPendingElementNameImpl(elementName);
    }

    void
    setPendingElementName(const XalanDOMChar*   elementName)
    {
        setPendingElementNameImpl(elementName);
    }

    /**
     * Get the locator from the top of the locator stack.
     *
     * @return A pointer to the Locator, or 0 if there is nothing on the stack.
     */
    const Locator*
    getLocatorFromStack() const
    {
        return m_stylesheetLocatorStack.empty() == true ? 0 : m_stylesheetLocatorStack.back();
    }

    /**
     * Push a locator on to the locator stack.
     *
     * @param A pointer to the Locator to push.
     */
    void
    pushLocatorOnStack(const Locator*   locator)
    {
        m_stylesheetLocatorStack.push_back(locator);
    }

    /**
     * Pop the locator from the top of the locator stack.
     */
    void
    popLocatorStack()
    {
        if (m_stylesheetLocatorStack.empty() == false)
        {
            m_stylesheetLocatorStack.pop_back();
        }
    }

protected:

    /**
     * Get the list of attributes yet to be processed
     * 
     * @return attribute list
     */
    const AttributeListImpl&
    getPendingAttributesImpl() const
    {
        return m_outputContextStack.getPendingAttributes();
    }

    /**
     * Get the list of attributes yet to be processed
     * 
     * @return attribute list
     */
    AttributeListImpl&
    getPendingAttributesImpl()
    {
        return m_outputContextStack.getPendingAttributes();
    }

    /**
     * Set the list of attributes yet to be processed
     * 
     * @param pendingAttributes The attribute list
     */
    void
    setPendingAttributesImpl(const AttributeListType&   pendingAttributes)
    {
        getPendingAttributesImpl() = pendingAttributes;
    }

    /**
     * Retrieve name of the pending element currently being processed.
     * 
     * @return element name
     */
    const XalanDOMString&
    getPendingElementNameImpl() const
    {
        return m_outputContextStack.getPendingElementName();
    }

    /**
     * Retrieve name of the pending element currently being processed.
     * 
     * @return element name
     */
    XalanDOMString&
    getPendingElementNameImpl()
    {
        return m_outputContextStack.getPendingElementName();
    }

    /**
     * Changes the currently pending element name.
     * 
     * @param elementName new name of element
     */
    void
    setPendingElementNameImpl(const XalanDOMString&     elementName)
    {
        m_outputContextStack.getPendingElementName() = elementName;
    }

    /**
     * Changes the currently pending element name.
     * 
     * @param elementName new name of element
     */
    void
    setPendingElementNameImpl(const XalanDOMChar*   elementName)
    {
        assert(elementName != 0);

        m_outputContextStack.getPendingElementName() = elementName;
    }

    /*
     * See if there is a pending start document event waiting.
     * @return true if there is a start document event waiting.
     */
    bool
    getHasPendingStartDocumentImpl() const
    {
        return m_outputContextStack.getHasPendingStartDocument();
    }

    /*
     * Set the pending start document event state.
     * @param the new value
     */
    void
    setHasPendingStartDocumentImpl(bool     b)
    {
        m_outputContextStack.getHasPendingStartDocument() = b;
    }

    /*
     * See if a pending start document event must be flushed.
     * @return true if the event must be flushed.
     */
    bool
    getMustFlushPendingStartDocumentImpl() const
    {
        return m_outputContextStack.getMustFlushPendingStartDocument();
    }

    /*
     * Set the pending start document event flush state.
     * @param the new value
     */
    void
    setMustFlushPendingStartDocumentImpl(bool   b)
    {
        m_outputContextStack.getMustFlushPendingStartDocument() = b;
    }

    FormatterListener*
    getFormatterListenerImpl() const
    {
        return m_outputContextStack.getFormatterListener();
    }

    void
    setFormatterListenerImpl(FormatterListener*     flistener)
    {
        m_outputContextStack.getFormatterListener() = flistener;
    }

    /**
     * The namespace that the result tree conforms to.  A null value 
     * indicates that result-ns is not used and there is no checking. 
     * A empty string indicates that the result tree conforms to the 
     * default namespace.
     */
    XalanDOMString  m_resultNameSpacePrefix;

    /**
     * The URL that belongs to the result namespace.
     */
    XalanDOMString  m_resultNameSpaceURL;


    /**
     * Copy the attributes from the XSL element to the created 
     * output element.
     */
    void
    copyAttributesToAttList(
            const XalanNode&    node,
            AttributeListImpl&  attList);

    // Factory for creating xpaths.
    XPathFactory&           m_xpathFactory;

    // Factory for creating xobjects
    XObjectFactory&         m_xobjectFactory;

    // The query/pattern-matcher object.
    const XPathProcessorPtrType     m_xpathProcessor;

    /**
     * Stack of Booleans to keep track of if we should be outputting 
     * cdata instead of escaped text.
     */
    BoolVectorType  m_cdataStack;

private:

    /**
     * Issue a warning that only text nodes can be copied.
     *
     * @param sourceNode node in source where error occurred
     * @param locator The Locator to use, if any.
     */
    void
    warnCopyTextNodesOnly(
            const XalanNode*    sourceNode,
            const Locator*      locator);

    /**
     * Clone a text node to the result tree
     *
     * @param node                  node to clone
     * @param overrideStrip         false if white space stripping should be done
     */
    void
    cloneToResultTree(
            const XalanText&    node,
            bool                overrideStrip);

    /**
     * Determine if any pending attributes is a default
     * namespace.
     */
    bool
    pendingAttributesHasDefaultNS() const; 

    void
    addResultNamespace(
            const XalanDOMString&   thePrefix,
            const XalanDOMString&   theName,
            const XalanNode&        theNode,
            AttributeListImpl&      thePendingAttributes,
            bool                    fOnlyIfPrefixNotPresent);

    void
    addResultNamespace(
            const XalanNode&    theNode,
            AttributeListImpl&  thePendingAttributes,
            bool                fOnlyIfPrefixNotPresent = false);

  /**
   * The top of this stack should contain the currently processed
   * stylesheet SAX locator object.
   */
    LocatorStack  m_stylesheetLocatorStack;

    /**
     * The XSL class can have a single listener that can be informed 
     * of errors and warnings, and can normally control if an exception
     * is thrown or not (or the problem listeners can throw their 
     * own RuntimeExceptions).
     */
    ProblemListenerDefault  m_defaultProblemListener;

    ProblemListener*    m_problemListener;

    /**
     * The root of a linked set of stylesheets.
     */
    const StylesheetRoot*               m_stylesheetRoot;

    /**
     * The namespace that we must match as a minimum for XSLT.
     */
    static const XalanDOMString&        s_XSLNameSpaceURL;  //"http://www.w3.org/1999/XSL/Transform"

    /**
     * Special Xalan namespace for built-in extensions.
     */
    static const XalanDOMString&        s_XalanNamespaceURL; // "http://xml.apache.org/xalan"

    /**
     * Prefix to use when generating unique namespaces.
     */
    static const XalanDOMString&        s_uniqueNamespacePrefix;

    /**
     * If this is set to true, selects will be traced
     */
    bool    m_traceSelects;

    /**
     * If this is set to true, do not warn about pattern 
     * match conflicts.
     */
    bool    m_quietConflictWarnings;

    /*
     * A stream to print diagnostics to.
     */
    PrintWriter*    m_diagnosticsPrintWriter;

    /**
     * List of listeners who are interested in tracing what's 
     * being generated.
     */
    TraceListenerVectorType     m_traceListeners;
    
    void
    problem(
            const XalanDOMString&               msg, 
            ProblemListener::eClassification    classification,
            const XalanNode*                    sourceNode,
            const ElemTemplateElement*          styleNode) const;

    void
    problem(
            const XalanDOMString&               msg, 
            ProblemListener::eClassification    classification,
            const Locator&                      locator,
            const XalanNode*                    sourceNode) const;

    void
    problem(
            const XalanDOMString&               msg, 
            ProblemListener::eClassification    classification) const;

  //==========================================================
  // SECTION: Function to do with attribute handling
  //==========================================================

    /**
     * This is used whenever a unique namespace is needed.
     */
    unsigned long       m_uniqueNSValue;

    ParamVectorType     m_topLevelParams;

public:

    /**
     * Reset the vector of top level parameters
     */
    void
    clearTopLevelParams()
    {
        m_topLevelParams.clear();
    }

private:

    bool
    generateCDATASection() const
    {
        if (m_hasCDATASectionElements == false)
        {
            return false;
        }
        else
        {
            assert(m_cdataStack.empty() == false);

            return m_cdataStack.back();
        }
    }

    void
    doFlushPending()
    {
        setMustFlushPendingStartDocument(true);

        flushPending();
    }

    /**
     * Tell if a given element name should output its text 
     * as cdata.
     *
     * @param elementName name of element
     * @return true if it should output as cdata
     */
    bool
    isCDataResultElem(const XalanDOMString&     elementName);

    void
    fireCharacterGenerateEvent(
            const XalanNode&    theNode,
            bool                isCDATA);

    void
    fireCharacterGenerateEvent(
            const XObjectPtr&   theXObject,
            bool                isCDATA);

    void
    fireCharacterGenerateEvent(
            const XalanDOMString&   theString,
            bool                    isCDATA);

    void
    fireCharacterGenerateEvent(
            const XalanDOMChar*     ch,
            size_type               start,
            size_type               length,
            bool                    isCDATA);

    void
    checkDefaultNamespace(
            const XalanDOMString&   theElementName,
            const XalanDOMString&   theElementNamespaceURI);

    void
    error(
            const XalanDOMString&   theMessage,
            const Locator*          theLocator,
            const XalanNode*        theSourceNode);

    void
    warn(
            const XalanDOMString&   theMessage,
            const Locator*          theLocator,
            const XalanNode*        theSourceNode);

    void
    message(
            const XalanDOMString&   theMessage,
            const Locator*          theLocator,
            const XalanNode*        theSourceNode);

    // Data members...
    XMLParserLiaison&   m_parserLiaison;

    XPathEnvSupport&    m_xpathEnvSupport;

    DOMSupport&         m_domSupport;

    /**
     * Current execution context...
     */
    StylesheetExecutionContext*     m_executionContext;

    /*
     * Stack of current output contexts...
     */
    OutputContextStack              m_outputContextStack;

    /*
     * Stack of current result namespaces...
     */
    XalanNamespacesStack            m_resultNamespacesStack;

    /*
     * Dummy AttributeListImpl
     */
    AttributeListImpl                   m_dummyAttributesList;

    XalanDOMString                      m_scratchString;

    XalanDOMStringPointerVectorType     m_attributeNamesVisited;

    bool                                m_hasCDATASectionElements;

    XPathConstructionContextDefault     m_xpathConstructionContext;

    ParamMapType                        m_stylesheetParams;

    static void
    installFunctions(MemoryManager& theManager);

    static void
    uninstallFunctions();


    static const XalanDOMString     s_emptyString;

    static const XalanDOMString&    s_stylesheetNodeName;
    static const XalanDOMString&    s_typeString;
    static const XalanDOMString&    s_hrefString;
    static const XalanDOMString&    s_piTokenizerString;
    static const XalanDOMString&    s_typeValueString1;
    static const XalanDOMString&    s_typeValueString2;
    static const XalanDOMString&    s_typeValueString3;
    static const XalanDOMString&    s_typeValueString4;

    // Not implemented...
    XSLTEngineImpl(const XSLTEngineImpl&);

    XSLTEngineImpl&
    operator=(const XSLTEngineImpl&);

    bool
    operator==(const XSLTEngineImpl&) const;
};



XALAN_CPP_NAMESPACE_END



#endif  // XALAN_XSLTENGINEIMPL_HEADER_GUARD
