package JavaAgent.resource.fopl;


import java.util.*;


/** 
 ** This class implements the foundations for symbolic programming in
 ** Java. At the moment a Symbol is basically a String that is its name.
 ** Using the Symbol class should be slightly more efficient than using 
 ** Strings and there may be extensions in future.
 ** <p> The cunning thing about Symbols is that there is only one Symbol
 ** with any given name. They are memory-unique objects. This saves memory
 ** if the same Symbol is used frequently and allows for efficient equality
 ** testing by comparing handles instead of content.
 ** @see UnnamedSymbol
 */

public class Symbol {

  /** 
  ** This function must be used to get hold of Symbols with the given 
  ** name. It effectively replaces a public constructor. For example,
  ** <p> <tt>Symbol mySy = Symbol.get("Foo");</tt>
  ** <p> initializes <tt>mySy</tt> with the Symbol named <tt>"Foo"</tt>. 
  ** If a Symbol with the given name has been gotten before, this very 
  ** Symbol will be returned. Otherwise <tt>get()</tt> will use the protected 
  ** constructor to create the new Symbol.
  ** @param aName the name of the Symbol seeked
  ** @return the Symbol with the given name
  ** @exception IllegalArgumentException An exception will occur if the 
  ** supplied String is empty or null.
  */
  public static Symbol get(String aName) throws IllegalArgumentException {
    if ((aName == null) || aName.equals(""))
      throw new IllegalArgumentException(
          "Attempt to get Symbol without name!");
    if (strsAndSys.containsKey(aName))
      return (Symbol)strsAndSys.get(aName);
    Symbol newSy = new Symbol(aName);
    strsAndSys.put(aName, newSy);
    return newSy;
  }

  /**
  ** Cloning a Symbol returns the <b>same Symbol, not a copy</b>!
  ** @return this Symbol
  */
  public Object clone() {
    return this;
  }

  /** 
  ** This function tests whether two Symbols are the same. The test 
  ** compares the physical address in memory and should thus be more 
  ** efficient than String comparison. Note that there cannot be two 
  ** different Symbols with the same name.
  ** @param otherSy the Object this one is compared to
  ** @return whether the other Object is the same as this
  */
  public boolean equals(Object otherSy) {
    return this == otherSy;
  }

  /** 
  ** A Symbol is printed as the String that is its name. 
  ** @return the String that is the name of this Symbol
  */
  public String toString() {
    return theName;
  }

  /** 
  ** The <tt>hashCode()</tt> of a Symbol is the <tt>hashCode()</tt> of the 
  ** String that is its name.
  ** @return the <tt>hashCode</tt> of this Symbol's name
  */
  public int hashCode() {
    return theName.hashCode();
  }

  /** 
  ** This protected constructor is used mainly by the static function 
  ** <tt>get()</tt> to create new Symbols.
  ** @param aName the name of the new Symbol
  ** @exception IllegalArgumentException An exception will occur if the 
  ** supplied String is empty or null.
  */
  protected Symbol(String aName) throws IllegalArgumentException {
    if ((aName == null) || aName.equals(""))
      throw new IllegalArgumentException(
          "Attempt to create Symbol without name!");
    theName = new String(aName);
  }

  /** the name of the Symbol */
  protected String theName;

  private static Hashtable strsAndSys = new Hashtable(10000);

}
