/*
 * Copyright (c) 2008, Aaron Digulla
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Aaron Digulla nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS 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 COPYRIGHT OWNER
 * OR 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.
 */
package de.pdark.decentxml;

import static org.junit.Assert.*;

import de.pdark.decentxml.XMLTokenizer.Type;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;

public class ElementTest {
  @Test
  public void testElement() throws Exception {
    Element e = new Element(" xxx ");
    assertEquals("< xxx />", e.toXML());
  }

  @Test
  public void testSetName() throws Exception {
    Element e = new Element(" xxx ");
    e.setName(e.getName().trim());
    assertEquals("<xxx/>", e.toXML());
  }

  @Test
  public void testHasChildren() throws Exception {
    Element e = new Element("root");
    assertFalse(e.hasNodes());
    assertFalse(e.hasChildren());

    e.addNode(new Text(" "));
    assertTrue(e.hasNodes());
    assertFalse(e.hasChildren());

    e.addNode(new Element("e"));
    assertTrue(e.hasNodes());
    assertTrue(e.hasChildren());
  }

  @Test
  public void testAddIllegalNode() throws Exception {
    Element e = new Element("a");
    Attribute a = new Attribute("x", "1");
    try {
      e.addNode(a);
      fail("No exception was thrown");
    } catch (XMLParseException ex) {
      assertEquals("Line 1, column 1: The node ATTRIBUTE is not allowed here", ex.getMessage());
    }
  }

  @Test
  public void testClearText() throws Exception {
    Element e = new Element("a").setPostSpace(" ");
    e.clearText();
    assertEquals("<a />", e.toXML());
  }

  @Test
  public void testClearText2() throws Exception {
    Element e = new Element("a").addNode(new Text(" "));
    e.clearText();
    assertEquals("<a/>", e.toXML());
  }

  @Test
  public void testClearText2b() throws Exception {
    Element e = new Element("a").setCompactEmpty(false).addNode(new Text(" "));
    e.clearText();
    assertEquals("<a></a>", e.toXML());
  }

  @Test
  public void testClearText3() throws Exception {
    Element e =
        new Element("a")
            .addNodes(new Text(" "), new Element("b").addNode(new Text("a")), new Text(" "));
    e.clearText();
    assertEquals("<a><b/></a>", e.toXML());
  }

  @Test
  public void testClearText4() throws Exception {
    Element e =
        new Element("a")
            .addNodes(new Text(" "), new Element("b").addNode(new Text("a")), new Text(" "));
    e.getChild("b").clearText();
    assertEquals("<a> <b/> </a>", e.toXML());
  }

  @Test
  public void testClearText5() throws Exception {
    Element e =
        new Element("e")
            .addNodes(new Text("1"), new Text(Type.CDATA, "2"), new ProcessingInstruction("dummy"));

    e.clearText();
    assertEquals("", e.getText());
  }

  @Test
  public void testClearNodes() throws Exception {
    Element e = new Element("e");

    e.clearNodes();
    assertEquals("<e/>", e.toXML());
  }

  @Test
  @SuppressWarnings("deprecation")
  public void testClearChildNodes() throws Exception {
    Element e = new Element("e");

    e.clearChildNodes();
    assertEquals("<e/>", e.toXML());
  }

  @Test
  public void testClearChildren() throws Exception {
    Element e = new Element("e");

    e.clearChildren();
    assertEquals("<e/>", e.toXML());
  }

  @Test
  public void testClearChildren2() throws Exception {
    Element e = new Element("e").addNodes(new Text("a"), new Element("b"));

    e.clearChildren();
    assertEquals("<e>a</e>", e.toXML());
  }

  @Test
  public void testGetText() throws Exception {
    Element e =
        new Element("e")
            .addNodes(new Text("1"), new Element("a").addNodes(new Text("2")), new Text("3"));

    assertEquals("123", e.getText());
  }

  @Test
  public void testGetText2() throws Exception {
    Element e = new Element("e").addNodes(new ProcessingInstruction("dummy"));

    assertEquals("", e.getText());
  }

  @Test
  public void testGetParentElement() throws Exception {
    Element e = new Element("e");
    assertNull(e.getParentElement());
  }

  @Test
  public void testElementNullName() throws Exception {
    try {
      new Element((String) null);
      fail("No exception was thrown");
    } catch (NullPointerException ex) {
      assertEquals("name is null", ex.getMessage());
    }
  }

  @Test
  public void testElementEmptyName() throws Exception {
    try {
      new Element("");
      fail("No exception was thrown");
    } catch (IllegalArgumentException ex) {
      assertEquals("name is blank", ex.getMessage());
    }
  }

  @Test
  public void testElementEmptyName2() throws Exception {
    try {
      new Element(" ");
      fail("No exception was thrown");
    } catch (IllegalArgumentException ex) {
      assertEquals("name is blank", ex.getMessage());
    }
  }

  @Test
  @SuppressWarnings("deprecation")
  public void testNodePath() throws Exception {
    Element e = new Element("e");
    assertEquals("e", e.getNodePath());
  }

  @Test
  public void testChildPath() throws Exception {
    Element e = new Element("e");
    assertEquals("e", e.getChildPath());
  }

  @Test
  public void testChildPath2() throws Exception {
    Element e = new Element("e");
    Element e2 = new Element("e2");
    e.addNode(e2);
    assertEquals("e/e2", e2.getChildPath());
  }

  @Test
  public void testChildPath3() throws Exception {
    Document doc = new Document();
    Element e = new Element("e");
    doc.addNode(e);
    assertEquals("/e", e.getChildPath());
  }

  @Test
  public void testChildPath4() throws Exception {
    Document doc = new Document(new Element("e").addNode(new Element("e2")));
    Element e = doc.getRootElement().getChild(0);
    assertEquals("/e/e2", e.getChildPath());
  }

  @Test
  public void testChildPath5() throws Exception {
    Document doc =
        new Document(
            new Element("e").addNodes(new Element("e2"), new Element("e2"), new Element("e2")));
    Element e = doc.getRootElement().getChild(2);
    assertEquals("/e/e2[2]", e.getChildPath());
  }

  @Test
  public void testGetChild() throws Exception {
    Element e = new Element("e");
    assertEquals(e, e.getChild(""));
  }

  @Test
  public void testGetChild2() throws Exception {
    Element e = new Element("e");
    assertEquals(e, e.getChild("."));
  }

  @Test
  public void testGetChild3() throws Exception {
    Element e = new Element("e");
    assertNull(e.getChild("/e"));
  }

  @Test
  public void testGetChild4() throws Exception {
    Element e = new Element("e");
    assertNull(e.getChild("x"));
  }

  @Test
  public void testGetChild5() throws Exception {
    Element e = new Element("e");
    Element e2 = new Element("e2");
    e.addNode(e2);
    assertEquals(e2, e.getChild("e2"));
  }

  @Test
  public void testGetChild6() throws Exception {
    Element e = new Element("e");
    Element e2 = new Element("e2");
    e.addNode(e2);
    Element e3 = new Element("e3");
    e2.addNode(e3);
    assertEquals(e3, e.getChild("e2/e3"));
  }

  @Test
  public void testGetChild7() throws Exception {
    Element e = new Element("e");
    Element e2 = new Element("e2");
    e.addNode(e2);
    Element e3 = new Element("e3");
    e2.addNode(e3);
    assertEquals(e3, e.getChild("e2[0]/e3"));
  }

  @Test
  public void testGetChild8() throws Exception {
    Element e = new Element("e");
    Element e2 = new Element("e2");
    e.addNode(e2);
    Element e3_1 = new Element("e3");
    e2.addNode(e3_1);
    Element e3_2 = new Element("e3");
    e2.addNode(e3_2);
    assertEquals(e3_2, e.getChild("e2/e3[1]"));
  }

  @Test
  public void testGetChild9() throws Exception {
    Document doc = new Document();
    Element e = new Element("e");
    doc.addNode(e);
    Element e2 = new Element("e2");
    e.addNode(e2);
    Element e3_1 = new Element("e3");
    e2.addNode(e3_1);
    Element e3_2 = new Element("e3");
    e2.addNode(e3_2);
    assertEquals(e3_2, e.getChild("/e/e2/e3[1]"));
  }

  @Test
  public void testGetChild10() throws Exception {
    Document doc = new Document();
    Element e = new Element("e");
    doc.addNode(e);
    Element e2 = new Element("e2");
    e.addNode(e2);
    Element e3_1 = new Element("e3");
    e2.addNode(e3_1);
    Element e3_2 = new Element("e3");
    e2.addNode(e3_2);
    assertEquals(e3_2, e.getChild("/e/e2/e3[1]"));
  }

  @Test
  public void testGetChild11() throws Exception {
    Document doc = new Document();
    Element e = new Element("e");
    doc.addNode(e);
    Element e2 = new Element("e2");
    e.addNode(e2);
    Element e3_1 = new Element("e3");
    e2.addNode(e3_1);
    Element e3_2 = new Element("e3");
    e2.addNode(e3_2);
    assertEquals(e, e3_2.getChild("/e"));
  }

  @Test
  public void testGetChild12() throws Exception {
    Element e = new Element("e");
    try {
      e.getChild(0);
      fail("No exception was thrown");
    } catch (IndexOutOfBoundsException ex) {
      assertEquals("Cannot return child 0, node has only 0 children", ex.getMessage());
    }
  }

  @Test
  public void testGetChild13() throws Exception {
    Element e = new Element("e");
    try {
      e.getChild(-1);
      fail("No exception was thrown");
    } catch (IndexOutOfBoundsException ex) {
      assertEquals("Cannot return child -1, node has only 0 children", ex.getMessage());
    }
  }

  @Test
  public void testGetChild14() throws Exception {
    Element e = new Element("e").addNode(new Element("e2"));
    try {
      e.getChild(2);
      fail("No exception was thrown");
    } catch (IndexOutOfBoundsException ex) {
      assertEquals("Cannot return child 2, node has only 1 child", ex.getMessage());
    }
  }

  @Test
  public void testGetChild15() throws Exception {
    Element e = new Element("e").addNodes(new Element("e2"), new Element("e2"));
    try {
      e.getChild(3);
      fail("No exception was thrown");
    } catch (IndexOutOfBoundsException ex) {
      assertEquals("Cannot return child 3, node has only 2 children", ex.getMessage());
    }
  }

  @Test
  public void testGetChild16() throws Exception {
    Element e = new Element("e").addNode(new Element("e2"));
    assertEquals(e.getNode(0), e.getChild(0));
  }

  @Test
  public void testGetChild17() throws Exception {
    Document doc = new Document();
    assertNull(doc.getChild(null));
  }

  @Test
  public void testGetChild18() throws Exception {
    Document doc = new Document(new Element("e"));
    assertNull(doc.getChild("a"));
  }

  @Test
  public void testGetChild19() throws Exception {
    Document doc = new Document(new Element("e").addNode(new Element("e2")));
    assertNull(doc.getChild("a/e2"));
  }

  @Test
  public void testGetChild20() throws Exception {
    Document doc =
        new Document(
            new Element("e")
                .addNodes(
                    new Text(" "),
                    new Element("e2"),
                    new Text(" "),
                    new Element("e2"),
                    new Text(" ")));
    Element e = doc.getChild("e/e2[1]");
    assertNotNull(e);
    assertEquals("/e/e2[1]", e.getChildPath());
  }

  @Test
  public void testGetChild21() throws Exception {
    Document doc =
        new Document(
            new Element("e")
                .addNodes(
                    new Text(" "),
                    new Element("e2"),
                    new Text(" "),
                    new Element("e2"),
                    new Text(" ")));
    Element e = doc.getChild("e").getChild(1);
    assertNotNull(e);
    assertEquals("/e/e2[1]", e.getChildPath());
  }

  @Test
  public void testIndexOf() throws Exception {
    Element e = new Element("e").addNodes(new Text(" "), new Element("e2"));
    assertEquals(-1, e.nodeIndexOf(null));
    assertEquals(-1, e.nodeIndexOf(new Text(" ")));
    assertEquals(0, e.nodeIndexOf(e.getNode(0)));
    assertEquals(1, e.nodeIndexOf(e.getNode(1)));
  }

  @Test
  public void testIndexOf2() throws Exception {
    Element e = new Element("e");
    assertEquals(-1, e.nodeIndexOf(new Text(" ")));
  }

  @Test
  public void testIndexOf3() throws Exception {
    Element e = new Element("e");
    assertEquals(-1, e.childIndexOf(new Element("a")));
  }

  @Test
  public void testGetNode() throws Exception {
    Element e = new Element("e");
    try {
      e.getNode(0);
      fail("No exception was thrown");
    } catch (IndexOutOfBoundsException ex) {
      assertEquals("Cannot return child 0, node has only 0 child nodes", ex.getMessage());
    }
  }

  @Test
  public void testGetNode2() throws Exception {
    Element e = new Element("e");
    try {
      e.getNode(-1);
      fail("No exception was thrown");
    } catch (IndexOutOfBoundsException ex) {
      assertEquals("Cannot return child -1, node has only 0 child nodes", ex.getMessage());
    }
  }

  @Test
  public void testGetNode3() throws Exception {
    Element e = new Element("e").addNode(new Element("e2"));
    try {
      e.getNode(2);
      fail("No exception was thrown");
    } catch (IndexOutOfBoundsException ex) {
      assertEquals("Cannot return child 2, node has only 1 child nodes", ex.getMessage());
    }
  }

  @Test
  public void testGetNode4() throws Exception {
    Element e = new Element("e").addNodes(new Element("e2"), new Element("e2"));
    try {
      e.getNode(3);
      fail("No exception was thrown");
    } catch (IndexOutOfBoundsException ex) {
      assertEquals("Cannot return child 3, node has only 2 child nodes", ex.getMessage());
    }
  }

  @Test
  public void testGetNode5() throws Exception {
    Element e = new Element("e").addNodes(new Element("e2"), new Element("e2"));

    assertNotNull(e.getNode(1));
  }

  @Test
  public void testAddNodesCollection() throws Exception {
    Element parent = new Element("parent");
    List<Node> l = new ArrayList<Node>();
    l.add(new Element("child2"));
    parent.addNodes(0, l);

    l.clear();
    l.add(new Element("child1"));
    parent.addNodes(0, l);

    assertEquals("<parent><child1/><child2/></parent>", parent.toXML());
  }

  @Test
  public void testCopy() throws Exception {
    Element e =
        new Element("e").setAttribute("a", "v").addNodes(new Element("e2"), new Element("e2"));

    Element copy = e.copy();
    assertEquals(e.toXML(), copy.toXML());
  }
}
