/*
 * Copyright 2001-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.
 */
package org.jboss.axis.message;

// $Id$

import org.jboss.axis.NotImplementedException;
import org.jboss.axis.utils.DOM2Utils;
import org.jboss.logging.Logger;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.w3c.dom.TypeInfo;

import javax.xml.soap.Name;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * An implemenation of the abstract SOAPElement.
 * <p/>
 * This class should not expose functionality that is not part of
 * {@link SOAPElement}. Client code should use <code>SOAPElement</code> whenever possible.
 *
 * @author Thomas Diesler (thomas.diesler@jboss.org)
 */
public class SOAPElementImpl extends NodeImpl implements SOAPElement
{

   // provide logging
   private static Logger log = Logger.getLogger(SOAPElement.class.getName());

   // The element
   private Element element;

   /**
    * Constructor used by the <code>SOAPElementFactory</code>
    */
   public SOAPElementImpl(String localPart)
   {
      super(DOM2Utils.createElement(null, localPart));
      element = (Element)domNode;
   }

   /**
    * Constructor used by the <code>SOAPElementFactory</code>
    */
   public SOAPElementImpl(String localPart, String prefix, String namespace)
   {
      super(DOM2Utils.createElement(null, namespace, prefix, localPart));
      element = (Element)domNode;
   }

   /**
    * Constructor used by the <code>SOAPElementFactory</code>
    */
   public SOAPElementImpl(Name name)
   {
      super(DOM2Utils.createElement(null, name));
      element = (Element)domNode;
   }

   // package protected contructors

   SOAPElementImpl(Element element)
   {
      super(element);
      this.element = element;
   }

   //  javax.xml.soap.SOAPElement *************************************************************************************

   /**
    * Adds an attribute with the specified name and value to this SOAPElement object.
    *
    * @param name  a Name object with the name of the attribute
    * @param value a String giving the value of the attribute
    * @return the SOAPElement object into which the attribute was inserted
    * @throws javax.xml.soap.SOAPException if there is an error in creating the Attribute
    */
   public SOAPElement addAttribute(Name name, String value) throws SOAPException
   {
      setAttributeNS(name.getURI(), name.getQualifiedName(), value);
      return this;
   }

   /**
    * Creates a new SOAPElement object initialized with the specified local name and adds the new element to this SOAPElement object.
    *
    * @param name a String giving the local name for the element
    * @return the new SOAPElement object that was created
    * @throws javax.xml.soap.SOAPException if there is an error in creating the SOAPElement object
    */
   public SOAPElement addChildElement(String name) throws SOAPException
   {
      SOAPElement soapElement = new SOAPElementImpl(name);
      addChildElement(soapElement);
      return soapElement;
   }

   /**
    * Creates a new SOAPElement object initialized with the specified local name and prefix and adds the new element to this SOAPElement object.
    *
    * @param localName a String giving the local name for the new element
    * @param prefix    a String giving the namespace prefix for the new element
    * @return the new SOAPElement object that was created
    * @throws javax.xml.soap.SOAPException if there is an error in creating the SOAPElement object
    */
   public SOAPElement addChildElement(String localName, String prefix) throws SOAPException
   {
      SOAPElement soapElement = new SOAPElementImpl(localName, prefix, null);
      addChildElement(soapElement);
      return soapElement;
   }

   /**
    * Creates a new SOAPElement object initialized with the specified local name, prefix, and URI and adds the new element to this SOAPElement object.
    *
    * @param localName a String giving the local name for the new element
    * @param prefix    a String giving the namespace prefix for the new element
    * @param uri       a String giving the URI of the namespace to which the new element belongs
    * @return the new SOAPElement object that was created
    * @throws javax.xml.soap.SOAPException if there is an error in creating the SOAPElement object
    */
   public SOAPElement addChildElement(String localName, String prefix, String uri) throws SOAPException
   {
      SOAPElement soapElement = new SOAPElementImpl(localName, prefix, uri);
      addChildElement(soapElement);
      return soapElement;
   }

   /**
    * Creates a new SOAPElement object initialized with the given Name object and adds the new element to this SOAPElement object.
    *
    * @param name a Name object with the XML name for the new element
    * @return the new SOAPElement object that was created
    * @throws javax.xml.soap.SOAPException if there is an error in creating the SOAPElement object
    */
   public SOAPElement addChildElement(Name name) throws SOAPException
   {
      SOAPElement soapElement = new SOAPElementImpl(name);
      addChildElement(soapElement);
      return soapElement;
   }

   /**
    * Add a SOAPElement as a child of this SOAPElement instance. The SOAPElement is expected to be created by a SOAPElementFactory.
    * <p/>
    * Callers should not rely on the element instance being added as is into the XML tree.
    * Implementations could end up copying the content of the SOAPElement passed into an instance of a different SOAPElement
    * implementation. For instance if addChildElement() is called on a SOAPHeader, element will be copied into an instance of a SOAPHeaderElement.
    * <p/>
    * The fragment rooted in element is either added as a whole or not at all, if there was an error.
    * <p/>
    * The fragment rooted in element cannot contain elements named "Envelope", "Header" or "Body" and in the SOAP namespace.
    * Any namespace prefixes present in the fragment should be fully resolved using appropriate namespace declarations within the fragment itself.
    *
    * @param child the SOAPElement to be added as a new child
    * @return an instance representing the new SOAP element that was actually added to the tree.
    * @throws javax.xml.soap.SOAPException if there was an error in adding this element as a child
    */
   public SOAPElement addChildElement(SOAPElement child) throws SOAPException
   {
      element.appendChild(child);
      return new SOAPElementAxisImpl(child);
   }

   /**
    * Adds a namespace declaration with the specified prefix and URI to this SOAPElement object.
    *
    * @param prefix a String giving the prefix of the namespace
    * @param uri    a String giving the uri of the namespace
    * @return the SOAPElement object into which this namespace declaration was inserted.
    * @throws javax.xml.soap.SOAPException if there is an error in creating the namespace
    */
   public SOAPElement addNamespaceDeclaration(String prefix, String uri) throws SOAPException
   {
      element.setAttribute("xmlns:" + prefix, uri);
      return this;
   }

   /**
    * Creates a new Text object initialized with the given String and adds it to this SOAPElement object.
    *
    * @param value a String object with the textual content to be added
    * @return the SOAPElement object into which the new Text object was inserted
    * @throws SOAPException if there is an error in creating the new Text object
    */
   public SOAPElement addTextNode(String value) throws SOAPException
   {
      org.w3c.dom.Text domText = element.getOwnerDocument().createTextNode(value);
      javax.xml.soap.Text soapText = new TextImpl(domText);
      appendChild(soapText);
      return this;
   }

   /**
    * Returns an Iterator over all of the attribute Name objects in this SOAPElement object.
    * <p/>
    * The iterator can be used to get the attribute names, which can then be passed to the method getAttributeValue to
    * retrieve the value of each attribute.
    *
    * @return an iterator over the names of the attributes
    */
   public Iterator getAllAttributes()
   {
      ArrayList list = new ArrayList();
      NamedNodeMap nnm = getAttributes();
      for (int i = 0; i < nnm.getLength(); i++)
      {
         org.w3c.dom.Node node = (org.w3c.dom.Node)nnm.item(i);
         String local = node.getLocalName();
         String prefix = node.getPrefix();
         String uri = node.getNamespaceURI();
         list.add(new NameImpl(local, prefix, uri));
      }
      return list.iterator();
   }

   /**
    * Returns the value of the attribute with the specified name.
    *
    * @param name a Name object with the name of the attribute
    * @return a String giving the value of the specified attribute
    */
   public String getAttributeValue(Name name)
   {
      throw new NotImplementedException();
   }

   /**
    * Returns an Iterator over all the immediate child Nodes of this element.
    * <p/>
    * This includes javax.xml.soap.Text objects as well as SOAPElement objects.
    * Calling this method may cause child Element, SOAPElement and org.w3c.dom.Text nodes to be replaced by SOAPElement,
    * SOAPHeaderElement, SOAPBodyElement or javax.xml.soap.Text nodes as appropriate for the type of this parent node.
    * As a result the calling application must treat any existing references to these child nodes that have been obtained
    * through DOM APIs as invalid and either discard them or refresh them with the values returned by this Iterator.
    * This behavior can be avoided by calling the equivalent DOM APIs. See javax.xml.soap for more details.
    *
    * @return an iterator with the content of this SOAPElement object
    */
   public Iterator getChildElements()
   {
      throw new NotImplementedException();
   }

   /**
    * Returns an Iterator over all the immediate child Nodes of this element with the specified name.
    * <p/>
    * All of these children will be SOAPElement nodes.
    * Calling this method may cause child Element, SOAPElement and org.w3c.dom.Text nodes to be replaced by SOAPElement,
    * SOAPHeaderElement, SOAPBodyElement or javax.xml.soap.Text nodes as appropriate for the type of this parent node.
    * As a result the calling application must treat any existing references to these child nodes that have been obtained
    * through DOM APIs as invalid and either discard them or refresh them with the values returned by this Iterator.
    * This behavior can be avoided by calling the equivalent DOM APIs. See javax.xml.soap for more details.
    *
    * @param name a Name object with the name of the child elements to be returned
    * @return an Iterator object over all the elements in this SOAPElement object with the specified name
    */
   public Iterator getChildElements(Name name)
   {
      throw new NotImplementedException();
   }

   /**
    * Returns the name of this SOAPElement object.
    *
    * @return a Name object with the name of this SOAPElement object
    */
   public Name getElementName()
   {
      throw new NotImplementedException();
   }

   /**
    * Returns the encoding style for this SOAPElement object.
    *
    * @return a String giving the encoding style
    */
   public String getEncodingStyle()
   {
      throw new NotImplementedException();
   }

   /**
    * Returns an Iterator over the namespace prefix Strings declared by this element.
    * <p/>
    * The prefixes returned by this iterator can be passed to the method getNamespaceURI to retrieve the URI of each namespace.
    *
    * @return an iterator over the namespace prefixes in this SOAPElement object
    */
   public Iterator getNamespacePrefixes()
   {
      throw new NotImplementedException();
   }

   /**
    * Returns the URI of the namespace that has the given prefix.
    *
    * @param prefix a String giving the prefix of the namespace for which to search
    * @return a String with the uri of the namespace that has the given prefix
    */
   public String getNamespaceURI(String prefix)
   {
      throw new NotImplementedException();
   }

   /**
    * Returns an Iterator over the namespace prefix Strings visible to this element.
    * <p/>
    * The prefixes returned by this iterator can be passed to the method getNamespaceURI to retrieve the URI of each namespace.
    *
    * @return an iterator over the namespace prefixes are within scope of this SOAPElement object
    */
   public Iterator getVisibleNamespacePrefixes()
   {
      throw new NotImplementedException();
   }

   /**
    * Removes the attribute with the specified name.
    *
    * @param name the Name object with the name of the attribute to be removed
    * @return true if the attribute was removed successfully; false if it was not
    */
   public boolean removeAttribute(Name name)
   {
      throw new NotImplementedException();
   }

   /**
    * Detaches all children of this SOAPElement.
    * <p/>
    * This method is useful for rolling back the construction of partially completed SOAPHeaders and SOAPBodys in
    * preparation for sending a fault when an error condition is detected.
    * It is also useful for recycling portions of a document within a SOAP message.
    */
   public void removeContents()
   {
      throw new NotImplementedException();
   }

   /**
    * Removes the namespace declaration corresponding to the given prefix.
    *
    * @param prefix a String giving the prefix for which to search
    * @return true if the namespace declaration was removed successfully; false if it was not
    */
   public boolean removeNamespaceDeclaration(String prefix)
   {
      throw new NotImplementedException();
   }

   /**
    * Sets the encoding style for this SOAPElement object to one specified.
    *
    * @param encodingStyle a String giving the encoding style
    * @throws javax.xml.soap.SOAPException if there was a problem in the encoding style being set.
    */
   public void setEncodingStyle(String encodingStyle) throws SOAPException
   {
      throw new NotImplementedException();
   }

   // org.w3c.Element ***********************************************************************************************

   public String getTagName()
   {
      return element.getTagName();
   }

   public void removeAttribute(String name) throws DOMException
   {
      element.removeAttribute(name);
   }

   public boolean hasAttribute(String name)
   {
      return element.hasAttribute(name);
   }

   public String getAttribute(String name)
   {
      return element.getAttribute(name);
   }

   public void removeAttributeNS(String namespaceURI, String localName) throws DOMException
   {
      element.removeAttributeNS(namespaceURI, localName);
   }

   public void setAttribute(String name, String value) throws DOMException
   {
      element.setAttribute(name, value);
   }

   public boolean hasAttributeNS(String namespaceURI, String localName)
   {
      return element.hasAttributeNS(namespaceURI, localName);
   }

   public Attr getAttributeNode(String name)
   {
      return element.getAttributeNode(name);
   }

   public Attr removeAttributeNode(Attr oldAttr) throws DOMException
   {
      return element.removeAttributeNode(oldAttr);
   }

   public Attr setAttributeNode(Attr newAttr) throws DOMException
   {
      return element.setAttributeNode(newAttr);
   }

   public Attr setAttributeNodeNS(Attr newAttr) throws DOMException
   {
      return element.setAttributeNodeNS(newAttr);
   }

   public NodeList getElementsByTagName(String name)
   {
      return element.getElementsByTagName(name);
   }

   public String getAttributeNS(String namespaceURI, String localName)
   {
      return element.getAttributeNS(namespaceURI, localName);
   }

   public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException
   {
      element.setAttributeNS(namespaceURI, qualifiedName, value);
   }

   public Attr getAttributeNodeNS(String namespaceURI, String localName)
   {
      return element.getAttributeNodeNS(namespaceURI, localName);
   }

   public NodeList getElementsByTagNameNS(String namespaceURI, String localName)
   {
      return element.getElementsByTagNameNS(namespaceURI, localName);
   }

   // DOM3-API start ***************************************************************************************************
   public TypeInfo getSchemaTypeInfo()
   {
      return null;
   }

   public void setIdAttribute(String name, boolean isId) throws DOMException
   {

   }

   public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException
   {

   }

   public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException
   {
      
   }
   // DOM3-API end *****************************************************************************************************
}
