// $Id: Set.java,v 1.2 1999/12/10 10:31:48 mpp Exp $

package IR2;

import java.util.*;

public class Set {
  private Hashtable table;

  // Set operators
  public static final int UNION = 1;
  public static final int INTERSECTION = 2;
  public static final int DIFFERENCE = 3;

  // Constructors
  public Set() {
    table = new Hashtable();
  }

  public Set(Enumeration e) {
    this();
    add(e);
  }
  
  public Set(Set source) {
    // Copy source
    copy(source);
  }

  // COPY (mutate set to match operand)
  public void copy(Set source) {
    this.table = (Hashtable)source.table.clone();  // Own copy of table
  }

  // Does set contain object? 
  public boolean contains(Object o) {
    return (table.containsKey(o));
  }

  // empty set?
  public boolean isEmpty() {
    return table.isEmpty();
  }

  // equality test
  public boolean equals(Object obj) {
    if (!(obj instanceof Set))
      return false;
    Set diff1 = new Set((Set) obj);
    diff1.difference(this);
    Set diff2 = new Set(this);
    diff2.difference((Set) obj);
    return diff1.isEmpty() && diff2.isEmpty();
  }

  // Adding stuff to a set
  public void add(Enumeration e) { addElements(e); }
  public void addElements(Enumeration e) {
    while (e.hasMoreElements())
      addElement(e.nextElement());
  }

  public void add(Object o) { addElement(o); }
  public void addElement(Object o) {
    table.put(o, this /* Hashtable isn't happy with null */ );
  }
  

  // Emptying the set
  public void clear() {
    table.clear();
  }

  public void remove(Object o) { removeElement(o); }
  public void removeElement(Object o) { table.remove(o); }

  // Enumeration of everything in set
  public Enumeration elements() {
    return table.keys();
  }

  // First element -- assumes set is not empty.
  public Object first_element() {
    return elements().nextElement();
  }

  // SET OPERATIONS -- These mutate current object!
  public void perform_op(int op, Set operand) {
    switch (op) 
      {
      case UNION:
        union(operand);
        break;
      case INTERSECTION:
        intersect(operand);
        break;
      case DIFFERENCE:
        difference(operand);
      }
  }
  
  public void union(Set operand) {
    for (Enumeration e = operand.elements(); e.hasMoreElements(); )
      this.addElement(e.nextElement());
  }

  public void intersect(Set operand) {
    for (Enumeration e = this.elements(); e.hasMoreElements(); ) {
      Object o = e.nextElement();
      if (!operand.contains(o))
        this.removeElement(o);
    }
  }

  public void difference(Set operand) {
    for (Enumeration e = this.elements(); e.hasMoreElements(); ) {
      Object o = e.nextElement();
      if (operand.contains(o))
        this.removeElement(o);
    }
  }

  // What's in here?
  public String toString() {
    String out = "{\n";
    Enumeration e = table.keys();
    if (e.hasMoreElements()) 
      out += "     " + e.nextElement().toString();

    while (e.hasMoreElements()) 
      out += ",\n     " + e.nextElement();
      
    out += " }";

    return out;
  }

}
