import java.util.*;

/**
 * CharBagI.java
 *
 *
 * Created: Thur Jan 30 2003
 *
 * <p>A bag of characters,
 * i.e., an unordered collection of characters,
 * that may contain some character some number of times.
 * Has an iterator.
 *
 * @author <a href="mailto:shapiro@cse.buffalo.edu">Stuart C. Shapiro</a>
 */

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

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

    /**
     * Creates a new <code>CharBagI</code> instance
     * containing all the chars of <code>b</code>.
     *
     * @param b a <code>StringBuffer</code> value
     */
    public CharBagI (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>CharBagI</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(CharBagI b) {
	if (size() != b.size()) {return false;}
	CharBagI tmp = new CharBagI(b.chars);
	for (int i=0; i<chars.length(); i++) {
	    if (!tmp.remove(chars.charAt(i))) {
		return false;}
	}
	return true;
    }

    /**
     * Creates and returns a new iterator for this CharBagI.
     *
     * @return An iterator for this CharBagI.
     */
    public Iterator iterator() {
	return new CharBagIIterator();
    }

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

    /**
     * Iterator for CharBagI.<br>
     * Produces Characters instead of chars,
     * because iterators must produce Objects.
     *
     */
    private class CharBagIIterator implements Iterator{
	private int next = 0;

	/**
	 * Creates a new <code>CharBagIIterator</code> instance.
	 *
	 */
	public CharBagIIterator() {
	    super();
	}

	/**
	 * Test for whether the iterator is finished with this CharBagI.
	 *
	 * @return true if there are more chars in this CharBagI;
	 * false if this iterator is finished.
	 */
	public boolean hasNext() {
	    return next < chars.length();
	}

	/**
	 * Generator of Characters from this CharBagI.
	 *
	 * @return a Character wrapping the next char in this CharBagI.
	 */
	public Object next() {
	    if (!hasNext()) {throw new NoSuchElementException();}
	    return new Character(chars.charAt(next++));
	}

	/**
	 * Remove the char that had been the last one returned by next().
	 */
	public void remove() {
	    if (next < 1) {
		throw new IllegalStateException("Nothing to remove.");
	    }
	    chars.delete(next-1, next--);
	}

    } // CharBagIIterator
    
    public static void main (String[] args) {
	CharBagI b = new CharBagI();
	b.add('a');
	b.add('b');
	b.add('c');
	b.add('d');
	Iterator it = b.iterator();
	while (it.hasNext()) System.out.println(((Character)it.next()).charValue());

    } // end of main ()
    

}// CharBagI
