Parent should provide the child node at the given offset.

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
index 26d3bab..58e58e1 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
@@ -10,6 +10,7 @@
 import java.util.Iterator;

 import java.util.List;

 

+import org.eclipse.core.runtime.AssertionFailedException;

 import org.junit.Before;

 import org.junit.Test;

 

@@ -375,6 +376,52 @@
 		assertTextNodeEquals(" World", 23, 28, childNodes.get(3));

 	}

 

+	@Test

+	public void shouldProvideSelfOnOwnBoundaries() throws Exception {

+		assertSame(parent, parent.getChildNodeAt(parent.getStartOffset()));

+		assertSame(parent, parent.getChildNodeAt(parent.getEndOffset()));

+	}

+

+	@Test

+	public void shouldReturnTextWithinBoundaries() throws Exception {

+		content.insertText(parent.getEndOffset(), "Hello World");

+		final Node text = parent.getChildNodes().get(0);

+		assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getStartOffset()));

+		assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getStartOffset() + 1));

+		assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getEndOffset() - 1));

+		assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getEndOffset()));

+	}

+

+	@Test

+	public void shouldReturnTextWithinChildBoundaries() throws Exception {

+		final int offset = parent.getEndOffset();

+		content.insertElementMarker(offset);

+		content.insertElementMarker(offset);

+		final Element child = new Element("child");

+		parent.addChild(child);

+		child.associate(content, offset, offset + 1);

+		content.insertText(child.getEndOffset(), "Hello World");

+		final Node text = child.getChildNodes().get(0);

+		assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getStartOffset()));

+		assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getStartOffset() + 1));

+		assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getEndOffset() - 1));

+		assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getEndOffset()));

+	}

+

+	@Test(expected = AssertionFailedException.class)

+	public void shouldNotProvideChildNodeBeforeStartOffset() throws Exception {

+		content.insertText(parent.getStartOffset(), "prefix");

+		parent.getChildNodeAt(parent.getStartOffset() - 1);

+

+	}

+

+	@Test(expected = AssertionFailedException.class)

+	public void shouldNotProvideChildNodeAfterEndOffset() throws Exception {

+		content.insertText(parent.getEndOffset() + 1, "suffix");

+		parent.getChildNodeAt(parent.getEndOffset() + 1);

+

+	}

+

 	private static void assertTextNodeEquals(final String text, final int startOffset, final int endOffset, final Node actualNode) {

 		assertTrue(actualNode instanceof Text);

 		assertEquals(text, actualNode.getText());

diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java
index e007fcf..6e44949 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java
@@ -15,6 +15,8 @@
 import java.util.Iterator;

 import java.util.List;

 

+import org.eclipse.core.runtime.Assert;

+

 /**

  * A Parent node is a Node which can contain other nodes as children. This class defines the tree-like structure of the

  * DOM. It handles the mergin of the child nodes and the textual content of one node within the structure of the

@@ -159,6 +161,28 @@
 	}

 

 	/**

+	 * Returns the node at the given offset.

+	 * 

+	 * @param offset

+	 *            the offset

+	 * @return the node at the given offset

+	 */

+	public Node getChildNodeAt(final int offset) {

+		Assert.isTrue(containsOffset(offset));

+		final List<Node> childNodes = getChildNodes();

+		for (final Node child : childNodes) {

+			if (child.containsOffset(offset)) {

+				if (child instanceof Parent) {

+					return ((Parent) child).getChildNodeAt(offset);

+				} else {

+					return child;

+				}

+			}

+		}

+		return this;

+	}

+

+	/**

 	 * Indicates if this parent node has child nodes. Text nodes are ignored, i.e. this method will return false if this

 	 * parent node contains only text.

 	 *