/* 
 * JGimp - A Java extension for the GIMP
 * Copyright (C) 2002  Georgia Tech Research Corp.
 * Written by Michael Terry, mterry@cc.gatech.edu
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package org.gimp.jgimp;

import java.awt.Color;
import java.awt.Rectangle;
import java.io.Serializable;


/**
 * JGimpData is the base class that encapsulates the various types of data
 * used to communicate with the GIMP and its procedural database.
 * <p>
 * Wrappers for native types are found in org.gimp.jgimp.nativewrappers.
 * Wrappers for types that are conceptually objects within the GIMP (such as images, 
 * drawables, etc.), are found in this package (org.gimp.jgimp).
 * <p>
 * Each child class of JGimpData corresponds to a certain data type in the GIMP.
 * For example, if a procedure in the GIMP calls for an "INT32," then a
 * {@link org.gimp.jgimp.nativewrappers.JGimpInt32} object is used to represent
 * that data. However, note that {@link org.gimp.jgimp.GimpApp} has methods that
 * will automatically perform conversions from native Java types to the proper
 * "wrapped" JGimpData type. For example, for INT32 data, if you use
 * {@link org.gimp.jgimp.GimpApp}'s callProcedure method, you can pass in a Short,
 * Integer, or Long and it will automatically convert it to a JGimpInt32 object
 * if that is the param type needed.
 */
public abstract class JGimpData implements Cloneable, Serializable {

    /**
     *   Returns the GIMP's integer constant defining this parameter's data type.
     *   These constants are defined in JGimpPDBArgTypeConstants and taken from the
     * file gimpenums.h
    */
    public abstract int getGimpPDBArgType();

    /**
     * Returns a human-readable representation of this data
     */
    public abstract String toString();
    
    public abstract boolean equals(Object inRight);

    /**
     * Attempts to convert the data into a boolean value.
     * This procedure will first attempt to convert the value into
     * an integer, then return true if the integer value is non-zero.
     * @return True if the data can be coerced to a non-zero integer value, false
     *         if it resolves to zero.
     * @throws JGimpInvalidDataCoercionException
     */
    public boolean convertToBoolean() throws JGimpInvalidDataCoercionException {
        return (this.convertToInt() != 0);
    }
    
    /**
     * Attempts to convert the data to a byte. Will not "down-cast"
     * the value from a more precise value (such as a short, float, etc.).
     * @return The value of this data as a byte.
     * @throws JGimpInvalidDataCoercionException
     */
    public byte convertToByte() throws JGimpInvalidDataCoercionException {
        throw new JGimpInvalidDataCoercionException(this.getClass(), this);
    }
    /**
     * Attempts to convert the data to a short. Will not "down-cast"
     * the value from a more precise value (such as an int, float, etc.).
     * However, will cast up (byte -> short).
     * @return The value of this data as a short.
     * @throws JGimpInvalidDataCoercionException
     */
    public short convertToShort() throws JGimpInvalidDataCoercionException {
        return this.convertToByte();
    }
    /**
     * Attempts to convert the data to an int. Will not "down-cast"
     * the value from a more precise value (such as a long, float, etc.).
     * However, will cast up (byte -> short -> int). Note that if the
     * data represents something by an integer (such as an image or
     * drawable), then it will return the integer value representing
     * that object.
     * @return The value of this data as an int.
     * @throws JGimpInvalidDataCoercionException
     */
    public int convertToInt() throws JGimpInvalidDataCoercionException {
        return this.convertToShort();
    }
    /**
     * Attempts to convert the data to a double. Will cast up if 
     * necessary (byte -> short -> int -> double).
     * Note that if the data represents something by an integer
     * (such as an image or drawable), then it will return the
     * integer value representing that object.
     * @return The value of this data as a double.
     * @throws JGimpInvalidDataCoercionException
     */
    public double convertToDouble() throws JGimpInvalidDataCoercionException {
        return this.convertToInt();
    }
    /**
     * Attempts to convert the data to a String. This version simply
     * throws an exception.
     * @return The value of this data as a String.
     * @throws JGimpInvalidDataCoercionException
     */
    public String convertToString() throws JGimpInvalidDataCoercionException {
        throw new JGimpInvalidDataCoercionException(String.class, this);
    }
    /**
     * Attempts to convert the data to a byte array. This version
     * tries to first convert to a byte to create a single-element
     * array containing that value.
     * @return This data as a byte array.
     * @throws JGimpInvalidDataCoercionException
     */
    public byte[] convertToByteArray() throws JGimpInvalidDataCoercionException {
        return new byte[] { this.convertToByte() };
    }
    /**
     * Attempts to convert the data to a short array. This version
     * tries to first convert to a short to create a single-element
     * array containing that value. If that fails, it then tries
     * to convert to a byte array, then converts that array to a short
     * array.
     * @return This data as a short array.
     * @throws JGimpInvalidDataCoercionException
     */
    public short[] convertToShortArray() throws JGimpInvalidDataCoercionException {
        try {
            return new short[] { this.convertToShort() };
        } catch (Exception ignoredException) {}

        byte[] byteArray = convertToByteArray();
        short[] returnArray = new short[byteArray.length];
        for (int i = 0; i < returnArray.length; i++) {
            returnArray[i] = byteArray[i];
        }
        return returnArray;
    }
    /**
     * Attempts to convert the data to an int array. This version
     * tries to first convert to an int to create a single-element
     * array containing that value. If that fails, it then tries
     * to convert to a short array, then converts that array to an int
     * array.
     * @return This data as an int array.
     * @throws JGimpInvalidDataCoercionException
     */
    public int[] convertToIntArray() throws JGimpInvalidDataCoercionException {
        try {
            return new int[] { this.convertToInt() };
        } catch (Exception ignoredException) {}

        short[] shortArray = convertToShortArray();
        int[] returnArray = new int[shortArray.length];
        for (int i = 0; i < returnArray.length; i++) {
            returnArray[i] = shortArray[i];
        }
        return returnArray;
    }
    /**
     * Attempts to convert the data to a double array. This version
     * tries to first convert to a double to create a single-element
     * array containing that value. If that fails, it then tries
     * to convert to an int array, then converts that array to a double
     * array.
     * @return This data as a double array.
     * @throws JGimpInvalidDataCoercionException
     */
    public double[] convertToDoubleArray() throws JGimpInvalidDataCoercionException {
        try {
            return new double[] { this.convertToDouble() };
        } catch (Exception ignoredException) {}

        int[] intArray = convertToIntArray();
        double[] returnArray = new double[intArray.length];
        for (int i = 0; i < returnArray.length; i++) {
            returnArray[i] = intArray[i];
        }
        return returnArray;
    }
    /**
     * Attempts to convert the data to a String array. This version
     * tries to first convert to a String to create a single-element
     * array containing that value. If that fails, it then tries
     * to convert to a double array, then converts that array to a
     * String array.
     * @return This data as a String array.
     * @throws JGimpInvalidDataCoercionException
     */
    public String[] convertToStringArray() throws JGimpInvalidDataCoercionException {
        try {
            return new String[] { this.convertToString() };
        } catch (Exception ignoredException) {}

        double[] doubleArray = convertToDoubleArray();
        String[] returnArray = new String[doubleArray.length];
        for (int i = 0; i < returnArray.length; i++) {
            returnArray[i] = "" + doubleArray[i];
        }
        return returnArray;
    }
    /**
     * Attempts to convert the data to a Rectangle. This version
     * throws an exception.
     * @return This data as a Rectangle.
     * @throws JGimpInvalidDataCoercionException
     */
    public Rectangle convertToRectangle() throws JGimpInvalidDataCoercionException {
        throw new JGimpInvalidDataCoercionException(Rectangle.class, this);
    }
    /**
     * Attempts to convert the data to a Color. This version
     * throws an exception.
     * @return This data as a Color.
     * @throws JGimpInvalidDataCoercionException
     */
    public Color convertToColor() throws JGimpInvalidDataCoercionException {
        throw new JGimpInvalidDataCoercionException(Color.class, this);
    }
}
