import java.util.*;

/**
 * CharBag.java
 *
 *
 * Created: Mon Jan 20 13:03:08 2003
 *
 * <p>A bag of characters,
 * i.e., an unordered collection of characters,
 * that may contain some character some number of times.
 *
 * @author <a href="mailto:shapiro@cse.buffalo.edu">Stuart C. Shapiro</a>
 */

public class CharBag extends AbstractCollection {
    /**
     * The real object, for which this <code>CharBag</code> is a proxy object.
     */
    private StringBuffer chars;

    /**
     * Creates a new empty <code>CharBag</code> instance.
     *
     */
    public CharBag (){
	super();
	chars = new StringBuffer();
    }

    /**
     * Creates a new <code>CharBag</code> instance
     * containing all the chars of <code>b</code>.
     *
     * @param b a <code>StringBuffer</code> value
     */
    public CharBag (StringBuffer b) {
	this();
	chars.append(b);
    }

    /**
     * Adds <code>c</code> to this bag of characters.
     *
     * @param c a <code>char</code> value
     * @return <code>true</code>
     */
    public boolean add(char c) {
	chars.append(c);
	return true;
    }

    /**
     * Returns the index of <code>c</code> in the chars of this bag, or -1.
     *
     * @param c a <code>char</code> value
     * @return the index of <code>c</code>, if it is in this bag of characters;
     * otherwise, -1
     */
    private int indexOf(char c) {
	return chars.indexOf("" + c);
    }

    /**
     * Removes <code>char</code> from this bag of characters.
     * <p>
     * <b>post:</b> this == this@pre->excluding(c)
     *
     * @param c a <code>char</code> value
     * @return <code>true</code> if <code>c</code> was in this@pre;
     * <code>false</code> otherwise
     */
    public boolean remove(char c) {
	int i = indexOf(c);
	if (i < 0) {return false;}
	chars.deleteCharAt(i);
	return true;
    }

    /**
     * Tests if <code>c</code> is in this bag of characters.
     *
     * @param c a <code>char</code> value
     * @return <code>true</code> if this->includes(c), else <code>false</code>
     */
    public boolean contains(char c) {
	return indexOf(c) >= 0;
    }

    /**
     * Tests if this bag of characters is empty
     *
     * @return <code>true</code> if this is empty, else  <code>false</code>
     */
    public boolean isEmpty() {
	return chars.length() == 0;
    }

    /**
     * Returns the number of characters in this bag of characters.
     *
     * @return the number of characters in this bag of characters.
     */
    public int size() {
	return chars.length();
    }

    /**
     * Tests whether this bag and <code>b</code> have the same characters
     * the same number of times.
     *
     * @param b a <code>CharBag</code> value
     * @return <code>true</code>
     *  if this bag and <code>b</code> have the same characters
     * the same number of times.
     * else <code>false</code>
     */
    public boolean equals(CharBag b) {
	if (size() != b.size()) {return false;}
	CharBag tmp = new CharBag(b.chars);
	for (int i=0; i<chars.length(); i++) {
	    if (!tmp.remove(chars.charAt(i))) {
		return false;}
	}
	return true;
    }

    /**
     * Not yet implemented.
     */
    public Iterator iterator() {
	throw new UnsupportedOperationException();
    }

    /**
     * Converts this bag of characters to a string.
     *
     * @return a <code>String</code> representation of this bag of characters.
     */
    public String toString() {
	return "[" + chars + "]";
    }

}// CharBag
