/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999-2004 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:  
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written 
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * @author <a href="mailto:david_n_bertoni@lotus.com">David N. Bertoni</a>
 */
#if !defined(XPATHEXECUTIONCONTEXT_HEADER_GUARD_1357924680)
#define XPATHEXECUTIONCONTEXT_HEADER_GUARD_1357924680



// Base include file.  Must be first.
#include <xalanc/XPath/XPathDefinitions.hpp>



#include <cassert>
#include <vector>



#include <xalanc/XalanDOM/XalanDOMString.hpp>



// Base class header file...
#include <xalanc/PlatformSupport/ExecutionContext.hpp>



#include <xalanc/XPath/MutableNodeRefList.hpp>



XALAN_CPP_NAMESPACE_BEGIN



class XalanDecimalFormatSymbols;
class PrefixResolver;
class XalanQName;
class XObject;
class XObjectPtr;
class XObjectFactory;
class XalanDocument;
class XalanElement;
class XalanNode;
class XalanText;



//
// An abstract class which provides support for executing XPath functions
// and extension functions.
//

class XALAN_XPATH_EXPORT XPathExecutionContext : public ExecutionContext
{
public:

#if defined(XALAN_NO_STD_NAMESPACE)
	typedef vector<XObjectPtr>			XObjectArgVectorType;
#else
	typedef std::vector<XObjectPtr>		XObjectArgVectorType;
#endif

	typedef NodeRefListBase::size_type	size_type;

	explicit
	XPathExecutionContext(XObjectFactory*	theXObjectFactory = 0);

	virtual
	~XPathExecutionContext();

	/**
	 * Reset the instance.  This must be called before another
	 * execution is attempted.
	 */
	virtual void
	reset() = 0;

	/**
	 * Retrieve the node currently being executed.
	 * 
	 * @return current node
	 */
	virtual XalanNode*
	getCurrentNode() const = 0;

	/**
	 * Change the node currently being executed.
	 * 
	 * @param theCurrentNode new current node
	 */
	virtual void
	pushCurrentNode(XalanNode*	theCurrentNode) = 0;

	/**
	 * Reset the node currently being executed.
	 */
	virtual void
	popCurrentNode() = 0;

	class CurrentNodePushAndPop
	{
	public:

		CurrentNodePushAndPop(
				XPathExecutionContext&	theExecutionContext,
				XalanNode*				theNewNode) :
			m_executionContext(theExecutionContext)
		{
			theExecutionContext.pushCurrentNode(theNewNode);
		}

		~CurrentNodePushAndPop()
		{
			m_executionContext.popCurrentNode();
		}

	private:

		XPathExecutionContext&	m_executionContext;
	};

	/**
	 * Retrieve the factory object for creating XObjects.
	 * 
	 * @return factory object instance
	 */
	XObjectFactory&
	getXObjectFactory() const
	{
		assert(m_xobjectFactory != 0);

		return *m_xobjectFactory;
	}

	/**
	 * Determine if a node is after another node, in document order.
	 *
	 * @param node1 The first node
	 * @param node2 The second node
	 * @return true if node1 one is after node2, or false if it is not.
	 */
	virtual bool
	isNodeAfter(
			const XalanNode&	node1,
			const XalanNode&	node2) const = 0;

	/**
	 * Push the node list for current context.
	 * 
	 * @param theList new node list
	 */
	virtual void
	pushContextNodeList(const NodeRefListBase&	theList) = 0;

	/**
	 * Pop the node list for current context.
	 */
	virtual void	
	popContextNodeList() = 0;

	class ContextNodeListPushAndPop
	{
	public:

		ContextNodeListPushAndPop(
				XPathExecutionContext&		theExecutionContext,
				const NodeRefListBase&		theNodeList) :
			m_executionContext(theExecutionContext)
		{
			m_executionContext.pushContextNodeList(theNodeList);
		}

		~ContextNodeListPushAndPop()
		{
			m_executionContext.popContextNodeList();
		}

	private:

		XPathExecutionContext&	m_executionContext;
	};

	/**
	 * Get the node list for current context.
	 * 
	 * @return node list
	 */
	virtual const NodeRefListBase&
	getContextNodeList() const = 0;

	/*
	 * Get the count of nodes in the current context node list.
	 *
	 * @return length of list
	 */
	virtual size_type
	getContextNodeListLength() const = 0;

	/*
	 * Get the position of the node in the current context node list.
	 * Note that this is 1-based indexing (XPath/XSLT-style), not 0-based.
	 * Thus, 0 will be returned if the node was not found.
	 *
	 * @return position in list
	 */
	virtual size_type
	getContextNodeListPosition(const XalanNode&		contextNode) const = 0;

	/**
	 * Determine if an external element is available.
	 *
	 * @param theQName The QName of the element
	 *
	 * @return whether the given element is available or not
	 */
	virtual bool
	elementAvailable(const XalanQName&	theQName) const = 0;

	/**
	 * Determine if an external element is available by resolving
	 * a string to a QName.
	 *
	 * @param theName The name of the element
	 * @param locator A LocatorType instance for error reporting
	 *
	 * @return whether the given element is available or not
	 */
	virtual bool
	elementAvailable(
			const XalanDOMString&	theName,
			const LocatorType*		locator) const = 0;

	/**
	 * Determine if a function is available.
	 *
	 * @param theQName The QName of the function
	 *
	 * @return whether the function is available or not
	 */
	virtual bool
	functionAvailable(const XalanQName&		theQName) const = 0;

	/**
	 * Determine if a function is available.
	 *
	 * @param theName The name of the function
	 * @param locator A LocatorType instance for error reporting
	 *
	 * @return whether the function is available or not
	 */
	virtual bool
	functionAvailable(
			const XalanDOMString&	theName,
			const LocatorType*		locator) const = 0;

	/**
	 * Handle an extension function.
	 * 
	 * @param theNamespace  namespace of function    
	 * @param functionName extension function name
	 * @param context The context node
	 * @param argVec vector of arguments to function
	 * @param locator A LocatorType instance for error reporting
	 * @return pointer to XObject result
	 */
	virtual const XObjectPtr
	extFunction(
			const XalanDOMString&			theNamespace,
			const XalanDOMString&			functionName,
			XalanNode*						context,
			const XObjectArgVectorType&		argVec,
			const LocatorType*				locator) = 0;

	/**
	 * Provides support for XML parsing service.
	 *
	 * @param urlString location of the XML
	 * @param base base location for URI
	 * @return parsed document
	 */
	virtual XalanDocument*
	parseXML(
			const XalanDOMString&	urlString,
			const XalanDOMString&	base) const = 0;

	/**
	 * Borrow a cached MutableNodeRefList instance.
	 *
	 * @return A pointer to the instance.
	 */
	virtual MutableNodeRefList*
	borrowMutableNodeRefList() = 0;

	/**
	 * Return a previously borrowed MutableNodeRefList instance.
	 *
	 * @param theList A pointer the to previously borrowed instance.
	 * @return true if the list was borrowed (at therefore, destroyed), false if not.
	 */
	virtual bool
	returnMutableNodeRefList(MutableNodeRefList*	theList) = 0;

	class BorrowReturnMutableNodeRefList
	{
	public:

		BorrowReturnMutableNodeRefList(XPathExecutionContext&	executionContext) :
			m_xpathExecutionContext(&executionContext),
			m_mutableNodeRefList(executionContext.borrowMutableNodeRefList())
		{
			assert(m_mutableNodeRefList != 0);
		}

		// N.B. Non-const copy constructor semantics (like std::auto_ptr)
		BorrowReturnMutableNodeRefList(const BorrowReturnMutableNodeRefList&	theSource) :
			m_xpathExecutionContext(theSource.m_xpathExecutionContext),
			m_mutableNodeRefList(theSource.m_mutableNodeRefList)
		{
			assert(m_mutableNodeRefList != 0);

			((BorrowReturnMutableNodeRefList&)theSource).m_mutableNodeRefList = 0;
		}

		~BorrowReturnMutableNodeRefList()
		{
			release();
		}

		MutableNodeRefList&
		operator*() const
		{
			assert(m_mutableNodeRefList != 0);

			return *m_mutableNodeRefList;
		}

		MutableNodeRefList*
		get() const
		{
			return m_mutableNodeRefList;
		}

		MutableNodeRefList*
		operator->() const
		{
			return get();
		}

		void
		release()
		{
			assert(m_xpathExecutionContext != 0);

			if (m_mutableNodeRefList != 0)
			{
				m_xpathExecutionContext->returnMutableNodeRefList(m_mutableNodeRefList);

				m_mutableNodeRefList = 0;
			}
		}

		BorrowReturnMutableNodeRefList
		clone() const
		{
			assert(m_xpathExecutionContext != 0);

			BorrowReturnMutableNodeRefList	theResult(*m_xpathExecutionContext);

			*theResult = *m_mutableNodeRefList;

			return theResult;
		}

		// N.B. Non-const assignment operator semantics.
		BorrowReturnMutableNodeRefList&
		operator=(BorrowReturnMutableNodeRefList&	theRHS)
		{
			release();

			m_xpathExecutionContext = theRHS.m_xpathExecutionContext;

			m_mutableNodeRefList = theRHS.m_mutableNodeRefList;

			theRHS.m_mutableNodeRefList = 0;

			return *this;
		}

	private:

		XPathExecutionContext*	m_xpathExecutionContext;

		MutableNodeRefList*		m_mutableNodeRefList;
	};

	/**
	 * Get a cached string for temporary use.
	 *
	 * @return A reference to the string
	 */
	virtual XalanDOMString&
	getCachedString() = 0;

	/**
	 * Return a cached string.
	 *
	 * @param theString The string to release.
	 *
	 * @return true if the string was released successfully.
	 */
	virtual bool
	releaseCachedString(XalanDOMString&		theString) = 0;

	class GetAndReleaseCachedString
	{
	public:

		GetAndReleaseCachedString(XPathExecutionContext&	theExecutionContext) :
			m_executionContext(&theExecutionContext),
			m_string(&theExecutionContext.getCachedString())
		{
		}

		// Note non-const copy semantics...
		GetAndReleaseCachedString(GetAndReleaseCachedString&	theSource) :
			m_executionContext(theSource.m_executionContext),
			m_string(theSource.m_string)
		{
			theSource.m_string = 0;
		}

		~GetAndReleaseCachedString()
		{
			if (m_string != 0)
			{
				m_executionContext->releaseCachedString(*m_string);
			}
		}

		XalanDOMString&
		get() const
		{
			assert(m_string != 0);

			return *m_string;
		}

		XPathExecutionContext&
		getExecutionContext() const
		{
			return *m_executionContext;
		}

	private:

		// Not implemented...
		GetAndReleaseCachedString&
		operator=(const GetAndReleaseCachedString&);


		// Data members...
		XPathExecutionContext*	m_executionContext;

		XalanDOMString*			m_string;
	};

	/**
	 * Create a MutableNodeRefList with the appropriate context.
	 *
	 * @return pointer to node list created
	 */
	virtual MutableNodeRefList*
	createMutableNodeRefList() const = 0;

	/**
	 * Given a valid element key, return the corresponding node list.
	 *
	 * @param doc              source document
	 * @param name             qname of the key, which must match the 'name'
	 *                         attribute on xsl:key
	 * @param ref              value that must match the value found by the
	 *                         'match' attribute on xsl:key
	 * @param nodelist         A node list to contain the nodes found
	 */
	virtual void
	getNodeSetByKey(
			XalanDocument*			doc,
			const XalanQName&		qname,
			const XalanDOMString&	ref,
			MutableNodeRefList&		nodelist) = 0;

	/**
	 * Given a valid element key, return the corresponding node list.
	 *
	 * @param doc              source document
	 * @param name             name of the key, which must match the 'name'
	 *                         attribute on xsl:key.  Will be resolved to a
	 *                         qname using the provided resolver.
	 * @param ref              value that must match the value found by the
	 *                         'match' attribute on xsl:key
	 * @param locator          The LocatorType to use for error reporting.  Can be 0.
	 * @param nodelist         A node list to contain the nodes found
	 */
	virtual void
	getNodeSetByKey(
			XalanDocument*			doc,
			const XalanDOMString&	name,
			const XalanDOMString&	ref,
			const LocatorType*		locator,
			MutableNodeRefList&		nodelist) = 0;

	/**
	 * Given a name, locate a variable in the current context, and return 
	 * a pointer to the object.
	 *
	 * @param theName name of variable
	 * @return pointer to an XObject if the variable was found, 0 if it was not
	 */
	virtual const XObjectPtr
	getVariable(
			const XalanQName&	name,
			const LocatorType*	locator = 0) = 0;

	/**
	 * Retrieve the resolver for namespaces.
	 * 
	 * @return object for namespace resolution
	 */
	virtual const PrefixResolver*
	getPrefixResolver() const = 0;

	/**
	 * Change the resolver for namespaces.
	 * 
	 * @param thePrefixResolver new object for namespace resolution
	 */
	virtual void
	setPrefixResolver(const PrefixResolver*		thePrefixResolver) = 0;

	class PrefixResolverSetAndRestore
	{
	public:

		PrefixResolverSetAndRestore(
				XPathExecutionContext&	theExecutionContext,
				const PrefixResolver*	theResolver) :
			m_executionContext(theExecutionContext),
			m_savedResolver(theExecutionContext.getPrefixResolver())
		{
			m_executionContext.setPrefixResolver(theResolver);
		}

		PrefixResolverSetAndRestore(
				XPathExecutionContext&	theExecutionContext,
				const PrefixResolver*	theOldResolver,
				const PrefixResolver*	theNewResolver) :
			m_executionContext(theExecutionContext),
			m_savedResolver(theOldResolver)
		{
			m_executionContext.setPrefixResolver(theNewResolver);
		}

		~PrefixResolverSetAndRestore()
		{
			m_executionContext.setPrefixResolver(m_savedResolver);
		}

	private:

		XPathExecutionContext&			m_executionContext;
		const PrefixResolver* const		m_savedResolver;
	};

	/**
	 * Retrieve the URI corresponding to a namespace prefix
	 * 
	 * @param prefix prefix for a namespace
	 * @return URI corresponding to namespace
	 */
	virtual const XalanDOMString*
	getNamespaceForPrefix(const XalanDOMString&		prefix) const = 0;

	/**
	 * Given a DOM Document, tell what URI was used to parse it. Needed for
	 * relative resolution.
	 *
	 * @param owner source document
	 * @return document URI
	 */
	virtual XalanDOMString
	findURIFromDoc(const XalanDocument*		owner) const = 0;

	/**
	 * The getUnparsedEntityURI function returns the URI of the unparsed
	 * entity with the specified name in the same document as the context
	 * node (see [3.3 Unparsed Entities]). It returns the empty string if
	 * there is no such entity.
	 *
	 * @param theName     name of entity
	 * @param theDocument document containing entity
	 * @return URI for the entity
	 */
	virtual const XalanDOMString&
	getUnparsedEntityURI(
			const XalanDOMString&	theName,
			const XalanDocument&	theDocument) const = 0;

	/**
	 * Tells, through the combination of the default-space attribute
	 * on xsl:stylesheet, xsl:strip-space, xsl:preserve-space, and the
	 * xml:space attribute, whether or not extra whitespace should be stripped
	 * from the node.  Literal elements from template elements should
	 * <em>not</em> be tested with this function.
	 *
	 * @param textNode text node from the source tree
	 * @return true if the text node should be stripped of extra whitespace
	 */
	virtual bool
	shouldStripSourceNode(const XalanNode&	node) = 0;

	/**
	 * Get the document associated with the given URI.
	 *
	 * @param theURI      document URI
	 * @return a pointer to the document instance, if any.
	 */
	virtual XalanDocument*
	getSourceDocument(const XalanDOMString&		theURI) const = 0;

	/**
	 * Associate a document with a given URI.
	 *
	 * @param theURI      document URI
	 * @param theDocument source document
	 */
	virtual void
	setSourceDocument(
			const XalanDOMString&	theURI,
			XalanDocument*			theDocument) = 0;


	/**
	 * Retrieve the XalanDecimalFormatSymbols instance associated with
	 * the name.
	 *
	 * @param qname the QName for the lookup
	 * @return a pointer to the matching instance, or 0 if none was found
	 */
	virtual const XalanDecimalFormatSymbols*
	getDecimalFormatSymbols(const XalanQName&	qname) = 0;

	// These interfaces are inherited from ExecutionContext...

	virtual void
	error(
			const XalanDOMString&	msg,
			const XalanNode* 		sourceNode = 0,
			const LocatorType* 		locator = 0) const = 0;

	virtual void
	error(
			const char*			msg,
			const XalanNode* 	sourceNode = 0,
			const LocatorType* 	locator = 0) const = 0;

	virtual void
	warn(
			const XalanDOMString&	msg,
			const XalanNode* 		sourceNode = 0,
			const LocatorType* 		locator = 0) const = 0;

	virtual void
	warn(
			const char*			msg,
			const XalanNode* 	sourceNode = 0,
			const LocatorType* 	locator = 0) const = 0;

	virtual void
	message(
			const XalanDOMString&	msg,
			const XalanNode* 		sourceNode = 0,
			const LocatorType* 		locator = 0) const = 0;

	virtual void
	message(
			const char*			msg,
			const XalanNode* 	sourceNode = 0,
			const LocatorType* 	locator = 0) const = 0;

protected:

	XObjectFactory*		m_xobjectFactory;
};



XALAN_CPP_NAMESPACE_END



#endif	// XPATHEXECUTIONCONTEXT_HEADER_GUARD_1357924680
