package relational;

import java.io.*;
import java.lang.reflect.Field;
import Tools.Assert;

/**
 * Describes a regular field of a class.
 */
public class FieldDescriptorField
	extends FieldDescriptor {

	transient protected Field f;	// describes member field (column)
	transient protected Class c;	// describes table that column belongs to
								// (even if field is declared in a superclass)

	public static FieldDescriptor get(Field f, Class c) {
		// don't need to cache at this level; FieldDescriptor generic
		// factory does that.
		FieldDescriptorField fd = new FieldDescriptorField();
		fd.f = f;
		fd.c = c;
		return fd;
	}

	public Object get(Row source) {
		if (source instanceof Relational) {
			Assert.assert(c.isInstance(source));
			try {
				return f.get(source);
			} catch (IllegalAccessException ex2) {
				throw new RuntimeException("source does not support "+this);
			}
		} else {
			return source.getField(this);
		}
	}

	public Class getDeclaringClass() {
		return c;
	}

	public Class getType() {
		return f.getType();
	}

	public String toString() {
		return c+"."+f.getName();
	}

	public Field getField() {
		return f;
	}

	public boolean equals(Object o) {
		if (o instanceof FieldDescriptorField) {
			return ((FieldDescriptorField)o).f.equals(this.f)
					&&
					((FieldDescriptorField)o).c.equals(this.c);
		}
		return false;
	}

	private void writeObject(java.io.ObjectOutputStream out)
		throws IOException {
		out.writeObject(c.getName());
		out.writeObject(f.getName());
	}

	private void readObject(java.io.ObjectInputStream in)
		throws IOException, ClassNotFoundException {
		String className = (String) in.readObject();
		String fieldName = (String) in.readObject();
		c = Class.forName(className);
		try {
			f = c.getField(fieldName);
		} catch (NoSuchFieldException ex) {
			throw new IOException("Couldn't find field "+fieldName);
		}
	}

	Object readResolve()
		throws ObjectStreamException {
		// Get the "official" instance of FieldDescriptor (from the cache),
		// so that hashCode/equals works right
		return FieldDescriptor.get(f, c);
	}
}
