package miningmart.storedProcedures;

/** A class to store the necessary information of a DB attribute and
 * to convert the database datatype to the internal datatype and vice
 * versa. */
class Attribute {

    private final String name;
    private final short  dataType;
    private final short  internalType;

    /**
     * @param name the name of the attribute in the database
     * @param dataType the relational datatype of the attribute in the database
     * @param internalType the datatype the operator expects the data to have
     */
    public Attribute(String name, short dataType, short internalType) {
		this.name = name;
		this.dataType = dataType;
		this.internalType = internalType;
    }

    public String getName() {
		return name;
    }

    public short getDataType() {
		return dataType;
    }

    public String getDataTypeName() {
		return (DataType.getNameFor(this.dataType));
    }

    public boolean isConvertable() {
		return (getConvertedInput() != null && getConvertedOutput("") != null);
    }

    /**
     * This method adds some conversion functions around the attribute
     * name, in order to receive the internal datatype, if it is
     * different from the attribute type in the database.
     *
     * @return a string to be used in SQL statements instead of the
     * attribute name. If conversion is not supported, then
     * <i>null</i> is returned!
     */
    public String getConvertedInput() {
		if (this.getDataType() == this.internalType) {
		    if (this.getDataType() == DataType.DATE) {
				return("to_char(" + this.getName() + ", 'DD.MM.YYYY HH24:MI:SS')");
		    }
		    else {
		    	return this.getName();
		    }
		}

		if (this.getDataType() == DataType.DATE &&
		    this.internalType  == DataType.NUMBER )
		{
		    return ("m4_date_to_timestamp(" + this.getName() + ")");
		}

		if (this.getDataType() == DataType.NUMBER &&
		    this.internalType  == DataType.DATE )
		{
		    return ("to_char(m4_timestamp_to_date(" + this.getName() + "), 'DD.MM.YYYY HH24:MI:SS')");
		}

		return null;
    }

    /**
     * This method adds some conversion functions around a value to be
     * inserted into the database.  It converts the internal datatype
     * into the datatype of the attribute in the database.
     *
     * @param value a value to be inserted into the
     *        database. <i>null</i> represents the DB value 'NULL'.
     * @return a string which should be used in a SQL <i>INSERT</i>
     * statement instead of the value as such. If conversion fails,
     * then <i>null</i> is returned!
     */
    public String getConvertedOutput(String value) {
		if (value == null) {
		    return "NULL";
		}
	
		if (this.getDataType() == this.internalType) {
		    if (this.getDataType() == DataType.DATE) {
				return("to_date('" + value + "', 'DD.MM.YYYY HH24:MI:SS')");
		    }
		    else {
		    	return value;
		    }
		}

		if (this.internalType  == DataType.NUMBER &&
		    this.getDataType() == DataType.DATE )
		{
	    	return ("m4_timestamp_to_date(" + value + ")");
		}

		if (this.internalType  == DataType.DATE &&
		    this.getDataType() == DataType.NUMBER )
		{
		    return ("m4_date_to_timestamp(to_date('" + value + "', 'DD.MM.YYYY HH24:MI:SS'))");
		}

		return null;
    }

    public String getConvertedOutput(double value) {
		return(this.getConvertedOutput(Double.toString(value)));
    }

    public String getConvertedOutput(int value) {
		return(this.getConvertedOutput(Integer.toString(value)));
    }

    public String getConvertedOutput(long value) {
		return(this.getConvertedOutput(Long.toString(value)));
    }

    public String getConvertedOutput(Object obj) {
		if (obj == null) {
		    return "NULL";
		}
		
		if (obj instanceof String) {
		    return(this.getConvertedOutput((String) obj));
		}

		if (obj instanceof Double) {
		    Double d = (Double) obj;
		    return(this.getConvertedOutput(d.doubleValue()));
		}

		if (obj instanceof Integer) {
		    Integer i = (Integer) obj;
	    	return(this.getConvertedOutput(i.intValue()));
		}

		if (obj instanceof Long) {
		    Long l = (Long) obj;
	    	return(this.getConvertedOutput(l.longValue()));
		}
	
		return null;
    }
}
