package relational;

import java.util.*;
import Tools.Assert;

/**
 * A ResultSetNarrow holds results shaped into a specific ColumnSpec,
 * not just a FromClause.
 */
public class ResultSetNarrow
	implements ResultSet {

	public ResultSetNarrow(ResultSet rs) {
		this(rs.getColumnSpec(), rs);
	}

	public ResultSetNarrow(ColumnSpec cs) {
		this.columnSpec = cs;
		this.myVector = new Vector();
	}

	public ResultSetNarrow(ColumnSpec cs, ResultSet rs) {
		this.myVector = new Vector(rs.getVector());
		// columnSpec may need to be corrected if its fromClause is in
		// a different order from rs's.
		this.columnSpec = alignColumnSpec(cs, rs.getFromClause());
	}

	protected static ColumnSpec alignColumnSpec(ColumnSpec cs, FromClause fc) {
		FieldDescriptor fields[] = new FieldDescriptor[cs.getNumFields()];
		String names[] = new String[cs.getNumFields()];
		for (int i=0; i<fields.length; i++) {
			names[i] = cs.getTableName(i);
			fields[i] = cs.getField(i);
		}
		return ColumnSpec.create(fc, names, fields);
	}

	// should only be called when constructing this object;
	// after first read, some internal state may become sticky,
	// and not see new addMember() calls.
	public void addMember(Object o) {
		myVector.addElement(o);
	}

	public void removeMember(Object o) {
		myVector.removeElement(o);
	}

	public FromClause getFromClause() {
		return columnSpec.getFromClause();
	}

	public ColumnSpec getColumnSpec() {
		return columnSpec;
	}

	public int size() {
		return myVector.size();
	}

	/**
	 * @deprecated in favor of getIterator
	 */
	public Enumeration getEnumeration() {
		return myVector.elements();
	}

	public Iterator iterator() {
		return myVector.iterator();
	}

	public Vector getVector() {
		return myVector;
			// TODO: dangerous because caller can frob with the vector that's
			// my protected data?
	}

	public boolean hasSingleton(Object o) {
		if (memberCache==null) {
			fillCache();
		}
		return memberCache.contains(o);
	}

	public boolean hasMember(Row o) {
		Assert.assert(false, "meaningless?");
		return false;
	}

	//////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////

	protected void fillCache() {
		if (getColumnSpec().getNumFields()!=1) {
			throw new RuntimeException(
				"membership test requires a single-column result set, not "
					+getColumnSpec().getNumFields());
		}
		memberCache = new HashSet();
		Enumeration e = getEnumeration();
		while (e.hasMoreElements()) {
			Row row = (Row) e.nextElement();
			Object o = columnSpec.getField(row, 0);
			memberCache.add(o);
		}
	}

	protected Vector myVector;
	protected ColumnSpec columnSpec;
	protected HashSet memberCache;
}
