package edu.uprm.admg.nettraveler.schema;

// JDK imports
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;

import edu.uprm.admg.util.DataVerify;

/**
 * <code>ProjectionAttribute</code> implements the simple projection 
 * of an attribute in a tuple read from a data source. Each instance 
 * contains the name to be used for the projected attribute, the base 
 * type for the attribute, the class that implements the base type, and
 * the index needed to find the argument for the projection in a
 * <code>Tuple</code> instance.
 * <p />
 * Example: Consider the following query on table
 * <code>Person(name:char(30), age:integer)</code>:
 * <PRE>
 * SELECT name, age 
 * FROM Person;
 * </PRE>
 * In this case, each tuple will be 
 * read from the table 
 * <code>Person</code>, and the base attributes
 * <code>name</code> and <code>age</code> will be 
 *  projected into two
 * attributes with the same names. One possible way to create 
 * the objects for the projected attributes is:
 * <PRE>
 * ProjectionAttribute[] proj_attrs;
 * ...
 * // create the necessary objects
 * proj_attrs = new ProjectionAttribute[2];
 * proj_attrs[0] = new ProjectionAttribute("name", Types.STRING, 
 * Class.forName("edu.umd.umiacs.mocha.type.MIString"), 0);
 * proj_attrs[1] = new ProjectionAttribute("age", Types.INTEGER, 
 * Class.forName("edu.umd.umiacs.mocha.type.MIInteger"), 1);
 * ...
 * // project a tuple and save the results
 * result1 = projs_attrs[0].project(tuple_instance);
 * result2 = projs_attrs[1].project(tuple_instance);
 * </PRE>
 * This code will project each of the required attributes from the
 * group of attributes contained in the tuple passed as argument.
 * In each case, the result of the projection will be stored 
 * in the <code>resultX</code> argument.
 * 
 * 
 * @author M. Rodriguez-Martinez
 * @author Elliot A. Vargas-Figueroa
 */
public class ProjectionAttribute extends Attribute implements RelationAttribute{
    /**
	 * Serial Version
	 */
	private static final long serialVersionUID = -8670333271706574408L;
    /** 
     * The index needed to get the argument of this projection from 
     * the structure holding the base attributes read from the data
     * source.
     * @serial
     */
    private int argIdx = -1;
    /** Relation name **/
    private String relationName = null;
    /** Relation alias **/
    private String relationAlias = null;
    /** Relation schema **/
    private String relationSchema = null;
    /**
     * Constructs a <code>ProjectionAttribute</code> from: an attribute
     * name, a base type, a class implementing the base type, and 
     * in the index needed to find the argument for the projection
     * in the <code>Tuple</code> instance containing the attributes 
     * read from the data source.
     * 
     * @param name the name of the projected attribute
     * @param aIdx index to find the argument for the projection operation in 
     * the <code>Tuple</code> containing the base attributes read from the source.
     * @param className Name of the class of the attribute type.
     * 
     */
    public ProjectionAttribute(String name, int aIdx, String className) {
	    	super(name, className);
	    	DataVerify.VerifyIntegerParam("aIdx", aIdx, 0);
	    this.argIdx = aIdx;
    }
    /**
     * @see edu.uprm.admg.nettraveler.schema.RelationAttribute#getSchemaName()
     */
	public String getSchemaName() {
		return relationSchema;
	}
	/**
	 * @see edu.uprm.admg.nettraveler.schema.RelationAttribute#setSchemaName(java.lang.String)
	 */
	public void setSchemaName(String name) {
		DataVerify.VerifyObjectParam("name", name);
		this.relationSchema = name;
	}
	/**
	 * @see edu.uprm.admg.nettraveler.schema.RelationAttribute#getRelationAlias()
	 */
	public String getRelationAlias() {
		return relationAlias;
	}
	/**
	 * @see edu.uprm.admg.nettraveler.schema.RelationAttribute#setRelationAlias(java.lang.String)
	 */
	public void setRelationAlias(String name) {
		DataVerify.VerifyObjectParam("name", name);
		this.relationAlias = name;
	}
	/**
	 * @see edu.uprm.admg.nettraveler.schema.RelationAttribute#getRelationName()
	 */
	public String getRelationName() {
		return relationName;
	}
	/**
	 * @see edu.uprm.admg.nettraveler.schema.RelationAttribute#setRelationName(java.lang.String)
	 */
	public void setRelationName(String name) {
		DataVerify.VerifyObjectParam("name", name);
		this.relationName =  name;
		
	}
    /**
     * @see edu.uprm.admg.nettraveler.schema.Attribute#localEquals(edu.uprm.admg.nettraveler.schema.Attribute)
     */
	protected boolean localEquals(Attribute attr) {
		if(!(attr instanceof ProjectionAttribute))
			return false;
		ProjectionAttribute o = (ProjectionAttribute) attr;
		return argIdx == o.argIdx;
		
	}
	/**
	 * @see edu.uprm.admg.nettraveler.schema.Attribute#localHashCode()
	 */
	protected int localHashCode() {
		int result = 17;
		result += result * 37 + argIdx;
		return result;
	}
    /**
     * Returns the index of this attribute in the
     * evaluated Tuple.
     * 
	 * @return index of this projection in the tuple.
	 */
	public final int getArgIdx() {
		return argIdx;
	}
	/*
     * Serialization stuff
     */
	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
		in.defaultReadObject();
		try{
			DataVerify.VerifyIntegerParam("Argument index", argIdx, 0);
		}catch(Exception e){
			throw new InvalidObjectException(e.toString());
		}
	}
}

