/*
 * Value.java
 *
 * Created on January 4, 2001, 11:37 AM
 */

package org.freehep.util;
import java.util.Date;

/**
 * A class that can represent any Java object or primitive. Unlike the
 * built-in primitive proxies (Double, Integer etc) it is mutable. It is
 * used to allow values to be used without needing overloaded methods for
 * each primitive type, and without the overhead of object creation/deletion.
 *
 * When a value is returned by an Object method it should be assumed to be valid
 * only until the next method call to that Object. The use of Value should be
 * avoided in multi-threaded environments.
 *
 * @author  tonyj
 * @version $Id: Value.java,v 1.1.1.1 2004/05/31 05:08:49 kuromaru Exp $
 */
public class Value {

    private int     intValue;
    private short   shortValue;
    private long    longValue;
    private float   floatValue;
    private double  doubleValue;
    private boolean boolValue;
    private byte    byteValue;
    private char    charValue;
    private Object  obj;
    private Class   type;

    public final static Class TYPE_INTEGER = Integer.TYPE;
    public final static Class TYPE_SHORT   = Short.TYPE;
    public final static Class TYPE_LONG    = Long.TYPE;
    public final static Class TYPE_FLOAT   = Float.TYPE;
    public final static Class TYPE_DOUBLE  = Double.TYPE;
    public final static Class TYPE_BOOLEAN = Boolean.TYPE;
    public final static Class TYPE_BYTE    = Byte.TYPE;
    public final static Class TYPE_CHAR    = Character.TYPE;
    public final static Class TYPE_STRING  = String.class;
    public final static Class TYPE_DATE    = Date.class;

    public Value() {}
    
    public Value( Value v ) {
        this.type        = v.getType();
        this.intValue    = v.intValue;
        this.shortValue  = v.shortValue;
        this.longValue   = v.longValue;
        this.floatValue  = v.floatValue;
        this.doubleValue = v.doubleValue;
        this.boolValue   = v.boolValue;
        this.byteValue   = v.byteValue;
        this.charValue   = v.charValue;
        this.obj         = v.obj;
    }
    
    /**
     * Get the Value's type
     * @return The Class of this Value.
     *
     */
    public Class getType() {
        return type;
    }

    /**
     * Set the Value's internal value to an integer.
     * @param val The integer value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(int val)    { intValue    = val; type = TYPE_INTEGER; return this; }

    /**
     * Set the Value's internal value to a short.
     * @param val The short value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(short val)  { shortValue  = val; type = TYPE_SHORT;   return this; }

    /**
     * Set the Value's internal value to a long.
     * @param val The long value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(long val)   { longValue   = val; type = TYPE_LONG;    return this; }

    /**
     * Set the Value's internal value to a float.
     * @param val The float value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(float val)  { floatValue  = val; type = TYPE_FLOAT;   return this; }

    /**
     * Set the Value's internal value to a double.
     * @param val The double value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(double val) { doubleValue = val; type = TYPE_DOUBLE;  return this; }

    /**
     * Set the Value's internal value to a boolean.
     * @param val The boolean value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(boolean val){ boolValue   = val; type = TYPE_BOOLEAN; return this; }

    /**
     * Set the Value's internal value to a byte.
     * @param val The byte value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(byte val)   { byteValue   = val; type = TYPE_BYTE;    return this; }

    /**
     * Set the Value's internal value to a char.
     * @param val The char value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(char val)   { charValue   = val; type = TYPE_CHAR;    return this; }

    /**
     * Set the Value's internal value to a String.
     * @param val The String value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(String val) { obj         = val; type = TYPE_STRING;  return this; }

    /**
     * Set the Value's internal value to a Date.
     * @param val The Date value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(Date val)   { obj         = val; type = TYPE_DATE;    return this; }

    /**
     * Set the Value's internal value to an Object.
     * @param val The Object value.
     * @return The Value object with the given internal value.
     *
     */
    public Value set(Object val) { obj         = val; type = obj == null ? Object.class : obj.getClass(); return this; }

    /**
     * Get the integer value.
     * @return The int value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public int getInt() {
        if (type == TYPE_INTEGER)    return intValue;
        else if (type == TYPE_SHORT) return shortValue;
        else if (type == TYPE_BYTE)  return byteValue;
        else throw new ClassCastException( "getInt cannot be called for type "+type.toString());
    }

    /**
     * Get the short value.
     * @return The short value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public short getShort() {
        if (type == TYPE_SHORT)     return shortValue;
        else if (type == TYPE_BYTE) return byteValue;
        else throw new ClassCastException( "getShort cannot be called for type "+type.toString());
    }

    /**
     * Get the long value.
     * @return The long value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public long getLong() {
        if (type == TYPE_LONG)         return longValue;
        else if (type == TYPE_INTEGER) return intValue;
        else if (type == TYPE_SHORT)   return shortValue;
        else if (type == TYPE_BYTE)    return byteValue;
        else throw new ClassCastException( "getLong cannot be called for type "+type.toString());
    }

    /**
     * Get the float value.
     * @return The float value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public float getFloat() {
        if (type == TYPE_FLOAT)        return floatValue;
        else if (type == TYPE_INTEGER) return intValue;
        else if (type == TYPE_SHORT)   return shortValue;
        else if (type == TYPE_LONG)    return longValue;
        else if (type == TYPE_BYTE)    return byteValue;
        else throw new ClassCastException( "getFloat cannot be called for type "+type.toString());
    }

    /**
     * Get the double value.
     * @return The double value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public double getDouble() {
        if (type == TYPE_DOUBLE)       return doubleValue;
        else if (type == TYPE_INTEGER) return intValue;
        else if (type == TYPE_SHORT)   return shortValue;
        else if (type == TYPE_LONG)    return longValue;
        else if (type == TYPE_FLOAT)   return floatValue;
        else if (type == TYPE_BYTE)    return byteValue;
        else if (type == TYPE_DATE)    return ((Date)obj).getTime();
        else throw new ClassCastException( "getDouble cannot be called for type "+type.toString());
    }

    /**
     * Get the boolean value.
     * @return The boolean value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public boolean getBoolean() {
        if (type == TYPE_BOOLEAN) return boolValue;
        else throw new ClassCastException( "getBoolean cannot be called for type "+type.toString());
    }

    /**
     * Get the byte value.
     * @return The byte value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public byte getByte() {
        if (type == TYPE_BYTE) return byteValue;
        else throw new ClassCastException( "getByte cannot be called for type "+type.toString());
    }

    /**
     * Get the char value.
     * @return The char value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public char getChar() {
        if (type == TYPE_CHAR) return charValue;
        else throw new ClassCastException( "getChar cannot be called for type "+type.toString());
    }

    /**
     * Get the String value.
     * @return The String representation of the internal value.
     *
     */
    public String getString() {
        if (type == TYPE_STRING)       return (String)obj;
        else if (type == TYPE_INTEGER) return String.valueOf(intValue);
        else if (type == TYPE_SHORT)   return String.valueOf(shortValue);
        else if (type == TYPE_LONG)    return String.valueOf(longValue);
        else if (type == TYPE_FLOAT)   return String.valueOf(floatValue);
        else if (type == TYPE_DOUBLE)  return String.valueOf(doubleValue);
        else if (type == TYPE_BOOLEAN) return String.valueOf(boolValue);
        else if (type == TYPE_BYTE)    return String.valueOf(byteValue);
        else if (type == TYPE_CHAR)    return String.valueOf(charValue);
        else if (type == TYPE_DATE)    return ((Date)obj).toString();
        else return obj != null ? obj.toString(): "null";
    }

    /**
     * Get the Date value.
     * @return The Date value.
     * @exception A ClassCastException is thrown if this Value has incompatible type.
     *
     */
    public Date getDate() {
        if (type == TYPE_DATE) return (Date)obj;
        else throw new ClassCastException( "getDate cannot be called for type "+type.toString());
    }

    /**
     * Get the Object value.
     * @return The Object value.
     *
     */
    public Object getObject() {
        if (obj != null)       return obj;
        else if (type == TYPE_INTEGER) return new Integer(intValue);
        else if (type == TYPE_SHORT)   return new Short(shortValue);
        else if (type == TYPE_LONG)    return new Long(longValue);
        else if (type == TYPE_FLOAT)   return new Float(floatValue);
        else if (type == TYPE_DOUBLE)  return new Double(doubleValue);
        else if (type == TYPE_BOOLEAN) return new Boolean(boolValue);
        else if (type == TYPE_BYTE)    return new Byte(byteValue);
        else if (type == TYPE_CHAR)    return new Character(charValue);
        else return null;
    }

    /**
     * Get the String value.
     * @return The String representation of the internal value.
     *
     */
    public String toString() {
        return getString();
    }
}
