import Array;
import IncomparableException;
import NotFoundException;
import java.util.Comparator;

/**
 * Utilities for searching through arrays.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of October 2000
 */
public class Searcher {

  /**
   * Determine if an array is in the order specified by a comparator.
   * Returns:
   *   True, if the array is in order.
   *   False, otherwise
   * Pre: 
   *   The comparator is able to compare all pairs of elements.
   * Post:
   *   Does not affect the array.
   *
   * @exception IncomparableException
   *   If any pair of elements cannot be compared.
   */
  public static boolean inorder(Array stuff, Comparator order) 
    throws IncomparableException
  {
    // Prepare to handle the exceptions thrown by compare.
    try {
      int length = stuff.size();
      for (int pos = 2; pos < length; pos++) {
        // If two things are out of order
        if (order.compare(stuff.get(pos-1), stuff.get(pos)) > 0) {
          // The array is not in order.
          return false;
        } // if two things are out of order
      } // for
    } // try
    // Whoops, we couldn't compare two things.
    catch (ClassCastException e) {
      throw new IncomparableException();
    } // catch
    // Hmmm ... we've gotten this far, so everything must be in order.
    return true;
  }  // inorder(Array, Comparator)

  /**
   * Search for the position of a value in an array using
   * a comparator to determine equality.
   * Pre: All values in the array can be compared to the given
   *      value using the given comparator.
   * Post: Returns an equal value, if there is one.
   *       Throws an exception if the equal value is not there.
   *
   * @exception IncomparableException
   *   If the comparator can't be used on some pair.
   * @exception NotFoundException
   *   If the value is not in the array.
   */
  public static Object sequentialSearch(Object value, Array stuff, 
                                        Comparator order)
    throws IncomparableException, NotFoundException
  {
    int length = stuff.size();
    // Look at each element.
    for (int i = 0; i < length; i++) {
      // If it matches, we're done.
      if (order.compare(value, stuff.get(i)) == 0) {
        return stuff.get(i);
      }
    } // for
    // Hmmm ... it must not be there.
    throw new NotFoundException();
  } // sequentialSearch(Object, Array, Comparator)

  /**
   * Search for the position of a value in a sorted array using
   * a comparator to determine equality.
   * Pre: All values in the array can be compared to the given
   *      value using the given comparator.
   *      All values in the array are ordered in increasing order
   *      by the comparator.
   * Post: Returns the index of the equal value, if there is one.
   *       Throws an exception if the equal value is not there.
   *
   * @exception IncomparableException
   *   If the comparator can't be used on some pair.
   * @exception NotFoundException
   *   If the value is not in the array.
   */
  public static Object binarySearch(Object value, Array stuff, 
                                    Comparator order)
    throws IncomparableException, NotFoundException
  {
    // Determine the length of the array.
    int length = stuff.size();

    // If there's only one element in the array ...
    if (length == 1) {
      // See if it's what we're looking for.
      if (order.compare(value, stuff.get(0)) == 0) {
        // If so, return it.
        return stuff.get(0);
      }
      else {
        // If not, give up.
        throw new NotFoundException();
      }
    } // only one element in the array

    // If there are multiple elements in the array ...
    else {
      // Compare to the middle element.
      int comp = order.compare(value,stuff.get(length/2));
      // Equal: We're done.
      if (comp == 0) {
        return stuff.get(length/2);
      }
      // Value is smaller; Search the left half.
      else if (comp < 0) {
        return binarySearch(value, new Array(stuff, 0, length/2), order);
      }
      // Value is larger: Search the right half.
      else {
        return binarySearch(value, new Array(stuff, length/2, length-1), order);
      }
    } // multiple elements in the array
  } // binarySearch(Object, Array, Comparator)
} // class Searcher

