// ShortSequence.java

/**
 * A sequence of short integers.
 * Encapsulates a growable array of <code>short</code>.
 */
public class ShortSequence  {

   /**  The growable array.  */
   private short[] numbers;

   /**  Number of data items in the array.  */
   private int lengthFilled = 0;

   /**
    * Creates an ShortSequence with the specified
    * initial capacity.
    *
    * @param initialCapacity the number of memory
    *          locations initially allocated to
    *          store short integer data.
    * @exception IllegalArgumentException if the
    *          specified initial capacity is negative.
    */
   public ShortSequence(int initialCapacity)
   {
      if ( initialCapacity < 0 )
         throw new IllegalArgumentException(
                            "ShortSequence initial capacity "
                            + initialCapacity
                            + ", must be >= 0.");

      numbers = new short[initialCapacity];
   }  // constructor ShortSequence(int)

   /**
    * Gets the number of short integers currently
    * stored in this ShortSequence.
    *
    * @return the number of short elements.
    */
   public int getLengthFilled()  { return lengthFilled; }

   /**
    * Gets the number of short integers this
    * ShortSequence can store without a reallocation.
    *
    * @return the current capacity
    */
   public int getCapacity()  { return numbers.length; }

   /**
    * Gets the short integer stored at the specified
    * index.
    *
    * @param index the index of the desired data element.
    *        The index must be must be >= 0, and less
    *        than the number of elements currently stored.
    * @return the number stored at index, if index
    *        is within range.
    * @exception IndexOutOfBoundsException if index
    *        is out of range.
    */
   public short getNumberAt(int index)
   {
      if ( index < 0 || index >= lengthFilled )
         throw new IndexOutOfBoundsException(
                            "ShortSequence index " + index
                            + " must be >=0 and < "
                            + lengthFilled + ".");

      return numbers[index];
   }  //method getNumberAt(int)

   /**
    * Appends a short integer data element to this
    * ShortSequence.
    *
    * @param data the data element to be appended.
    */
   public void append(short data)
   {
      if ( lengthFilled >= numbers.length )
         ensureCapacity( lengthFilled + 10 );
      numbers[lengthFilled++] = data;
   }  // method append(short)

   /**
    * Ensures that the capacity is at least the
    * specified minimum, reallocating storage if
    * necessary.  The new capacity will be the
    * larger of (1) the specified minumum and
    * (2) twice the current number of stored
    * elements plus 10.
    * 
    * @param the desired minimum new capacity.
    */
   public void ensureCapacity(int minimumCapacity)   
   {
      int newCapacity = Math.max( minimumCapacity,
                                  2 * lengthFilled + 10 );
      short[] temp = new short[newCapacity];
      for ( int i = 0; i < lengthFilled; i++ )
         temp[i] = numbers[i];
      numbers = temp;
   }  // method ensureCapacity(int)

   /**
    * Inserts a short integer data item at the
    * specified position, if the position is within
    * range.  The data item previously at that
    * position, and all data items with higher
    * indices, move to make room for it.  If the
    * position is out of range, the data item is
    * not inserted or appended.
    *
    * @param index the position at which to insert the
    *           specified data item.  May range from 0 to
    *           the length of the filled portion minus 1.
    * @param data the data item to be inserted
    * @exception IndexOutOfBoundsException if the
    *        index is out of range.
    */
   public void insert(int index, short data)
   {
      if ( index < 0 || index >= lengthFilled )
         throw new IndexOutOfBoundsException(
                            "ShortSequence index " + index
                            + " must be >=0 and < "
                            + lengthFilled + ".");

      if ( lengthFilled == numbers.length )
         ensureCapacity(lengthFilled + 10);
      for ( int i = lengthFilled; i > index; i-- )
         numbers[i] = numbers[i-1];
      numbers[index] = data;
      lengthFilled++;
   }  // method insert(int, short)

   /**
    * Determines whether this ShortSequence is
    * equal in value to the parameter object.
    * They are equal if the parameter is of
    * class ShortSequence and the two objects
    * contain the same short integer values at
    * each index.
    *
    * @param other the object to be compared
    *          to this ShortSequence
    *
    * @return <code>true</code> if the parameter
    *        object is a ShortSequence containing
    *        the same numbers at each index as
    *        this ShortSequence, <code>false</code>
    *        otherwise.
    */
   public boolean equals(Object other)
   {
      if ( other == null 
              || getClass() != other.getClass()
              || lengthFilled != ((ShortSequence) other).lengthFilled )
          return false;
      for (int i = 0; i < lengthFilled; i++)
          if ( numbers[i] != ((ShortSequence) other).numbers[i] )
             return false;
      return true;
   }  // method equals

   /**
    * If a class defines the equals method, it must
    * also define a hashCode method such that
    * two objects that are "equal" according to the
    * equals method ALSO have the same hashCode.
    * 
    * @return the hash code
    */
   public int hashCode()
   {
      // Exact details are unimportant as long
      // as two "equal" objects have the same
      // hash code.  One simple implementation,
      // good enough for this course, would be:

      return toString().hashCode();

      // This is okay ONLY IF the toString method
      // has been defined in such a way that any
      // two objects of this class which are equal
      // according to the equals method also
      // return exactly equal strings when the
      // toString method is called.
      //
      // More typical implementations of the
      // hashCode method involve the instance
      // variables and addition and
      // multiplication by odd primes (for reasons
      // you'll learn about in a data structurs
      // course), as exemplified below:
      //
      // int code = 37;   // just some odd prime
      // for (int i = 0; i < lengthFilled; i++)
      // {
      //    code = 101 * code + numbers[i];
      //    // (101 is just another odd prime.)
      // }  // for i
      // return code;
      //
   }  // method hashCode

   /**
    * Returns a string representation of this
    * ShortSequence.
    *
    * @return a string beginning with "ShortSequence:"
    *         and then listing the numbers in this
    *         sequence on a single line of text.  If
    *         there are no numbers in the sequence,
    *         then the string returned is
    *         "ShortSequence: empty".
    */
   public String toString()
   {
      String s = "ShortSequence: ";
      if ( lengthFilled == 0 )
         s += " empty";
      else
         for ( int i = 0; i < lengthFilled; i++ )
            s += " " + numbers[i];
      return s;
   }  // method toString()
}  // class ShortSequence