/**
  * Create a clone of this ClientNodePath.
  *
  * @return A clone of this ClientNodePath.
  */
 @Override
 public synchronized ClientNodePath clone() {
   ClientNodePath clonedPath =
       new InternalClientNodePath(
           parent, editMode, closedPath, pathStyle != null ? pathStyle.clone() : null);
   for (ClientPathNode node : pathNodes) {
     node.clone(clonedPath);
   }
   return clonedPath;
 }
 /**
  * Get the IndexedPathNode with the specified label.
  *
  * @param label The label of the IndexedPathNode to be returned.
  * @return The IndexedPathNode with the specified label or null if no IndexedPathNode was found
  *     with that with that label.
  */
 @Override
 public ClientPathNode getPathNode(String label) {
   synchronized (pathNodes) {
     if (label != null) {
       for (ClientPathNode node : pathNodes) {
         if (label.equals(node.getName())) {
           return node;
         }
       }
     }
     return null;
   }
 }
 /** Remove all the ClientPathNodes in this PathCell. */
 @Override
 public void removeAllNodes() {
   synchronized (pathNodes) {
     if (!pathNodes.isEmpty()) {
       // ToDo synch UI with changes.
       ClientPathNode current = null;
       while (pathNodes.size() > 0) {
         current = pathNodes.remove(pathNodes.size() - 1);
         current.dispose();
       }
       parent.updatePathUI();
     }
   }
 }
 /** {@inheritDoc} */
 @Override
 public void getCoordRange(Vector3f min, Vector3f max) {
   for (ClientPathNode node : pathNodes) {
     if (min != null) {
       min.x = Math.min(min.x, node.getPosition().x);
       min.y = Math.min(min.y, node.getPosition().y);
       min.z = Math.min(min.z, node.getPosition().z);
     }
     if (max != null) {
       max.x = Math.max(max.x, node.getPosition().x);
       max.y = Math.max(max.y, node.getPosition().y);
       max.z = Math.max(max.z, node.getPosition().z);
     }
   }
 }
 /**
  * Set the IndexedPathNode position.
  *
  * @param index The index of the PathNode for which to set the position.
  * @param x The new X position of the PathNode.
  * @param y The new Y position of the PathNode.
  * @param z The new Z position of the PathNode.
  * @throws IndexOutOfBoundsException If the specified index of the PathNode to be updated was
  *     outside the valid range.
  */
 @Override
 public void setNodePosition(int index, float x, float y, float z)
     throws IndexOutOfBoundsException {
   synchronized (pathNodes) {
     if (index >= 0 && index < pathNodes.size()) {
       ClientPathNode node = pathNodes.get(index);
       node.getPosition().set(x, y, z);
       // Not working properly yet
       // parent.updateNodeUI(index, true);
       // Update the whole path as a temporary measure.
       parent.updatePathUI();
     } else {
       throw new IndexOutOfBoundsException(
           "The index of the PathNode to have its position updated was outside the valid range!");
     }
   }
 }
 /**
  * Add a new node to this PathCell.
  *
  * @param node The node to be added to this PathCell.
  * @return True if the node was able to be added successfully.
  */
 @Override
 public boolean addNode(ClientPathNode node) {
   synchronized (pathNodes) {
     if (node != null && pathNodes.add(node)) {
       node.setSequenceIndex(pathNodes.size() - 1);
       parent.updatePathUI();
       return true;
     } else {
       return false;
     }
   }
 }
 /**
  * Insert the specified ClientPathNode at the specified node index.
  *
  * @param nodeIndex The index at which the ClientPathNode is to be inserted. If the insertion
  *     index is the same as the number of nodes before insertion then the method is essentially
  *     like addNode except there is no ClientPathNode to be returned by the method in that case.
  * @param node The ClientPathNode to be inserted at the specified index.
  * @return The ClientPathNode which used to be at the specified index (if any).
  * @throws IndexOutOfBoundsException If the specified nodeIndex at which to insert the node is
  *     invalid.
  */
 @Override
 public ClientPathNode insertNode(int nodeIndex, ClientPathNode node)
     throws IllegalArgumentException, IndexOutOfBoundsException {
   synchronized (pathNodes) {
     if (node == null) {
       throw new IllegalArgumentException("The specified path node to be inserted was null!");
     } else {
       final int noOfNodes = pathNodes.size();
       if (nodeIndex >= 0 && nodeIndex <= noOfNodes) {
         if (nodeIndex == noOfNodes) {
           addNode(node);
           return null;
         } else {
           ClientPathNode previous = pathNodes.get(nodeIndex);
           pathNodes.add(nodeIndex, node);
           node.setSequenceIndex(nodeIndex);
           nodeIndex++;
           previous.setSequenceIndex(nodeIndex);
           nodeIndex++;
           // Use less than or equal as the number of nodes has gone up by one.
           while (nodeIndex <= noOfNodes) {
             pathNodes.get(nodeIndex).setSequenceIndex(nodeIndex);
             nodeIndex++;
           }
           parent.updatePathUI();
           return previous;
         }
       } else {
         throw new IndexOutOfBoundsException(
             String.format(
                 "The node index: %d at which the path node was to be inserted was outside the range of valid indices at which to insert! No of path nodes: %d.",
                 nodeIndex, pathNodes.size()));
       }
     }
   }
 }