/home/umdweb/cs4521/programming/pa1/Quicksort/src/sorts/Partitioner.java
package sorts;

import arraymodel.ArrayIndex;
import arraymodel.ArrayModel;
import arraymodel.IndexRange;
import display.Operation;
import java.awt.Color;

/**
 * A Partitioner is an array model operation that choses a pivot entry from the
 * array and partitions the array around the pivot.
 * This operation is used in a quicksort algorithm.
 * The quicksort algorithm sets the hi and lo indices of a partitioner by
 * invoking its setBounds() method before invoking its operate() method.
 * After invoking operate() the quicksort algorithm can determine the split
 * index for the partition by invoking the getSplitIndex() method.
 */
public class Partitioner
        implements Operation<ArrayModel> {

  int lo;
  int hi;
  int splitIndex;

  /**
   * p.setBounds(lo, hi) sets the endpoints of the segment that will be
   * partitioned by the p's operate() method.
   * @param lo the index of the first entry in the partitioned segment
   * @param hi the index of the entry just beyond the end of the partitioned
   * segment
   */
  public void setBounds(int lo, int hi) {
    this.lo = lo;
    this.hi = hi;
  }

  /**
   * p.operate(array) partitions array between the current bounds of p.
   * These bounds are set prior to invoking p.operate() by invoking
   * p.setBounds().
   * @param array the array to be partitioned
   */
  public void operate(ArrayModel array) {
    // The index range is used to control the coloring of the segments in the
    // array.  The portions of the array outside the range are colored gray.
    // The portion inside the range is colored orange.  However, when an
    // ArrayIndex is created it will cause a portion of the range to be colored
    // differently.
    IndexRange range = array.createIndexRange(lo, hi, Color.orange, Color.gray);
    // This causes the portion of the array from lo up to but not including the
    // value of geq to be colored yellow.  This ArrayIndex is initialized to lo,
    // so initially the yellow segment (entries less than the pivot) is empty.
    // You can send an ArrayIndex an increment() or decrement() message to
    // change its value.
    ArrayIndex geq = range.createIndex(lo, Color.yellow);
    // This causes the portion of the array from geq up to but not including unk
    // to be colored green.  This ArrayIndex is also initialized to lo, so
    // initially the green segment (entries greater than or equal to the pivot)
    // is empty.
    ArrayIndex unk = range.createIndex(lo, Color.green);
    // This causes the portion of the array from unk up to but not including end
    // to be colored light gray.  This ArrayIndex is initialized to hi - 1, so
    // initially the gray segment (unknown entries) covers all but the last
    // entry.
    ArrayIndex end = range.createIndex(hi - 1, Color.lightGray);
    // Use this to force display of the changes to the ArrayIndex objects.
    // These changes are not automatically displayed because it can make the
    // display confusing depending on the order of your ArrayIndex increments.
    array.showChanges();
    // Now set up for the partition loop.
    int pivotIndex = (lo + hi) / 2;
    Character pivotValue = array.get(pivotIndex);
    // This is how you swap two entries.  Note that for an ArrayIndex you get
    // its current value by sending it a get() message.
    // The array object will automatically display all swaps.
    array.swap(pivotIndex, end.get());
    while (unk.get() < end.get()) {
      Character unknownValue = array.get(unk.get());
      // FIXME - you fill in the rest of the code for the loop here.
      // Use unknownValue.compareTo(pivotValue) for comparison.

      // Use this to force display of the changes to the ArrayIndex objects.
      // These changes are not automatically displayed because it can make the
      // display confusing depending on the order of your ArrayIndex increments.
      array.showChanges();
    }
    array.swap(geq.get(), end.get());
    // The following lines are not essential to the algorithm.  They just make
    // the display at the end better.
    end.increment();
    unk.increment();
    array.showChanges();
    splitIndex = geq.get();
  }

  /**
   * p.getSplitIndex() returns the split index for the previous invokation of
   * p.operate().
   * The pivot should be located at this index.
   * All entries before the split index are less than the pivot.
   * All entries after the split index are greater than or equal to the pivot.
   * @return the split index
   */
  public int getSplitIndex() {
    // This is used by the quicksort operation.  It should be set at the end of
    // a partition.
    return splitIndex;
  }

  @Override
  public String toString() {
    // This is used for creating a menu item label for the operation.
    return "Partition(" + lo + ", " + hi + ")";
  }

}