/**
 * A container for items and characters. Items and characters can be added, deleted, and searched
 * for by item or character type. 
 */
public class Container{
  private int size;
  private Thing[] contents;
  private static final int INITIAL_CAPACITY = 4;
  /**
   * Create an empty container.
   *
   */
  public Container() {
    contents = new Thing[INITIAL_CAPACITY];
  }
  
  protected void copy(Thing[] from, Thing[] to, int count) {
    for (int i = 0; i < count; i++)
      to[i] = from[i];
  }
  
  public void empty(){
    contents = new Thing[INITIAL_CAPACITY];
    size = 0;
  }
  
  /**
   * Find a thing in this container.
   *
   * @param thing a thing to find
   * @return the index of <code> thing </code> in this container
   */
  public int find(Thing thing) {
    for (int i = 0; i < size; i++){
      if (contents[i] == thing)
        return i;
    }
    return -1;
  }
 /**
   * Get the contents (items and characters) in this container.
   *
   * @return a copy of the array of things in this container
   */
  public Thing[] getContents() {
    Thing[] tempContents = new Thing[size];
    copy(contents, tempContents, size);
    return tempContents;
  }

  /**
   * Add a thing to this container. Return false if the thing cannot be
   * added because it is already in the container, true otherwise. The
   * added thing's container is set to this container.
   *
   * @param thing thing to add
   * @return whether the thing was added
   */
  public boolean addThing(Thing thing) {
    int found = find(thing);
    if (found >= 0)
      return false;
    if (size == contents.length){
      Thing[] tempContents = new Thing[size + size/2];
      copy(contents, tempContents, size);
      contents = tempContents;
    }
    contents[size++] = thing;
    thing.setContainer(this);
    return true;
  }
   
 /**
   * Remove a thing from the container. Return true if the thing was in
   * the container, false otherwise. The removed thing's container is
   * set to <code>null</code>.
   *
   * @param thing a thing to remove
   * @return whether it was found and removed
   */
  public boolean removeThing(Thing thing) {
    int found = find(thing);
    if (found < 0)
      return false;
    for (int j = found + 1; j < size; j++){
      contents[j-1] = contents[j];
    }
    size--;
    thing.setContainer(null);
    return true;
  }
      
 /**
   * Find the ith thing (counting from 0 to one less than the number of
   * things of that type) of the given type in the container. Return
   * <code>null</code> if there is no such thing
   *
   * @param type a thing type
   * @param i the position of the thing
   * @return the thing found
   */
  public Thing findThing(ThingType type, int i) {
    Thing[] contents = getContents();
    for (int j = 0; j < size; j++){
      if (contents[j].getThingType() == type && i-- == 0)
        return contents[j];
    }
    return null;
  }
  
 /**
   * Count the number of things of a given type in the container.
   *
   * @param type the thing type
   * @return the number of things of that type
   */
  public int getNumberOfThingType(ThingType type) {
    int count = 0;
    Thing[] contents = getContents();
    for (int i = 0; i < size; i++){
      if (contents[i].getThingType() == type)
        count++;
    }
    return count;
  }
  
  /**
   * Get size (number of all things) in this container
   * 
   * @return the size of this container
   */
  public int getSize(){
    return size;
  }
    
  public String toString() {
    StringBuffer buf = new StringBuffer();
    int count = 0;
    ThingType[] types = ThingType.values();
    for (int i = 0; i < types.length; i++) {
      int n = getNumberOfThingType(types[i]);
      if (n > 0) {
        if (count > 0)
          buf.append(", ");
        buf.append(types[i].nThingsToString(n));
        count += n;
      }
    }
    if (count == 0)
      buf.append("nothing");
    return buf.toString();
  }
}
