/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */

package nuts.core.oxm.adapter;

import java.util.Arrays;
import java.util.List;

import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;

/**
 * SimpleAdapterDocument adapted a Java object and presents it as a Document.
 * This class represents the Document container and uses the AdapterFactory to
 * produce a child adapter for the wrapped object. The adapter produced must be
 * of an Element type or an exception is thrown.
 * 
 * Note: in theory we could base this on AbstractAdapterElement and then allow
 * the wrapped object to be a more general Node type. We would just use
 * ourselves as the root element. However I don't think this is an issue as
 * people expect Documents to wrap Elements.
 */
public class SimpleDocumentAdapter extends AbstractNodeAdapter implements Document {

	private Element rootElement;
	private boolean xmlStandalone = true;
	private String inputEncoding;
	private String xmlEncoding;

	public SimpleDocumentAdapter(AdapterFactory adapterFactory,
			NodeAdapter parent, String propertyName, Object value) {
		setContext(adapterFactory, parent, propertyName, value);

	}

	public void setPropertyValue(Object prop) {
		super.setPropertyValue(prop);
		rootElement = null; // recreate the root element
	}

	public NamedNodeMap getAttributes() {
		return EMPTY_NAMEDNODEMAP;
	}

	/**
	 * Lazily construct the root element adapter from the value object.
	 */
	private Element getRootElement() {
		if (rootElement != null)
			return rootElement;

		Node node = getAdapterFactory().adaptNode(this, getPropertyName(), getPropertyValue());
		if (node instanceof Element)
			rootElement = (Element)node;
		else
			throw new RuntimeException(
					"Document adapter expected to wrap an Element type.  Node is not an element:"
							+ node);

		return rootElement;
	}

	protected List<Node> getChildAdapters() {
		return Arrays.asList(new Node[] { getRootElement() });
	}

	public NodeList getChildNodes() {
		return new NodeList() {
			public Node item(int i) {
				return getRootElement();
			}

			public int getLength() {
				return 1;
			}
		};
	}

	public DocumentType getDoctype() {
		return null;
	}

	public Element getDocumentElement() {
		return getRootElement();
	}

	public Element getElementById(String string) {
		return null;
	}

	public NodeList getElementsByTagName(String string) {
		return null;
	}

	public NodeList getElementsByTagNameNS(String string, String string1) {
		return null;
	}

	public Node getFirstChild() {
		return getRootElement();
	}

	public DOMImplementation getImplementation() {
		return null;
	}

	public Node getLastChild() {
		return getRootElement();
	}

	public String getNodeName() {
		return "#document";
	}

	public short getNodeType() {
		return Node.DOCUMENT_NODE;
	}

	public Attr createAttribute(String string) throws DOMException {
		return null;
	}

	public Attr createAttributeNS(String string, String string1)
			throws DOMException {
		return null;
	}

	public CDATASection createCDATASection(String string) throws DOMException {
		return null;
	}

	public Comment createComment(String string) {
		return null;
	}

	public DocumentFragment createDocumentFragment() {
		return null;
	}

	public Element createElement(String string) throws DOMException {
		return null;
	}

	public Element createElementNS(String string, String string1)
			throws DOMException {
		return null;
	}

	public EntityReference createEntityReference(String string)
			throws DOMException {
		return null;
	}

	public ProcessingInstruction createProcessingInstruction(String string,
			String string1) throws DOMException {
		return null;
	}

	public Text createTextNode(String string) {
		return null;
	}

	public boolean hasChildNodes() {
		return true;
	}

	public Node importNode(Node node, boolean b) throws DOMException {
		return null;
	}

	public Node getChildAfter(Node child) {
		return null;
	}

	public Node getChildBefore(Node child) {
		return null;
	}

	// DOM level 3

	/**
	 * @param xmlStandalone the xmlStandalone to set
	 */
	public void setXmlStandalone(boolean xmlStandalone) {
		this.xmlStandalone = xmlStandalone;
	}

	/**
	 * @return the xmlStandalone
	 */
	public boolean getXmlStandalone() {
		return xmlStandalone;
	}

	/**
	 * @return the inputEncoding
	 */
	public String getInputEncoding() {
		return inputEncoding;
	}

	/**
	 * @return the xmlEncoding
	 */
	public String getXmlEncoding() {
		return xmlEncoding;
	}

	/**
	 * @param inputEncoding the inputEncoding to set
	 */
	public void setInputEncoding(String inputEncoding) {
		this.inputEncoding = inputEncoding;
	}

	/**
	 * @param xmlEncoding the xmlEncoding to set
	 */
	public void setXmlEncoding(String xmlEncoding) throws DOMException {
		this.xmlEncoding = xmlEncoding;
	}

	public String getXmlVersion() {
		return "1.0";
	}

	public void setXmlVersion(String string) throws DOMException {
		throw new UnsupportedOperationException("setXmlVersion");
	}

	public boolean getStrictErrorChecking() {
		throw new UnsupportedOperationException("getStrictErrorChecking");
	}

	public void setStrictErrorChecking(boolean b) {
		throw new UnsupportedOperationException("setStrictErrorChecking");
	}

	public String getDocumentURI() {
		throw new UnsupportedOperationException("getDocumentURI");
	}

	public void setDocumentURI(String string) {
		throw new UnsupportedOperationException("setDocumentURI");
	}

	public Node adoptNode(Node node) throws DOMException {
		throw new UnsupportedOperationException("adoptNode");
	}

	public DOMConfiguration getDomConfig() {
		throw new UnsupportedOperationException("getDomConfig");
	}

	public void normalizeDocument() {
		throw new UnsupportedOperationException("normalizeDocument");
	}

	public Node renameNode(Node node, String string, String string1)
			throws DOMException {
		return null;
	}
	// end DOM level 3
}
