/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License. 
 *
 */
package Mini;

import java.util.Vector;

/**
 * For efficiency and convenience reasons we want our own hash table. It does
 * not conform to java.util.Dictionary(yet).
 *
 * That environment contains all function definitions and identifiers.
 * Hash keys are Strings (identifiers), which are mapped to a table index.
 *
 * The table consists of `SIZE' fields which have `SLOTS' subfields. Thus 
 * the maximum number of storable items is `SLOTS' * `SIZE'.
 *
 * @version $Id$
 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
 */
public class Environment implements Cloneable {
  private static final int SIZE  = 127; // Prime number large enough for most cases
  private static final int SLOTS = 3;   // Number of slots of each field
  
  private int       size;               // The table is an array of
  private Vector[]  table;              // Vectors
  private int       elements=0;

  public Environment(int size) {
    this.size = size;
    table     = new Vector[size];
  }

  private Environment(Vector[] table) {
    size       = table.length;
    this.table = table;
  }

  public Environment() {
    this(SIZE);
  }

  private final int hashCode(String key) {
    return Math.abs(key.hashCode()) % size;
  }

  /**
   * Inserts macro into table or overwrite old contents if it
   * was already stored.
   */
  public void put(EnvEntry obj) {
    int    hash;
    Vector v;
    String key = obj.getHashKey();

    hash = hashCode(key);
    v    = table[hash];

    elements++; // Count

    if(v == null) {
        table[hash] = v = new Vector(SLOTS);
    } else {
      try {
        int index = lookup(v, key);

        if(index >= 0) {
          v.setElementAt(obj, index); // Overwrite
          return;
        }
      } catch(ArrayIndexOutOfBoundsException e) {}
    }

    // Not found in Vector -> add it
    v.addElement(obj);
  }

  /** Get entry from hash table.
   */
  public EnvEntry get(String key) {
    int       hash;
    Vector    v;
    EnvEntry entry = null;

    hash = hashCode(key);
    v    = table[hash];

    if(v == null) {
        return null;
    }

    try {
      int index = lookup(v, key);

      if(index >= 0) {
        entry = (EnvEntry)v.elementAt(index);
    }
    } catch(ArrayIndexOutOfBoundsException e) {}

    return entry;
  }

  /**
   * Delete an object if it does exist.
   */
  public void delete(String key) {
    int       hash;
    Vector    v;

    hash = hashCode(key);
    v    = table[hash];

    if(v == null) {
        return;
    }

    try {
      int index = lookup(v, key);

      if(index >= 0) {
        elements--; // Count
        v.removeElementAt(index);
      }
    } catch(ArrayIndexOutOfBoundsException e) {}
  }

  private static final int lookup(Vector v, String key) 
       throws ArrayIndexOutOfBoundsException
  {
    int len = v.size();

    for(int i=0; i < len; i++) {
      EnvEntry entry = (EnvEntry)v.elementAt(i);

      if(entry.getHashKey().equals(key)) {
        return i;
    }
    }

    return -1;
  }

  @Override
  public Object clone() { 
    Vector[] copy = new Vector[size];

    for(int i=0; i < size; i++) {
      if(table[i] != null) {
        copy[i] = (Vector)table[i].clone(); // Copies references

        /*
        int len = table[i].size();

        copy[i] = new Vector(len);
        try {
          for(int j=0; j < len; j++)
            copy[i].addElement(table[i].elementAt(j));
        } catch(ArrayIndexOutOfBoundsException e) {}*/
      }
    }

    return new Environment(copy);
  }

  @Override
  public String toString() {
    StringBuffer buf = new StringBuffer();

    for(int i=0; i < size; i++) {
        if(table[i] != null) {
            buf.append(table[i] + "\n");
        }
    }

    return buf.toString();
  }

  public EnvEntry[] getEntries() {
    EnvEntry[] entries = new EnvEntry[elements];
    int        k       = 0;
    Vector     v;

    for(int i=0; i < size; i++) {
      if((v = table[i]) != null) {
        int len = v.size();
        try {
          for(int j=0; j < len; j++) {
        entries[k++] = (EnvEntry)v.elementAt(j);
    }
        } catch(ArrayIndexOutOfBoundsException e) {}  
      }
    }

    return entries;
  }
}

@@ -1631,16 +1631,26 @@
 e Vector
+%3CEnvEntry%3E
 %5B%5D  tabl
@@ -1676,16 +1676,16 @@
 Vectors%0A
-
   privat
@@ -1831,16 +1831,26 @@
 t(Vector
+%3CEnvEntry%3E
 %5B%5D table
@@ -2211,16 +2211,26 @@
   Vector
+%3CEnvEntry%3E
  v;%0A    
@@ -2394,16 +2394,26 @@
 w Vector
+%3CEnvEntry%3E
 (SLOTS);
@@ -2803,24 +2803,34 @@
 ;%0A    Vector
+%3CEnvEntry%3E
     v;%0A    E
@@ -3031,34 +3031,24 @@
     entry = 
-(EnvEntry)
 v.elementAt(
@@ -3247,24 +3247,34 @@
 ;%0A    Vector
+%3CEnvEntry%3E
     v;%0A%0A    
@@ -3596,16 +3596,26 @@
 p(Vector
+%3CEnvEntry%3E
  v, Stri
@@ -3753,26 +3753,16 @@
 entry = 
-(EnvEntry)
 v.elemen
@@ -3913,16 +3913,26 @@
   Vector
+%3CEnvEntry%3E
 %5B%5D copy 
@@ -4740,16 +4740,26 @@
   Vector
+%3CEnvEntry%3E
      v;%0A
@@ -4905,24 +4905,24 @@
 len; j++) %7B%0A
+
         entr
@@ -4936,18 +4936,8 @@
 %5D = 
-(EnvEntry)
 v.el

Fix up some generics warnings