package relational;

import java.io.Serializable;
import java.rmi.RemoteException;
import Tools.Assert;

/**
 * All objects that can be accessed relationally must subclass this
 * abstract class. They all have an ``update'' method that makes their
 * data ``persistent'' (although it may be already), and ensures that it
 * is indexed.<p>
 *
 * Note that this is a ``Row.'' A Relational instance is a single row from
 * a single table (Relational class); a compound row made up from multiple
 * tables joined would be some other implementation of Row (like BasicRow).
 */
public abstract class Relational
	implements Row {

	public Object primaryKey;
	transient boolean valid;

	public void setPrimaryKey(Object pk) {
		primaryKey = pk;
	}

	public abstract Database getDatabase();

	public void update()
		throws RemoteException {
		getDatabase().update(this);
	}

	public void insert()
		throws RemoteException {
		getDatabase().insert(this);
	}

	public Object resolveForeignKey(Class c, Object key) {
		try {
			ResultSet rs = getDatabase().evaluateSelect(new Select(c,
				Where.equals(FieldDescriptor.get(c), key)));
			if (rs.size()==1) {
				// don't allow ambiguity
				return rs.getVector().elementAt(0);
			}
		} catch (RemoteException ex) { }
		return null;
	}

	//
	// Row methods
	//

	public Relational getTable(FromClause fc, int table) {
		Assert.assert(table==0);
		Assert.assert(fc.getNumTables() == 1);
		Assert.assert(fc.getTable(0) == this.getClass());
		return this;
	}

	public Object getField(int tableIndex, FieldDescriptor fd) {
		Tools.Assert.assert(tableIndex==0);
		return fd.get(this);
	}

	public Object getField(FieldDescriptor fd) {
		return fd.get(this);
	}

	public ColumnSpec getColumnSpec() {
		return getFromClause().getNaturalColumnSpec();
	}

	public boolean supports(ColumnSpec cs) {
		return cs.getFromClause().subsetOf(getFromClause());
	}

	public FromClause getFromClause() {
		return FromClause.createAnonymous(this.getClass());
	}

	public Relational getTable(Class c) {
		Assert.assert(this.getClass() == c);
		return this;
	}

	public Relational getTable(String tableName) {
		Assert.assert(getFromClause().getName(0) == tableName);
		return this;
	}
}
