package relational;

import java.io.Serializable;
import java.util.*;
import java.lang.reflect.Field;

/**
 * A ColumnSpec is an ordered list of unique columns of a FromClause.
 */
public class ColumnSpec
	implements Serializable {

	FromClause		fromClause;
	int				indices[];
	FieldDescriptor	fields[];

	public static ColumnSpec create(FromClause fromClause,
		String[] names, FieldDescriptor fields[]) {
		int indices[] = new int[names.length];
		for (int i=0; i<names.length; i++) {
			indices[i] = fromClause.getIndex(names[i]);
		}
		return create(fromClause, indices, fields);
	}

	public static ColumnSpec create(FromClause fromClause,
		int indices[], FieldDescriptor fields[]) {
		if (indices.length!=fields.length) {
			throw new IllegalArgumentException("arguments must be same length");		}
		ColumnSpec cs = new ColumnSpec();
		cs.fromClause = fromClause;
		cs.indices = (int[]) indices.clone();
		cs.fields = (FieldDescriptor[]) fields.clone();
		return cs;
	}

	public FromClause getFromClause() { return fromClause; }

	public FieldDescriptor getField(int field) { return fields[field]; }

	public int findField(FieldDescriptor fieldIdent) {
		// TODO: slow operation could be improved
		for (int i=0; i<fields.length; i++) {
			if (fields[i].equals(fieldIdent)) {
				return i;
			}
		}
		return -1;
	}

	public boolean supports(FieldDescriptor fieldIdent) {
		return findField(fieldIdent)>=0;
	}

	public int getNumFields() { return fields.length; }

	public Class getDeclaringClass(int field) {
		return fields[field].getDeclaringClass();
	}

	public Class getType(int field) {
		return fields[field].getType();
	}

	public String getTableName(int field) {
		return fromClause.getName(indices[field]);
	}

	public int getTableIndex(int field) {
		return indices[field];
	}

	public Object getField(Row source, int field) {
		// source can be a native object (if fromClause is unambiguous for
		// that object) or a Row implementation
		if (source instanceof Relational) {
			return fields[field].get(source);
		} else {
			return ((Row) source).getField(indices[field], fields[field]);
		}
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("ColumnSpec[");
		for (int i=0; i<indices.length; i++) {
			sb.append(fields[i].toString());
			if (i<indices.length-1) {
				sb.append(", ");
			}
		}
		sb.append("]");
		return sb.toString();
	}
}
