content: /*
   * Created on Apr 3, 2009
   *
   * 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.
   *
   * Copyright @2009 the original author or authors.
   */
  package org.fest.swing.junit.xml;
  
  import static org.fest.util.Objects.*;
  import static org.fest.util.Strings.concat;
  
  import org.w3c.dom.*;
  
  /**
   * Understands a DOM-based XML element. This class is intended for internal use only. It is just a thin wrapper around
   * a DOM <code>{@link Element}</code>. It only provides the necessary functionality needed by the FEST-Swing JUnit
   * extension.
   *
   * @author Alex Ruiz
   */
  public class XmlNode {
  
    private final Element target;
  
    /**
     * Creates a new </code>{@link XmlNode}</code>.
     * @param target the underlying DOM element.
     */
    protected XmlNode(Element target) {
      this.target = target;
    }
  
    /**
     * Creates and adds a new XML node to this node.
     * @param name the name of the node to add.
     * @return the created node.
     */
    public XmlNode addNewNode(String name) {
      return new XmlNode(createAndAddChild(name));
    }
  
    /**
     * Creates and adds a new XML node to this node.
     * @param name the name of the node to add.
     * @param attributes the attributes of the node to add.
     * @return the created node.
     */
    public XmlNode addNewNode(String name, XmlAttributes attributes) {
      Element e = createAndAddChild(name);
      for (XmlAttribute a : attributes) addAttribute(e, a);
      return new XmlNode(e);
    }
  
    private Element createAndAddChild(String name) {
      Element e = document().createElement(name);
      target.appendChild(e);
      return e;
    }
  
    /**
     * Adds a CDATA section to this node.
     * @param data the data for the CDATA section to create.
     */
    public void addCdata(String data) {
      CDATASection s = document().createCDATASection(data);
      target.appendChild(s);
    }
  
    /**
     * Adds a text node to this node.
     * @param text the text of the new text node.
     */
    public void addText(String text) {
      Text textNode = document().createTextNode(text);
      target.appendChild(textNode);
    }
  
    private Document document() {
      return target.getOwnerDocument();
    }
  
    /**
     * Adds an attribute to this node.
     * @param a the attribute to add.
     */
    public void addAttribute(XmlAttribute a) {
      addAttribute(target, a);
    }
  
    /**
     * Adds one or more attributes to this node.
     * @param attributes the attribute(s) to add to this node.
     */
    public void addAttributes(XmlAttribute...attributes) {
      for (XmlAttribute a : attributes) addAttribute(target, a);
    }
  
    private static void addAttribute(Element e, XmlAttribute a) {
      e.setAttribute(a.name(), a.value());
    }
  
    /**
     * Returns the underlying DOM <code>{@link Element}</code>.
     * @return the underlying DOM element.
     */
    public Element target() { return target; }
  
    /**
     * Returns the parent node of this node.
     * @return the parent node of this node.
     */
    public XmlNode parentNode() {
      return xmlNodeFrom(target.getParentNode());
    }
  
    /**
     * Returns the number of children in this node.
     * @return the number of children in this node.
     */
    public int size() {
      return target.getChildNodes().getLength();
    }
  
    /**
     * Returns the child at the given index.
     * @param index the given index.
     * @return the child at the given index.
     */
    public XmlNode child(int index) {
      return xmlNodeFrom(target.getChildNodes().item(index));
    }
  
    private static XmlNode xmlNodeFrom(Node n) {
      if (!(n instanceof Element)) return null;
      return new XmlNode((Element)n);
    }
  
    /**
     * Returns the value of the given attribute, or an empty <code>String</code> if this node does not contain an
     * attribute with the given name.
     * @param name the name of the attribute we are looking for.
     * @return the value of the attribute with the given name, or an empty <code>String</code> if this node does not
     * contain a matching attribute.
     */
    public String valueOfAttribute(String name) {
      return target.getAttribute(name);
    }
  
    /**
     * Returns the name of this node.
     * @return the name of this node.
     */
    public String name() {
      return target.getNodeName();
    }
  
    /**
     * Returns the text content of this node.
     * @return the text content of this node.
     */
    public String text() {
      return target.getTextContent();
    }
  
    /**
     * Returns the number of attributes in this node.
     * @return the number of attributes in this node.
     */
    public int attributeCount() {
      return target.getAttributes().getLength();
    }
  
    @Override public boolean equals(Object obj) {
      if (this == obj) return true;
      if (obj == null) return false;
      if (getClass() != obj.getClass()) return false;
      XmlNode other = (XmlNode) obj;
      return target.isEqualNode(other.target);
    }
  
    @Override public int hashCode() {
      int result = 1;
      result = HASH_CODE_PRIME * result + hashCodeFor(name());
      return result;
    }
  
    @Override public String toString() {
      return concat(
          getClass().getSimpleName(), "[",
          "target=", target, "]"
      );
    }
  }
  