title: Bouncing shape nested in another shape (What is wrong with this code)
body: <p>I have an application that bounces <code>Shapes</code> around inside a JPanel. Whenever shapes hit a side they will bounce off in the other direction. I am trying to add a new shape called a <code>NestingShape</code> that contains zero or more <code>Shapes</code> that bounce around inside it, while the <code>NestingShape</code> bounces around in the JPanel. The children of a <code>NestingShape</code> instance can be either simple <code>Shapes</code> or other <code>NestingShape</code> instances.</p>
  
  <p>Right now I am having trouble with moving the children of a <code>NestingShape</code> within a <code>NestingShape</code> with the <code>move(width, height)</code> method in the NestingShape subclass. I am also having trouble with developing a method in the <code>Shape</code> superclass that can find the parent any given shape. I'll copy and paste the code I have come up with so far for the <code>Shape</code> superclass and <code>NestingShape</code> subclass below and the test cases I am using to test the code so far:</p>
  
  <p><code>Shape</code> superclass:</p>
  
  <p>NOTE: parent() and path() methods are the most relevant methods for this task and the parent() method is the one I'm having trouble implementing. There are a lot of little details such as <code>fFill</code> and <code>count</code> and such that are related to different <code>Shapes</code> that I have developed, and those can be ignored.</p>
  
  <pre><code>package bounce;
  
  import java.awt.Color;
  import java.util.List;
  
  /**
   * Abstract superclass to represent the general concept of a Shape. This class
   * defines state common to all special kinds of Shape instances and implements
   * a common movement algorithm. Shape subclasses must override method paint()
   * to handle shape-specific painting.
   * 
   * @author wadfsd
   *
   */
  public abstract class Shape {
      // === Constants for default values. ===
      protected static final int DEFAULT_X_POS = 0;
  
      protected static final int DEFAULT_Y_POS = 0;
  
      protected static final int DEFAULT_DELTA_X = 5;
  
      protected static final int DEFAULT_DELTA_Y = 5;
  
      protected static final int DEFAULT_HEIGHT = 35;
  
      protected static final int DEFAULT_WIDTH = 25;
  
      protected static final Color DEFAULT_COLOR = Color.black;
  
      protected static final String DEFAULT_STRING = "";
      // ===
  
      // === Instance variables, accessible by subclasses.
      protected int fX;
  
      protected int fY;
  
      protected int fDeltaX;
  
      protected int fDeltaY;
  
      protected int fWidth;
  
      protected int fHeight;
  
      protected boolean fFill;
  
      protected Color fColor;
  
      protected int count;
  
      protected int fState;
  
      protected int before;
  
      protected String fString;
      // ===
  
      /**
       * Creates a Shape object with default values for instance variables.
       */
      public Shape() {
          this(DEFAULT_X_POS, DEFAULT_Y_POS, DEFAULT_DELTA_X, DEFAULT_DELTA_Y, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_COLOR, DEFAULT_STRING);
      }
  
      /**
       * Creates a Shape object with a specified x and y position.
       */
      public Shape(int x, int y) {
          this(x, y, DEFAULT_DELTA_X, DEFAULT_DELTA_Y, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_COLOR, DEFAULT_STRING);
      }
  
      public Shape(int x, int y, String str) {
          this(x, y, DEFAULT_DELTA_X, DEFAULT_DELTA_Y, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_COLOR, str);
      }
  
      /**
       * Creates a Shape object with specified x, y, and color values.
       */
      public Shape(int x, int y, Color c) {
          this(x, y, DEFAULT_DELTA_X, DEFAULT_DELTA_Y, DEFAULT_WIDTH, DEFAULT_HEIGHT, c, DEFAULT_STRING);
      }
  
      public Shape(int x, int y, Color c, String str) {
          this(x, y, DEFAULT_DELTA_X, DEFAULT_DELTA_Y, DEFAULT_WIDTH, DEFAULT_HEIGHT, c, str);
      }
  
      /**
       * Creates a Shape instance with specified x, y, deltaX and deltaY values.
       * The Shape object is created with a default width, height and color.
       */
      public Shape(int x, int y, int deltaX, int deltaY) {
          this(x, y, deltaX, deltaY, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_COLOR, DEFAULT_STRING);
      }
  
      public Shape(int x, int y, int deltaX, int deltaY, String str) {
          this(x, y, deltaX, deltaY, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_COLOR, str);
      }
  
      /**
       * Creates a Shape instance with specified x, y, deltaX, deltaY and color values.
       * The Shape object is created with a default width and height.
       */
      public Shape(int x, int y, int deltaX, int deltaY, Color c) {
          this(x, y, deltaX, deltaY, DEFAULT_WIDTH, DEFAULT_HEIGHT, c, DEFAULT_STRING);
      }
  
      public Shape(int x, int y, int deltaX, int deltaY, Color c, String str) {
          this(x, y, deltaX, deltaY, DEFAULT_WIDTH, DEFAULT_HEIGHT, c, str);
      }
  
      /**
       * Creates a Shape instance with specified x, y, deltaX, deltaY, width and
       * height values. The Shape object is created with a default color.
       */
      public Shape(int x, int y, int deltaX, int deltaY, int width, int height) {
          this(x, y, deltaX, deltaY, width, height, DEFAULT_COLOR, DEFAULT_STRING);
      }
  
      public Shape(int x, int y, int deltaX, int deltaY, int width, int height, String str) {
          this(x, y, deltaX, deltaY, width, height, DEFAULT_COLOR, str);
      }
  
      public Shape(int x, int y, int deltaX, int deltaY, int width, int height, Color c) {
          this(x, y, deltaX, deltaY, width, height, c, DEFAULT_STRING);
      }
  
      /**
       * Creates a Shape instance with specified x, y, deltaX, deltaY, width,
       * height and color values.
       */
      public Shape(int x, int y, int deltaX, int deltaY, int width, int height, Color c, String str) {
          fX = x;
          fY = y;
          fDeltaX = deltaX;
          fDeltaY = deltaY;
          fWidth = width;
          fHeight = height;
          fFill = false;
          fColor = c;
          count = 0;
          fState = 1;
          before = 0;
          fString = str;
      }
  
      /**
       * Moves this Shape object within the specified bounds. On hitting a 
       * boundary the Shape instance bounces off and back into the two- 
       * dimensional world and logs whether a vertical or horizontal wall
       * was hit for the DynamicRectangleShape.
       * @param width width of two-dimensional world.
       * @param height height of two-dimensional world.
       */
      public void move(int width, int height) {
          int nextX = fX + fDeltaX;
          int nextY = fY + fDeltaY;
  
          if (nextY &lt;= 0) {
              nextY = 0;
              fDeltaY = -fDeltaY;
              fFill = false;
              count++;
          } else if (nextY + fHeight &gt;= height) {
              nextY = height - fHeight;
              fDeltaY = -fDeltaY;
              fFill = false;
              count++;
          }
  
          // When Shape hits a corner the vertical wall fFill value overrides the horizontal
          if (nextX &lt;= 0) {
              nextX = 0;
              fDeltaX = -fDeltaX;
              fFill = true;
              count++;
          } else if (nextX + fWidth &gt;= width) {
              nextX = width - fWidth;
              fDeltaX = -fDeltaX;
              fFill = true;
              count++;
          }
  
          fX = nextX;
          fY = nextY;
      }
  
      public void text(Painter painter, String str) {
          painter.drawCentredText(str, fX, fY, fWidth, fHeight);
      }
  
      /**
       * Returns the NestingShape that contains the Shape that method parent
       * is called on. If the callee object is not a child within a
       * NestingShape instance this method returns null.
       */
      public NestingShape parent() {
          // Related to NestingShape
      }
  
      /**
       * Returns an ordered list of Shape objects. The first item within the
       * list is the root NestingShape of the containment hierarchy. The last
       * item within the list is the callee object (hence this method always
       * returns a list with at least one item). Any intermediate items are
       * NestingShapes that connect the root NestingShape to the callee Shape.
       * E.g. given:
       * 
       *   NestingShape root = new NestingShape();
       *   NestingShape intermediate = new NestingShape();
       *   Shape oval = new OvalShape();
       *   root.add(intermediate);
       *   intermediate.add(oval);
       *   
       * a call to oval.path() yields: [root,intermediate,oval] 
       */
      public List&lt;Shape&gt; path() {
          // Related to NestingShape
      }
  
      /**
       * Method to be implemented by concrete subclasses to handle subclass
       * specific painting.
       * @param painter the Painter object used for drawing.
       */
      public abstract void paint(Painter painter);
  
      /**
       * Returns this Shape object's x position.
       */
      public int x() {
          return fX;
      }
  
      /**
       * Returns this Shape object's y position.
       */
      public int y() {
          return fY;
      }
  
      /**
       * Returns this Shape object's speed and direction.
       */
      public int deltaX() {
          return fDeltaX;
      }
  
      /**
       * Returns this Shape object's speed and direction.
       */
      public int deltaY() {
          return fDeltaY;
      }
  
      /**
       * Returns this Shape's width.
       */
      public int width() {
          return fWidth;
      }
  
      /**
       * Returns this Shape's height.
       */
      public int height() {
          return fHeight;
      }
  
      /**
       * Returns a String whose value is the fully qualified name of this class 
       * of object. E.g., when called on a RectangleShape instance, this method 
       * will return "bounce.RectangleShape".
       */
      public String toString() {
          return getClass().getName();
      }
  }
  </code></pre>
  
  <p><code>NestingShape</code> subclass:</p>
  
  <p>NOTE: Having trouble with the move() method</p>
  
  <pre><code>package bounce;
  
  import java.util.ArrayList;
  import java.util.List;
  
  public class NestingShape extends Shape {
      private List&lt;Shape&gt; nest = new ArrayList&lt;Shape&gt;();
  
      /**
       * Creates a NestingShape object with default values for state.
       */
      public NestingShape() {
          super();
      }
  
      /**
       * Creates a NestingShape object with specified location values, default values for other
       * state items.
       */
      public NestingShape(int x, int y) {
          super(x,y);
      }
  
      /**
       * Creates a NestingShape with specified values for location, velocity and direction.
       * Non-specified state items take on default values.
       */
      public NestingShape(int x, int y, int deltaX, int deltaY) {
          super(x,y,deltaX,deltaY);
      }
  
      /**
       * Creates a NestingShape with specified values for location, velocity, direction, width, and
       * height.
       */
      public NestingShape(int x, int y, int deltaX, int deltaY, int width, int height) {
          super(x,y,deltaX,deltaY,width,height);
      }
  
      /**
       * Moves a NestingShape object (including its children) with the bounds specified by arguments
       * width and height.
       */
      public void move(int width, int height) {   
          int nextX = fX + fDeltaX;
          int nextY = fY + fDeltaY;
  
          if (nextY &lt;= 0) {
              nextY = 0;
              fDeltaY = -fDeltaY;
              fFill = false;
              count++;
          } else if (nextY + fHeight &gt;= height) {
              nextY = height - fHeight;
              fDeltaY = -fDeltaY;
              fFill = false;
              count++;
          }
  
          if (nextX &lt;= 0) {
              nextX = 0;
              fDeltaX = -fDeltaX;
              fFill = true;
              count++;
          } else if (nextX + fWidth &gt;= width) {
              nextX = width - fWidth;
              fDeltaX = -fDeltaX;
              fFill = true;
              count++;
          }
  
          fX = nextX;
          fY = nextY;
  
          // Move children
          for (int i = 0; i &lt; shapeCount(); i++) {
              Shape shape = shapeAt(i);
  
              int nextXChild = shape.fX + shape.fDeltaX;
              int nextYChild = shape.fY + shape.fDeltaY;
  
              if (nextYChild &lt;= 0) {
                  nextYChild = 0;
                  shape.fDeltaY = -shape.fDeltaY;
              } else if (nextYChild + shape.fHeight &gt;= fHeight) {
                  nextYChild = fHeight - shape.fHeight;
                  shape.fDeltaY = -shape.fDeltaY;
              }
  
              if (nextXChild &lt;= 0) {
                  nextXChild = 0;
                  shape.fDeltaX = -shape.fDeltaX;
              } else if (nextXChild + fWidth &gt;= width) {
                  nextXChild = fWidth - shape.fWidth;
                  shape.fDeltaX = -shape.fDeltaX;
              }
  
              shape.fX = nextXChild;
              shape.fY = nextYChild;
          }
      }
  
      /**
       * Paints a NestingShape object by drawing a rectangle around the edge of its bounding box.
       * The NestingShape object's children are then painted.
       */
      public void paint(Painter painter) {
          painter.drawRect(fX,fY,fWidth,fHeight);
          painter.translate(fX,fY);
          for (int i = 0; i &lt; shapeCount(); i++) {
              Shape shape = shapeAt(i);
              shape.paint(painter);
          }
          painter.translate(0,0);
      }
  
      /**
       * Attempts to add a Shape to a NestingShape object. If successful, a two-way link is
       * established between the NestingShape and the newly added Shape. Note that this method
       * has package visibility - for reasons that will become apparent in Bounce III.
       * @param shape the shape to be added.
       * @throws IllegalArgumentException if an attempt is made to add a Shape to a NestingShape
       * instance where the Shape argument is already a child within a NestingShape instance. An
       * IllegalArgumentException is also thrown when an attempt is made to add a Shape that will
       * not fit within the bounds of the proposed NestingShape object.
       */
      void add(Shape shape) throws IllegalArgumentException {
          if (contains(shape)) {
              throw new IllegalArgumentException();
          } else if (shape.fWidth &gt; fWidth || shape.fHeight &gt; fHeight) {
              throw new IllegalArgumentException();
          } else {
              nest.add(shape);
          }
      }
  
      /**
       * Removes a particular Shape from a NestingShape instance. Once removed, the two-way link
       * between the NestingShape and its former child is destroyed. This method has no effect if
       * the Shape specified to remove is not a child of the NestingShape. Note that this method
       * has package visibility - for reasons that will become apparent in Bounce III.
       * @param shape the shape to be removed.
       */
      void remove(Shape shape) {
          int index = indexOf(shape);
          nest.remove(index);
      }
  
      /**
       * Returns the Shape at a specified position within a NestingShape. If the position specified
       * is less than zero or greater than the number of children stored in the NestingShape less
       * one this method throws an IndexOutOfBoundsException.
       * @param index the specified index position.
       */
      public Shape shapeAt(int index) throws IndexOutOfBoundsException {
          if (index &lt; 0 || index &gt;= shapeCount()) {
              throw new IndexOutOfBoundsException();
          } else {
              Shape shape = nest.get(index);
              return shape;
          }
      }
  
      /**
       * Returns the number of children contained within a NestingShape object. Note this method is
       * not recursive - it simply returns the number of children at the top level within the callee
       * NestingShape object.
       */
      public int shapeCount() {
          int number = nest.size();
          return number;
      }
  
      /**
       * Returns the index of a specified child within a NestingShape object. If the Shape specified
       * is not actually a child of the NestingShape this method returns -1; otherwise the value
       * returned is in the range 0 .. shapeCount() - 1.
       * @param shape the shape whose index position within the NestingShape is requested.
       */
      public int indexOf(Shape shape) {
          int index = nest.indexOf(shape);
          return index;
      }
  
      /**
       * Returns true if the shape argument is a child of the NestingShape object on which this method
       * is called, false otherwise.
       */
      public boolean contains(Shape shape) {
          boolean child = nest.contains(shape);
          return child;
      }
  }
  </code></pre>
  
  <p><code>TestNestingShape</code> test cases:</p>
  
  <pre><code>package bounce;
  
  import java.util.List;
  
  import junit.framework.TestCase;
  
  /**
   * Class to test class NestingShape according to its specification.
   */
  public class TestNestingShape extends TestCase {
  
      private NestingShape topLevelNest;
      private NestingShape midLevelNest;
      private NestingShape bottomLevelNest;
      private Shape simpleShape;
  
      public TestNestingShape(String name) {
          super(name);
      }
  
      /**
       * Creates a Shape composition hierarchy with the following structure:
       *   NestingShape (topLevelNest)
       *     |
       *     --- NestingShape (midLevelNest)
       *           |
       *           --- NestingShape (bottomLevelNest)
       *           |
       *           --- RectangleShape (simpleShape)
       */
      protected void setUp() throws Exception {
          topLevelNest = new NestingShape(0, 0, 2, 2, 100, 100);
          midLevelNest = new NestingShape(0, 0, 2, 2, 50, 50);
          bottomLevelNest = new NestingShape(5, 5, 2, 2, 10, 10);
          simpleShape = new RectangleShape(1, 1, 1, 1, 5, 5);
  
          midLevelNest.add(bottomLevelNest);
          midLevelNest.add(simpleShape);
          topLevelNest.add(midLevelNest);
      }
  
      /**
       * Checks that methods move() and paint() correctly move and paint a 
       * NestingShape's contents.
       */
      public void testBasicMovementAndPainting() {
          Painter painter = new MockPainter();
  
          topLevelNest.move(500, 500);
          topLevelNest.paint(painter);
          assertEquals("(rectangle 2,2,100,100)(rectangle 2,2,50,50)(rectangle 7,7,10,10)(rectangle 2,2,5,5)", painter.toString());
      }
  
      /**
       * Checks that method add successfuly adds a valid Shape, supplied as 
       * argument, to a NestingShape instance. 
       */
      public void testAdd() {
          // Check that topLevelNest and midLevelNest mutually reference each other.
          assertSame(topLevelNest, midLevelNest.parent());
          assertTrue(topLevelNest.contains(midLevelNest));
  
          // Check that midLevelNest and bottomLevelNest mutually reference each other.
          assertSame(midLevelNest, bottomLevelNest.parent());
          assertTrue(midLevelNest.contains(bottomLevelNest));
      }
  
      /**
       * Check that method add throws an IlegalArgumentException when an attempt 
       * is made to add a Shape to a NestingShape instance where the Shape 
       * argument is already part of some NestingShape instance.
       */
      public void testAddWithArgumentThatIsAChildOfSomeOtherNestingShape() {
          try {
              topLevelNest.add(bottomLevelNest);
              fail();
          } catch(IllegalArgumentException e) {
              // Expected action. Ensure the state of topLevelNest and 
              // bottomLevelNest has not been changed.
              assertFalse(topLevelNest.contains(bottomLevelNest));
              assertSame(midLevelNest, bottomLevelNest.parent());
          }
      }
  
      /**
       * Check that method add throws an IllegalArgumentException when an attempt
       * is made to add a shape that will not fit within the bounds of the 
       * proposed NestingShape object.
       */
      public void testAddWithOutOfBoundsArgument() {
          Shape rectangle = new RectangleShape(80, 80, 2, 2, 50, 50);
  
          try {
              topLevelNest.add(rectangle);
              fail();
          } catch(IllegalArgumentException e) {
              // Expected action. Ensure the state of topLevelNest and 
              // rectangle has not been changed.
              assertFalse(topLevelNest.contains(rectangle));
              assertNull(rectangle.parent());
          }
      }
  
      /**
       * Check that method remove breaks the two-way link between the Shape 
       * object that has been removed and the NestingShape it was once part of.
       */
      public void testRemove() {
          topLevelNest.remove(midLevelNest);
          assertFalse(topLevelNest.contains(midLevelNest));
          assertNull(midLevelNest.parent());
      }
  
      /**
       * Check that method shapeAt returns the Shape object that is held at a
       * specified position within a NestingShape instance.
       */
      public void testShapeAt() {
          assertSame(midLevelNest, topLevelNest.shapeAt(0));
      }
  
      /**
       * Check that method shapeAt throws a IndexOutOfBoundsException when called
       * with an invalid index argument.
       */
      public void testShapeAtWithInvalidIndex() {
          try {
              topLevelNest.shapeAt(1);
              fail();
          } catch(IndexOutOfBoundsException e) {
              // Expected action.
          }
      }
  
      /**
       * Check that method shapeCount returns zero when called on a NestingShape
       * object without children.
       */
      public void testShapeCountOnEmptyParent() {
          assertEquals(0, bottomLevelNest.shapeCount());
      }
  
      /**
       * Check that method shapeCount returns the number of children held within 
       * a NestingShape instance - where the number of children &gt; 0.
       */
      public void testShapeCountOnNonEmptyParent() {
          assertEquals(2, midLevelNest.shapeCount());
      }
  
      /**
       * Check that method indexOf returns the index position within a
       * NestingShape instance of a Shape held within the NestingShape. 
       */
      public void testIndexOfWith() {
          assertEquals(0, topLevelNest.indexOf(midLevelNest));
          assertEquals(1, midLevelNest.indexOf(simpleShape));
      }
  
      /**
       * Check that method indexOf returns -1 when called with an argument that
       * is not part of the NestingShape callee object.
       */
      public void testIndexOfWithNonExistingChild() {
          assertEquals(-1, topLevelNest.indexOf(bottomLevelNest));
      }
  
      /**
       * Check that Shape's path method correctly returns the path from the root
       * NestingShape object through to the Shape object that path is called on.
       */
      public void testPath() {
          List&lt;Shape&gt; path = simpleShape.path();
  
          assertEquals(3, path.size());
          assertSame(topLevelNest, path.get(0));
          assertSame(midLevelNest, path.get(1));
          assertSame(simpleShape, path.get(2));
      }
  
      /**
       * Check that Shape's path method correctly returns a singleton list
       * containing only the callee object when this Shape object has no parent.
       */
      public void testPathOnShapeWithoutParent() {
          List&lt;Shape&gt; path = topLevelNest.path();
  
          assertEquals(1, path.size());
          assertSame(topLevelNest, path.get(0));
      }
  }
  </code></pre>
  
  <p>With the code I have so far when I run the test cases, I am unable to test the testAdd and testRemove related  test cases to make sure I'm adding shapes properly because I haven't yet developed the <code>parent()</code> method in the <code>Shape</code> class. But I can't think of a way of implementing the parent method.</p>
  
  <p>Whenever I <code>testBasicMovementAndPainting</code>, I also get a failed test because my current <code>move()</code> method (in the NestingShape class) only moves the children in the first <code>NestingShape</code> and doesn't move the children of the midLevelNest.</p>
  
  <p>It's a bit of a long read and I'm not sure if that provides enough context as there are a lot of other classes in the package that I didn't include but if anyone could help I would really appreciate it.</p>
  
  <p>Thanks.</p>