/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.sets;

import java.util.Iterator;
import java.util.Set;
import net.ranides.assira.collection.ACollection;

/**
 * An abstract class with hashcode & equals suitable for most sets.
 * @author Ranides Atterwim <ranides@gmail.com>
 * @param <K> 
 */
public abstract class ASet<K> extends ACollection<K> implements Set<K>, java.io.Serializable {
    
    private static final long serialVersionUID = 1L;

    protected ASet() {
        // protected constructor
    }

    @Override
    public abstract Iterator<K> iterator();

    @Override
    public boolean remove(Object value) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        }
        if (!(other instanceof Set)) {
            return false;
        }
        Set<?> oset = (Set<?>) other;
        if (oset.size() != size()) {
            return false;
        }
        return containsAll(oset);
    }

    /**
     * Returns a hash code for this set. The hash code of a set is computed 
     * by summing the hash codes of its elements because order should not change
     * result.
     * @return a hash code for this set.
     */
    @Override
    public int hashCode() {
        int h = 0, n = size();
        Iterator<K> i = iterator();
        K item;
        while (n-- != 0) {
            item = i.next();
            h += (item == null ? 0 : item.hashCode());
        }
        return h;
    }
    
    @Override
    public String toString() {
        Iterator<K> itr = iterator();
        if ( !itr.hasNext() ) {
            return "{}";
        }
        StringBuilder builder = new StringBuilder();
        builder.append('{');
        for (;;) {
            K item = itr.next();
            builder.append(item == this ? "(this Collection)" : item);
            if ( !itr.hasNext() ) {
                return builder.append('}').toString();
            }
            builder.append(", ");
        }
    }
}
