refactor for more symmetry in MoveUp and MoveDown

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/boxes/FakeContentBox.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/boxes/FakeContentBox.java
index e7db0cb..c84f409 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/boxes/FakeContentBox.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/boxes/FakeContentBox.java
@@ -93,6 +93,14 @@
 		return getEndOffset() - getStartOffset() <= 1;
 	}
 
+	public boolean isAtStart(final int offset) {
+		return getStartOffset() == offset;
+	}
+
+	public boolean isAtEnd(final int offset) {
+		return getEndOffset() == offset;
+	}
+
 	@Override
 	public Rectangle getPositionArea(final Graphics graphics, final int offset) {
 		return area;
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IContentBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IContentBox.java
index eaf0b51..71af707 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IContentBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IContentBox.java
@@ -24,6 +24,10 @@
 
 	boolean isEmpty();
 
+	boolean isAtStart(int offset);
+
+	boolean isAtEnd(int offset);
+
 	Rectangle getPositionArea(Graphics graphics, int offset);
 
 	int getOffsetForCoordinates(Graphics graphics, int x, int y);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/MoveDown.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/MoveDown.java
index 30bb7d7..6d55ca4 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/MoveDown.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/MoveDown.java
@@ -21,6 +21,11 @@
 public class MoveDown implements ICursorMove {
 
 	@Override
+	public boolean preferX() {
+		return false;
+	}
+
+	@Override
 	public int calculateNewOffset(final Graphics graphics, final ContentMap contentMap, final int currentOffset, final IContentBox currentBox, final Rectangle hotArea, final int preferredX) {
 		if (isAtStartOfEmptyBox(currentOffset, currentBox)) {
 			return currentBox.getEndOffset();
@@ -29,30 +34,15 @@
 			return getFirstChild(currentBox).getStartOffset();
 		}
 
-		final int x = preferredX;
-		final int y = hotArea.getY() + hotArea.getHeight() - 1;
-		final IContentBox box = findClosestBoxBelow(contentMap, currentBox, x, y);
-		if (box.isEmpty()) {
-			return box.getStartOffset();
-		}
-		return box.getOffsetForCoordinates(graphics, x - box.getAbsoluteLeft(), y - box.getAbsoluteTop());
-	}
-
-	@Override
-	public boolean preferX() {
-		return false;
+		return findOffsetInNextBoxBelow(graphics, contentMap, currentBox, hotArea, preferredX);
 	}
 
 	private static boolean isAtStartOfEmptyBox(final int offset, final IContentBox box) {
-		return isAtStartOfBox(offset, box) && box.isEmpty();
+		return box.isAtStart(offset) && box.isEmpty();
 	}
 
 	private static boolean isAtStartOfBoxWithChildren(final int offset, final IContentBox box) {
-		return isAtStartOfBox(offset, box) && canHaveChildren(box);
-	}
-
-	private static boolean isAtStartOfBox(final int offset, final IContentBox box) {
-		return offset == box.getStartOffset();
+		return box.isAtStart(offset) && canHaveChildren(box);
 	}
 
 	private static boolean canHaveChildren(final IContentBox box) {
@@ -73,6 +63,18 @@
 		});
 	}
 
+	private static IContentBox getParent(final IContentBox childBox) {
+		return childBox.accept(new ParentTraversal<IContentBox>() {
+			@Override
+			public IContentBox visit(final NodeReference box) {
+				if (box == childBox) {
+					return super.visit(box);
+				}
+				return box;
+			}
+		});
+	}
+
 	private static IContentBox getFirstChild(final IContentBox parent) {
 		return parent.accept(new DepthFirstTraversal<IContentBox>() {
 			@Override
@@ -90,7 +92,17 @@
 		});
 	}
 
-	private static IContentBox findClosestBoxBelow(final ContentMap contentMap, final IContentBox currentBox, final int x, final int y) {
+	private int findOffsetInNextBoxBelow(final Graphics graphics, final ContentMap contentMap, final IContentBox currentBox, final Rectangle hotArea, final int preferredX) {
+		final int x = preferredX;
+		final int y = hotArea.getY() + hotArea.getHeight() - 1;
+		final IContentBox box = findNextBoxBelow(contentMap, currentBox, x, y);
+		if (box.isEmpty()) {
+			return box.getStartOffset();
+		}
+		return box.getOffsetForCoordinates(graphics, x - box.getAbsoluteLeft(), y - box.getAbsoluteTop());
+	}
+
+	private static IContentBox findNextBoxBelow(final ContentMap contentMap, final IContentBox currentBox, final int x, final int y) {
 		final Environment environment = contentMap.findEnvironmentForCoordinates(x, y, true);
 		final Neighbour neighbourBelow = environment.neighbours.getBelow();
 		if (neighbourBelow.box == null) {
@@ -116,19 +128,16 @@
 			}
 		});
 
-		return currentBox.accept(new BaseBoxVisitorWithResult<IContentBox>() {
+		return currentBox.accept(new ParentTraversal<IContentBox>() {
 			@Override
 			public IContentBox visit(final NodeReference box) {
-				if (box == getParent(boxBelow)) {
-					return boxBelow;
+				if (box == currentBox) {
+					return super.visit(box);
 				}
-				if (!isInLastLine(box, boxBelow)) {
-					return boxBelow;
+				if (containerBottomCloserThanNeighbourBelow(box, neighbourBelow, y)) {
+					return box;
 				}
-				if (boxBelow.isRightOf(x)) {
-					return boxBelow;
-				}
-				return getParent(box);
+				return boxBelow;
 			}
 
 			@Override
@@ -138,7 +147,6 @@
 				}
 				return getParent(box);
 			}
-
 		});
 	}
 
@@ -162,20 +170,8 @@
 		});
 	}
 
-	private static boolean isInLastLine(final IContentBox box, final IContentBox boxBelow) {
-		return !(getParent(box) == getParent(boxBelow));
+	private static boolean containerBottomCloserThanNeighbourBelow(final IContentBox box, final Neighbour neighbourBelow, final int y) {
+		final int distanceToContainerBottom = box.getAbsoluteTop() + box.getHeight() - y;
+		return distanceToContainerBottom <= neighbourBelow.distance;
 	}
-
-	private static IContentBox getParent(final IContentBox childBox) {
-		return childBox.accept(new ParentTraversal<IContentBox>() {
-			@Override
-			public IContentBox visit(final NodeReference box) {
-				if (box == childBox) {
-					return super.visit(box);
-				}
-				return box;
-			}
-		});
-	}
-
 }
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/MoveUp.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/MoveUp.java
index 9358eac..7ffe0b5 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/MoveUp.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/MoveUp.java
@@ -21,6 +21,11 @@
 public class MoveUp implements ICursorMove {
 
 	@Override
+	public boolean preferX() {
+		return false;
+	}
+
+	@Override
 	public int calculateNewOffset(final Graphics graphics, final ContentMap contentMap, final int currentOffset, final IContentBox currentBox, final Rectangle hotArea, final int preferredX) {
 		if (isAtEndOfEmptyBox(currentOffset, currentBox)) {
 			return currentBox.getStartOffset();
@@ -29,27 +34,15 @@
 			return getLastChild(currentBox).getEndOffset();
 		}
 
-		final int x = preferredX;
-		final int y = hotArea.getY();
-		final IContentBox box = findClosestBoxAbove(contentMap, currentBox, x, y);
-		return box.getOffsetForCoordinates(graphics, x - box.getAbsoluteLeft(), y - box.getAbsoluteTop());
-	}
-
-	@Override
-	public boolean preferX() {
-		return false;
+		return findOffsetInNextBoxAbove(graphics, contentMap, currentBox, hotArea, preferredX);
 	}
 
 	private static boolean isAtEndOfEmptyBox(final int offset, final IContentBox box) {
-		return isAtEndOfBox(offset, box) && box.isEmpty();
+		return box.isAtEnd(offset) && box.isEmpty();
 	}
 
 	private static boolean isAtEndOfBoxWithChildren(final int offset, final IContentBox box) {
-		return isAtEndOfBox(offset, box) && canHaveChildren(box);
-	}
-
-	private static boolean isAtEndOfBox(final int offset, final IContentBox box) {
-		return offset == box.getEndOffset();
+		return box.isAtEnd(offset) && canHaveChildren(box);
 	}
 
 	private static boolean canHaveChildren(final IContentBox box) {
@@ -70,6 +63,18 @@
 		});
 	}
 
+	private static IContentBox getParent(final IContentBox childBox) {
+		return childBox.accept(new ParentTraversal<IContentBox>() {
+			@Override
+			public IContentBox visit(final NodeReference box) {
+				if (box == childBox) {
+					return super.visit(box);
+				}
+				return box;
+			}
+		});
+	}
+
 	private static IContentBox getLastChild(final IContentBox parent) {
 		return parent.accept(new DepthFirstTraversal<IContentBox>() {
 			private IContentBox lastChild;
@@ -92,13 +97,16 @@
 		});
 	}
 
-	private static IContentBox findClosestBoxAbove(final ContentMap contentMap, final IContentBox currentBox, final int x, final int y) {
+	private int findOffsetInNextBoxAbove(final Graphics graphics, final ContentMap contentMap, final IContentBox currentBox, final Rectangle hotArea, final int preferredX) {
+		final int x = preferredX;
+		final int y = hotArea.getY();
+		final IContentBox box = findNextBoxAbove(contentMap, currentBox, x, y);
+		return box.getOffsetForCoordinates(graphics, x - box.getAbsoluteLeft(), y - box.getAbsoluteTop());
+	}
+
+	private static IContentBox findNextBoxAbove(final ContentMap contentMap, final IContentBox currentBox, final int x, final int y) {
 		final Environment environment = contentMap.findEnvironmentForCoordinates(x, y, true);
 		final Neighbour neighbourAbove = environment.neighbours.getAbove();
-		if (environment.deepestContainer == null) {
-			return currentBox;
-		}
-
 		if (neighbourAbove.box == null) {
 			final IContentBox parent = getParent(currentBox);
 			if (parent == null) {
@@ -112,10 +120,7 @@
 			public IContentBox visit(final NodeReference box) {
 				if (box.canContainText()) {
 					final IContentBox lastChild = deepestLastChild(box);
-					if (lastChild.isRightOf(x)) {
-						return lastChild;
-					}
-					if (lastChild.containsX(x)) {
+					if (!lastChild.isLeftOf(x)) {
 						return lastChild;
 					}
 				}
@@ -134,8 +139,7 @@
 				if (box == currentBox) {
 					return super.visit(box);
 				}
-				final int distanceToContainerTop = y - box.getAbsoluteTop();
-				if (distanceToContainerTop <= neighbourAbove.distance) {
+				if (containerTopCloserThanNeighbourAbove(box, neighbourAbove, y)) {
 					return box;
 				}
 				return boxAbove;
@@ -143,18 +147,6 @@
 		});
 	}
 
-	private static IContentBox getParent(final IContentBox childBox) {
-		return childBox.accept(new ParentTraversal<IContentBox>() {
-			@Override
-			public IContentBox visit(final NodeReference box) {
-				if (box == childBox) {
-					return super.visit(box);
-				}
-				return box;
-			}
-		});
-	}
-
 	private static IContentBox deepestLastChild(final IContentBox parentBox) {
 		return parentBox.accept(new DepthFirstTraversal<IContentBox>() {
 			private IContentBox lastChild;
@@ -178,4 +170,8 @@
 		});
 	}
 
+	private static boolean containerTopCloserThanNeighbourAbove(final IContentBox box, final Neighbour neighbourAbove, final int y) {
+		final int distanceToContainerTop = y - box.getAbsoluteTop();
+		return distanceToContainerTop <= neighbourAbove.distance;
+	}
 }
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/NodeReference.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/NodeReference.java
index fad1e40..4b446fa 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/NodeReference.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/NodeReference.java
@@ -185,14 +185,14 @@
 		return getEndOffset() - getStartOffset() <= 1;
 	}
 
-	public boolean isAtEnd(final int offset) {
-		return getEndOffset() == offset;
-	}
-
 	public boolean isAtStart(final int offset) {
 		return getStartOffset() == offset;
 	}
 
+	public boolean isAtEnd(final int offset) {
+		return getEndOffset() == offset;
+	}
+
 	@Override
 	public String toString() {
 		String result = "NodeReference{ ";
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TextContent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TextContent.java
index 225d48d..898aaf2 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TextContent.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TextContent.java
@@ -259,6 +259,14 @@
 		return getEndOffset() - getStartOffset() <= 1;
 	}
 
+	public boolean isAtStart(final int offset) {
+		return getStartOffset() == offset;
+	}
+
+	public boolean isAtEnd(final int offset) {
+		return getEndOffset() == offset;
+	}
+
 	@Override
 	public Rectangle getPositionArea(final Graphics graphics, final int offset) {
 		if (startPosition.getOffset() > offset || endPosition.getOffset() < offset) {