/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed 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.
 */

#include <crtdbg.h>

#include <xalanc/Include/PlatformDefinitions.hpp>



#if defined(XALAN_CLASSIC_IOSTREAMS)
#include <iostream.h>
#else
#include <iostream>
#endif



#include <xercesc/util/PlatformUtils.hpp>



#include <xalanc/XalanTransformer/XalanTransformer.hpp>

#include <xalanc/XalanDOM/XalanDOMException.hpp>
#include <xalanc/XalanDOM/XalanDocument.hpp>
#include <xalanc/XalanDOM/XalanNode.hpp>
#include <xalanc/XalanDOM/XalanNodeList.hpp>
#include <xalanc/XalanDOM/XalanNamedNodeMap.hpp>
#include <xalanc/XalanDOM/XalanElement.hpp>

#include <xercesc/sax/SAXParseException.hpp>

XALAN_CPP_NAMESPACE_USE

//========================================================================
class TestElement : public XalanElement, public XalanNodeList
{
public:
    TestElement(const char *name, const char *value);
const XalanDOMString    &getNodeName() const { return(mName); }
const XalanDOMString    &getNodeValue() const { return(mValue); }

    NodeType            getNodeType() const { return(DOCUMENT_NODE); }
    XalanNode           *getParentNode() const { return(pDocument); }
const XalanNodeList     *getChildNodes() const { return(this); }
    XalanNode           *getFirstChild() const { return(NULL); }
    XalanNode           *getLastChild() const { return(NULL); }
    XalanNode           *getPreviousSibling() const { return(NULL); }
    XalanNode           *getNextSibling() const { return(NULL); }
const XalanNamedNodeMap *getAttributes() const { return(NULL); }
    XalanDocument       *getOwnerDocument() const { return(pDocument); }
const XalanDOMString    &getTagName() const { return(mName); }
const XalanDOMString    &getAttribute(const XalanDOMString &) const { notSupported(); return(getEmpty()); }
    XalanAttr           *getAttributeNode(const XalanDOMString &) const { notSupported(); return(NULL); }
    XalanNodeList       *getElementsByTagName(const XalanDOMString &) const { notSupported(); return(NULL); }
    XalanElement        *cloneNode(bool) const { notSupported(); return(NULL); }
    XalanNode           *insertBefore(XalanNode *, XalanNode *) { notSupported(); return(NULL); }
    XalanNode           *replaceChild(XalanNode *, XalanNode *) { notSupported(); return(NULL); }
    XalanNode           *removeChild(XalanNode *) { notSupported(); return(NULL); }
    XalanNode           *appendChild(XalanNode *) { notSupported(); return(NULL); }
    bool                hasChildNodes() const { return(false); }
    void                setNodeValue(const XalanDOMString &) { notSupported(); }
    void                normalize() { notSupported(); }

    bool                isSupported(const XalanDOMString &, const XalanDOMString &) const { notSupported(); return(false); }
const XalanDOMString    &getNamespaceURI() const { return(getEmpty()); }
const XalanDOMString    &getPrefix() const { return(getEmpty()); }
const XalanDOMString    &getLocalName() const { return(getEmpty()); }
    void                setPrefix(const XalanDOMString &) { notSupported(); }
    bool                isIndexed() const { return(false); }
    IndexType           getIndex() const { return(0); }        
    void                setAttribute(const XalanDOMString &, const XalanDOMString &) { notSupported(); }
    XalanAttr           *setAttributeNode(XalanAttr *) { notSupported(); return(NULL); }
    XalanAttr           *removeAttributeNode(XalanAttr *) { notSupported(); return(NULL); }
    void                removeAttribute(const XalanDOMString &) { notSupported(); }

const XalanDOMString    &getAttributeNS(const XalanDOMString &, const XalanDOMString &) const { return(getEmpty()); }
    void                setAttributeNS(const XalanDOMString &, const XalanDOMString &, const XalanDOMString &) { notSupported(); }
    void                removeAttributeNS(const XalanDOMString &, const XalanDOMString &) { notSupported(); }
    XalanAttr           *getAttributeNodeNS(const XalanDOMString &, const XalanDOMString &) const { notSupported(); return(NULL); }
    XalanAttr           *setAttributeNodeNS(XalanAttr *) { notSupported(); return(NULL); }
    XalanNodeList       *getElementsByTagNameNS(const XalanDOMString &, const XalanDOMString &) const { notSupported(); return(NULL); }
// XalanNodeList  
    XalanNode           *item(unsigned int) const { return(NULL); }
    unsigned int        getLength() const { return(0U); }
private:
    void                notSupported() const;
const XalanDOMString    &getEmpty() const;
    XalanDOMString      mName;
    XalanDOMString      mValue;
    XalanDocument       *pDocument;
};

//========================================================================
inline
void TestElement::notSupported() const
{
    assert(false);
    throw XalanDOMException(XalanDOMException::NOT_SUPPORTED_ERR);
}

//========================================================================
const XalanDOMString &TestElement::getEmpty() const
{
static XalanDOMString _sEmpty;
    return(_sEmpty);
}

//========================================================================
TestElement::TestElement(const char *name, const char *value)
{
    mName = name;
    mValue = value;
}

//========================================================================
class TestDocument : public XalanDocument, public XalanNodeList
{
public:
    TestDocument(const char *name, const char *value, const char *ename, const char *evalue);
const XalanDOMString    &getNodeName() const { return(mName); }
const XalanDOMString    &getNodeValue() const { return(mValue); }

    NodeType            getNodeType() const { return(DOCUMENT_NODE); }
    XalanNode           *getParentNode() const { return(NULL); }
const XalanNodeList     *getChildNodes() const { return(this); }
    XalanNode           *getFirstChild() const { return(NULL); }
    XalanNode           *getLastChild() const { return(NULL); }
    XalanNode           *getPreviousSibling() const { return(NULL); }
    XalanNode           *getNextSibling() const { return(NULL); }
const XalanNamedNodeMap *getAttributes() const { return(NULL); }
    XalanDocument       *getOwnerDocument() const { return(NULL); }
const XalanDOMString    &getTagName() const { return(mName); }
const XalanDOMString    &getAttribute(const XalanDOMString &) const { notSupported(); return(getEmpty()); }
    XalanAttr           *getAttributeNode(const XalanDOMString &) const { notSupported(); return(NULL); }
    XalanNodeList       *getElementsByTagName(const XalanDOMString &) const { notSupported(); return(NULL); }
    XalanDocument       *cloneNode(bool) const { notSupported(); return(NULL); }
    XalanNode           *insertBefore(XalanNode *, XalanNode *) { notSupported(); return(NULL); }
    XalanNode           *replaceChild(XalanNode *, XalanNode *) { notSupported(); return(NULL); }
    XalanNode           *removeChild(XalanNode *) { notSupported(); return(NULL); }
    XalanNode           *appendChild(XalanNode *) { notSupported(); return(NULL); }
    bool                hasChildNodes() const { return(false); }
    void                setNodeValue(const XalanDOMString &) { notSupported(); }
    void                normalize() { notSupported(); }

    bool                isSupported(const XalanDOMString &, const XalanDOMString &) const { notSupported(); return(false); }
const XalanDOMString    &getNamespaceURI() const { return(getEmpty()); }
const XalanDOMString    &getPrefix() const { return(getEmpty()); }
const XalanDOMString    &getLocalName() const { return(getEmpty()); }
    void                setPrefix(const XalanDOMString &) { notSupported(); }
    bool                isIndexed() const { return(false); }
    IndexType           getIndex() const { return(0); }        
    void                setAttribute(const XalanDOMString &, const XalanDOMString &) { notSupported(); }
    XalanAttr           *setAttributeNode(XalanAttr *) { notSupported(); return(NULL); }
    XalanAttr           *removeAttributeNode(XalanAttr *) { notSupported(); return(NULL); }
    void                removeAttribute(const XalanDOMString &) { notSupported(); }

const XalanDOMString    &getAttributeNS(const XalanDOMString &, const XalanDOMString &) const { return(getEmpty()); }
    void                setAttributeNS(const XalanDOMString &, const XalanDOMString &, const XalanDOMString &) { notSupported(); }
    void                removeAttributeNS(const XalanDOMString &, const XalanDOMString &) { notSupported(); }
    XalanAttr           *getAttributeNodeNS(const XalanDOMString &, const XalanDOMString &) const { notSupported(); return(NULL); }
    XalanAttr           *setAttributeNodeNS(XalanAttr *) { notSupported(); return(NULL); }
    XalanNodeList       *getElementsByTagNameNS(const XalanDOMString &, const XalanDOMString &) const { notSupported(); return(NULL); }
    XalanNode           *importNode(XalanNode *, bool ) { notSupported(); return(NULL); }
    XalanElement        *createElementNS(const XalanDOMString &, const XalanDOMString &) { notSupported(); return(NULL); }
    XalanAttr           *createAttributeNS(const XalanDOMString &, const XalanDOMString &) { notSupported(); return(NULL); }
// No creates supported
    XalanElement        *createElement(const XalanDOMString &) { notSupported(); return(NULL); }
    XalanDocumentFragment *createDocumentFragment() { notSupported(); return(NULL); }
    XalanText           *createTextNode(const XalanDOMString &) { notSupported(); return(NULL); }
    XalanComment        *createComment(const XalanDOMString &) { notSupported(); return(NULL); }
    XalanCDATASection   *createCDATASection(const XalanDOMString &) { notSupported(); return(NULL); }
    XalanProcessingInstruction *createProcessingInstruction(const XalanDOMString &, const XalanDOMString &) { notSupported(); return(NULL); }
    XalanAttr           *createAttribute(const XalanDOMString &) { notSupported(); return(NULL); }
    XalanEntityReference *createEntityReference(const XalanDOMString &) { notSupported(); return(NULL); }
    XalanDocumentType *getDoctype() const { return(NULL); }
    XalanDOMImplementation *getImplementation() const { return(NULL); }
    XalanElement        *getDocumentElement() const { return(&mElement); }
    XalanElement        *getElementById(const XalanDOMString &) const { notSupported(); return(NULL); }
// XalanNodeList  
    XalanNode           *item(unsigned int index) const { return( (0 == index) ? &mElement : NULL); }
    unsigned int        getLength() const { return(1U); }
private:
    void                notSupported() const;
const XalanDOMString    &getEmpty() const;
private:
mutable TestElement     mElement;
    XalanDOMString      mName;
    XalanDOMString      mValue;
};

//========================================================================
TestDocument::TestDocument(const char *name, const char *value, const char *ename, const char *evalue)
: mElement(ename, evalue)
{
    mName = name;
    mValue = value;
}

//========================================================================
inline
void TestDocument::notSupported() const
{
    assert(false);
    throw XalanDOMException(XalanDOMException::NOT_SUPPORTED_ERR);
}

//========================================================================
const XalanDOMString &TestDocument::getEmpty() const
{
static XalanDOMString _sEmpty;
    return(_sEmpty);
}

//========================================================================
int
main(
			int		argc,
			char*	argv[])
{
	XALAN_USING_STD(cerr)
	XALAN_USING_STD(cout)
	XALAN_USING_STD(endl)

    if (argc < 3 || argc > 4)
	{
		cerr << "Usage: XalanTransform XMLFileName XSLFileName [OutFileName]" << endl;
		return -1;
	}

	int		theResult = -1;

    try
	{
		XALAN_USING_XERCES(XMLPlatformUtils)

		XALAN_USING_XALAN(XalanTransformer)

		// Call the static initializer for Xerces.
		XMLPlatformUtils::Initialize();

		// Initialize Xalan.
		XalanTransformer::initialize();

        TestDocument document("document name", "document value", "element name", "element value");

        XSLTInputSource input(&document);
        // I've tried using the document and the document element and get the same problem
//        XSLTInputSource input(document.getDocumentElement());
		{
			// Create a XalanTransformer.
			XalanTransformer theXalanTransformer;

			if (argc == 4)
			{
				// Do the transform.
				theResult = theXalanTransformer.transform(input, argv[2], argv[3]);
        
				if(theResult != 0)
				{
					cerr << "Error: " << theXalanTransformer.getLastError() << endl;
				}
			}
			else
			{
				// Do the transform.
				theResult = theXalanTransformer.transform(input, argv[2], cout);
        
				if(theResult != 0)
				{
					cerr << "Error: " << theXalanTransformer.getLastError() << endl;
				}
			}
		}

		// Terminate Xalan...
		XalanTransformer::terminate();

		// Terminate Xerces...
		XMLPlatformUtils::Terminate();

		// Clean up the ICU, if it's integrated...
		XalanTransformer::ICUCleanUp();
	}
	catch(...)
	{
		cerr << "An unknown error occurred!" << endl;
	}

	return theResult;
}
