public class FixedTableGhost implements Dictionary {
  protected /*@ spec_public non_null */ Object[] keyObjects;
  protected /*@ spec_public non_null */ Object[] storedObjects;
  //@ invariant \typeof(keyObjects) == \type(Object[]);
  //@ invariant \typeof(storedObjects) == \type(Object[]);

  protected int nextFree;
  //@ invariant this.nextFree >= 0 && this.nextFree <= MAX_TABLE_SIZE;

  protected static final int MAX_TABLE_SIZE = 10;
  //@ invariant MAX_TABLE_SIZE == storedObjects.length;
  //@ invariant MAX_TABLE_SIZE == keyObjects.length;

  //@ invariant keyObjects != storedObjects;

  //@ ghost public int found_loc;

  /*@ 
        ensures nextFree == 0;
        ensures \fresh(keyObjects);
        ensures \fresh(storedObjects);
   */
  public FixedTableGhost() {
    keyObjects = new Object[MAX_TABLE_SIZE];
    storedObjects = new Object[MAX_TABLE_SIZE];
    nextFree = 0;
  }

  /*@ 
       also_modifies keyObjects, storedObjects, nextFree;

       also_exsures (DictionaryException) 
                    keyObject==null || storedObject==null || 
                    nextFree==MAX_TABLE_SIZE;

       also_ensures found_loc <= \old(nextFree);
       also_ensures found_loc < \old(nextFree) 
                     ==> nextFree == \old(nextFree); 
       also_ensures 
         found_loc == \old(nextFree) ==> nextFree == \old(nextFree)+1;
       also_ensures keyObjects[found_loc] == keyObject;
       also_ensures storedObjects[found_loc] == storedObject;
       also_ensures (\forall int i; 0 <= i && i < found_loc ==> 
                     keyObjects[i] != keyObject);
       also_ensures (\forall int i; 0 <= i && i < nextFree && i!=found_loc==>
                     (keyObjects[i] == \old(keyObjects[i])) &&
		     (storedObjects[i] == \old(storedObjects[i])));
   */
  public void put(Object storedObject, Object keyObject) 
         throws DictionaryException {
    if (keyObject == null) 
      throw new DictionaryException("put: null Key"); 

    if (storedObject == null) 
      throw new DictionaryException("put: null Object"); 

    boolean found = false;

    //@ set found_loc = 0;
    /*@ loop_invariant (\forall int j; 0<=j && j<found_loc && !found ==> 
                                       keyObjects[j]!=keyObject); 
     */
    for (int i=0; !found && i<nextFree; i++) {
      //@ set found_loc = i;
      if (keyObjects[i] == keyObject) {
        found=true;
        storedObjects[i] = storedObject; 
      }
    }

    if (!found) {
      if (nextFree == MAX_TABLE_SIZE) 
        throw new DictionaryException("put: table full"); 

      keyObjects[nextFree] = keyObject;  
      storedObjects[nextFree] = storedObject;  
      //@ set found_loc = nextFree;
      nextFree++;
    }
  }


  /*@ 
        also_ensures 
          (\exists int i; 0 <= i && i < nextFree &&
                          keyObject == keyObjects[i] &&
                          \result == storedObjects[i])
          ||
          \result == null;
        also_exsures (DictionaryException) keyObject==null;
   */
  public Object get(Object keyObject) throws DictionaryException {
    if (keyObject == null) throw new DictionaryException("get: null Key"); 

    for (int i=0; i<nextFree; i++) {
      if (keyObjects[i] == keyObject) return storedObjects[i];    
    }

    return null;
  }

  /*@
        also_ensures \result ==> (\exists int i; 0 <= i && i < nextFree ==>
                                                 keyObject == keyObjects[i]) &&
                     (\exists int i; 0 <= i && i < nextFree ==>
                                     keyObject == keyObjects[i]) ==> \result; 
        also_exsures (DictionaryException) keyObject==null;
   */
  public boolean hasKey(Object keyObject) throws DictionaryException {
    if (keyObject == null) throw new DictionaryException("hasKey: null Key"); 

    for (int i=0; i<nextFree; i++) {
      if (keyObjects[i] == keyObject) return true;    
    }

    return false;
  } 
}

  
