
// Copyright (c) 2000 Oracle Corporation
package oracle.portal.provider.v1;

import java.io.*;
import java.util.*;
import oracle.portal.provider.v1.*;
import oracle.portal.provider.v1.ProviderXtra2;
import oracle.webdb.utils.SimpleStringBuffer;

/**
 * Base customization data class. Manages customization data all portlets
 * should support. By default, this is the portlet's title and short title.<p>
 *
 * Generally, portlets should support customization even if they only allow a
 * user to customize the titlebar. Portlets providing further customization
 * (data) should use a subclassed version of this class as a data class and
 * override the init() method so that further data items can be defaulted.
 */
public class NameValuePersonalizationObject extends Object implements PersonalizationObject 
{

    private String mVersion = null;
    private Hashtable mContent = new Hashtable();
    private boolean mDebug = false;
    private ProviderLog mLogger = null;

    // Constants enumerating allowed value types
    private static final int INTEGER_TYPE       = 1;
    private static final int DOUBLE_TYPE        = 2;
    private static final int FLOAT_TYPE         = 3;
    private static final int LONG_TYPE          = 4;
    private static final int BOOLEAN_TYPE       = 5;
    private static final int STRING_TYPE        = 6;
    private static final int INTEGER_ARRAY_TYPE = 7;
    private static final int DOUBLE_ARRAY_TYPE  = 8;
    private static final int FLOAT_ARRAY_TYPE   = 9;
    private static final int LONG_ARRAY_TYPE    = 10;
    private static final int BOOLEAN_ARRAY_TYPE = 11;
    private static final int STRING_ARRAY_TYPE  = 12;

    // Names with special associated values
    private static final String TITLE_KEY = "NVPO_TITLE";
    private static final String SHORT_TITLE_KEY = "NVPO_SHORT_TITLE";
    private static final String REFERENCE_PATH_KEY = "NVPO_REFERENCE_PATH";

    /**
     * Null Constructor.
     */
    public NameValuePersonalizationObject() 
    {
    }

    /**
     *  Init method used to initialize the data object after instantiation via
     *  its null constructor.  Defined by the PersonalizationObject interface.
     *  Personalization manager is expected to call the init method of data
     *  objects that implement the PersonalizationObject interface.<p>
     *
     *  Behavior is to initialize the title using the (static) title from the
     *  portlet metadata (<code>portlet.getTitle()</code>). The portlet's
     *  default Locale is used to retrieve the title.
     *
     *  @param pr the portlet reference that identifies the customization
     *  instance this object represents.
     */
    public void init(PortletReference pr) 
    {
        if (pr.getProvider() instanceof ProviderXtra2)
        {
            ProviderXtra2 px = (ProviderXtra2)pr.getProvider();
            mLogger = px.getProviderLog();

            // only enable debug if we also have a ProviderLog
            mDebug = (px.isDebugEnabled() && (mLogger != null));
        }

        try 
        {
            String title = pr.getPortlet().getTitle(pr.getLocale());
            if (title == null) 
            {
                title = "";
            }
            setPortletTitle(title);
        }
        catch (Exception e) 
        {
            if (mLogger != null)
            {
                SimpleStringBuffer buf = new SimpleStringBuffer(200);
                buf.append("NameValuePersonalizationObject.init failed: ");
                buf.append("unable to create Title.  ");
                buf.append(e.getMessage());
                mLogger.log(buf.toString());
            }
            e.printStackTrace();
        }

        try
        {
            String sTitle = null;
            Portlet p = pr.getPortlet();
            if (p instanceof PortletXtra2)
            {
                sTitle = ((PortletXtra2) p).getShortTitle(pr.getLocale());
            }
            if (sTitle == null)
            {
                sTitle = "";
            }
            setPortletShortTitle(sTitle);
        }
        catch (Exception e)
        {
            if (mLogger != null)
            {
                SimpleStringBuffer buf = new SimpleStringBuffer(200);
                buf.append("NameValuePersonalizationObject.init failed: ");
                buf.append("unable to create Short Title.  ");
                buf.append(e.getMessage());
                mLogger.log(buf.toString());
            }
            e.printStackTrace();
        }
    }

    /**
     * Sets the version associated with the content of the
     * PersonalizationObject. The version number is a String to allow you to
     * define the structure of your version numbers.
     *
     * @param version version string to be associated with the content of the
     * PersonalizationObject
     */
    public void setContentVersion(String version) 
    {
        mVersion = version;
    }

    /**
     * @return the version String associated with the content of the
     * PersonalizationObject
     */
    public String getContentVersion() 
    {
        return mVersion;
    }

    /**
     * Sets the string to be displayed on the Portlet's title bar.
     *
     * @param title string to be displayed on the Portlet's title bar.
     */
    public void setPortletTitle(String title)
    {
        putString(TITLE_KEY, title);
    }

    /**
     * Gets the string to be displayed on the Portlet's title bar.
     *
     * @return title string to be displayed on the Portlet's title bar.
     */
    public String getPortletTitle()
    {
        return getString(TITLE_KEY);
    }

    /**
     * Sets the string to be displayed for the Portlet's title when there
     * is limited space.  For example the menu item in mobile page.
     *
     * @param title string to be displayed for the Portlet's title when there
     * is limited space.
     */
    public void setPortletShortTitle(String title)
    {
        putString(SHORT_TITLE_KEY, title);
    }

    /**
     * Gets the string to be displayed for the Portlet's title when there
     * is limited space.  For example the menu item in mobile page.
     *
     * @return title string to be displayed for the Portlet's title when there
     * is limited space.
     */
    public String getPortletShortTitle()
    {
        return getString(SHORT_TITLE_KEY);
    }

    /**
     * Optionally records the identifying path string used to store and
     * retrieve the contents of this NameValuePersonalizationObject from the
     * storage medium.
     *
     * @param path identifying path against which the
     * NameValuePersonalizationObject data is stored
     */
    public void setReferencePath(String path)
    {
        putString(REFERENCE_PATH_KEY, path);
    }

    /**
     * Gets the the identifying path string used to store and retrieve the
     * contents of this NameValuePersonalizationObject from the storage medium.
     *
     * @return identifying path string
     */
    public String getReferencePath()
    {
        return getString(REFERENCE_PATH_KEY);
    }

    /**
     * Retrieves an Enumeration object containing all names in the content of 
     * the NameValuePreferenceDataObject
     * @return Iterator object containing all names
     */
    public Enumeration getNames()
    {
        return mContent.keys();
    }

    /**
     * Records the given Integer value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Integer value
     */
    public void putInteger(String name, Integer value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }


    /**
     * Records the given Double value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Double value
     */
    public void putDouble(String name, Double value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given Float value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Float value
     */
    public void putFloat(String name, Float value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given Long value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Long value
     */
    public void putLong(String name, Long value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given Boolean value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Boolean value
     */
    public void putBoolean(String name, Boolean value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given String value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value String value
     */
    public void putString(String name, String value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given Integer Array value against the given name in the
     * NameValuePersonalizationObject content. If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Integer array value
     */
    public void putIntegerArray(String name, Integer[] value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given Double Array value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Double array value
     */
    public void putDoubleArray(String name, Double[] value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given Float Array value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Float array value
     */
    public void putFloatArray(String name, Float[] value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given Long Array value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Long array value
     */
    public void putLongArray(String name, Long[] value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given Boolean Array value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value Boolean array value
     */
    public void putBooleanArray(String name, Boolean[] value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Records the given String Array value against the given name in the
     * NameValuePersonalizationObject content.  If the name already exists, then 
     * the value for that name will be overwritten with the new value given
     * @param name String name against which the value is to be stored
     * @param value String array value
     */
    public void putStringArray(String name, String[] value)
    {
        mContent.put(name, new TypeValueWrapper(value));
    }

    /**
     * Retrieves the Integer value stored against the given name from the
     * content of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Integer value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given name
     * is not an Integer.
     */
    public Integer getInteger(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Integer)(value.getValue());
    }

    /**
     * Retrieves the Double value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Double value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a Double.
     */
    public Double getDouble(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Double)(value.getValue());
    }

    /**
     * Retrieves the Float value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Float value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a Float.
     */
    public Float getFloat(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Float)(value.getValue());
    }

    /**
     * Retrieves the Long value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Long value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a Long.
     */
    public Long getLong(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Long)(value.getValue());
    }

    /**
     * Retrieves the Boolean value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Boolean value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a Boolean.
     */
    public Boolean getBoolean(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Boolean)(value.getValue());
    }

    /**
     * Retrieves the String value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return String value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a String.
     */
    public String getString(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (String)(value.getValue());
    }

    /**
     * Retrieves the Integer Array value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Integer Array value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not an Integer array.
     */
    public Integer[] getIntegerArray(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Integer[])(value.getValue());
    }

    /**
     * Retrieves the Double Array value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Double Array value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a Double array.
     */
    public Double[] getDoubleArray(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Double[])(value.getValue());
    }

    /**
     * Retrieves the Float Array value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Float Array value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a Float array.
     */
    public Float[] getFloatArray(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Float[])(value.getValue());
    }

    /**
     * Retrieves the Long Array value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Long Array value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a Long array.
     */
    public Long[] getLongArray(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Long[])(value.getValue());
    }

    /**
     * Retrieves the Boolean Array value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return Boolean Array value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a Boolean array.
     */
    public Boolean[] getBooleanArray(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (Boolean[])(value.getValue());
    }

    /**
     * Retrieves the String Array value stored against the given name from the content
     * of the NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     * @return String Array value stored against the given name if one exists, or
     * null otherwise
     * @exception ClassCastException if the value stored against the given
     * name is not a String array.
     */
    public String[] getStringArray(String name)
    {
        TypeValueWrapper value = (TypeValueWrapper)mContent.get(name);
        return value == null ? null : (String[])(value.getValue());
    }
    
    /**
     * Convert the contents of this object to a String representation
     * @return String representation of this object
     */
    public String toString()
    {
        SimpleStringBuffer buf = new SimpleStringBuffer(300);
        Enumeration enum = mContent.keys();
        String key;
        TypeValueWrapper wrapper;
        while (enum.hasMoreElements())
        {
            key = (String)enum.nextElement();
            wrapper = (TypeValueWrapper)mContent.get(key);
            buf.append("Key: '");
            buf.append(key);
            buf.append("', Value: '");
            if (wrapper == null)
            {
                buf.append("{null}");
            }
            else
            {
                buf.append(wrapper.toString());
            }
            buf.append("'  ");
        }
        return buf.toString();
    }

    /**
     * Removes the value stored against the given name from the content of the
     * NameValuePersonalizationObject.
     * @param name String name against which the value is stored
     */
    public void remove(String name)
    {
        mContent.remove(name);
    }

    /**
     * Writes the content of the PersonalizationObject to a given OutputStream
     *
     * @param os OutputStream to which content should be written
     */
    public void write(OutputStream os) throws IOException 
    {
        if (mDebug)
        {
            SimpleStringBuffer buf = new SimpleStringBuffer(300);
            buf.append("Saving NameValuePersonalizationObject. Contents(");
            buf.append(this.toString());
            buf.append(")");
            mLogger.log(buf.toString());
        }    

        // Get a DataOutputStream based on the given output stream, so that
        // we can encode primitive types
        DataOutputStream dos = new DataOutputStream(os);

        // First, write the version number
        dos.writeUTF(mVersion == null ? "-1" : mVersion);

        // Iterate through each key/value pair in the content hash and
        // write type and value to reference file
        for (Enumeration enum = mContent.keys(); enum.hasMoreElements(); )
        {
            String currentKey = (String)enum.nextElement();
            TypeValueWrapper currentVal = (TypeValueWrapper)mContent.get(currentKey);
            writeEntry(currentKey, currentVal, dos);
        }
    }


    /**
     * Populates the PersonalizationObject with content read from a given
     * InputStream
     *
     * @param is InputStream from which content should be read
     */
    public void read(InputStream is) throws IOException 
    {

        // Get a DataInputStream based on the given incode stream, so that
        // we can decode primitive types
        DataInputStream dis = new DataInputStream(is);

        // Make sure we overwrite the old contents, if there were any!
        mContent.clear();

        // First, get the version number
        mVersion = dis.readUTF();

        if(mVersion.equals("-1"))
        {
            mVersion = null;
        }

        // Continue reading entries until we reach the end of the file
        try 
        {
            for(;;) 
            {
                Object[] currentEntry = readEntry(dis);
                if(currentEntry[0] != null && currentEntry[1] != null) 
                {
                    mContent.put(currentEntry[0], currentEntry[1]);
                }
            }

        }
        catch(EOFException eof) 
        {
            // do nothing. This is expected.
            // FIXME: There has to be a better way to do this!!!
        }
        
        if (mDebug)
        {
            SimpleStringBuffer buf = new SimpleStringBuffer(300);
            buf.append("Reading NameValuePersonalizationObject. Contents(");
            buf.append(this.toString());
            buf.append(")");
            mLogger.log(buf.toString());
        }    
    }

    // Encodes a single name/value entry to a DataOutputStream
    private boolean writeEntry(String name, TypeValueWrapper value, DataOutputStream dos)
        throws IOException 
    {

        boolean retCode = true;

        // Write the hash key, <name>, to the output stream
        dos.writeUTF(name);

        // Write the <type> to the output stream from the TypeValueWrapper
        dos.writeInt(value.getType());

        // Write the <value> to the ouput stream from the TypeValueWrapper
        switch (value.getType())
        {
        case INTEGER_TYPE:
            dos.writeInt(((Integer)((TypeValueWrapper)mContent.get(name)).getValue()).intValue());
            break;
        case DOUBLE_TYPE:
            dos.writeDouble(((Double)((TypeValueWrapper)mContent.get(name)).getValue()).doubleValue());
            break;
        case FLOAT_TYPE:
            dos.writeFloat(((Float)((TypeValueWrapper)mContent.get(name)).getValue()).floatValue());
            break;
        case LONG_TYPE:
            dos.writeLong(((Long)((TypeValueWrapper)mContent.get(name)).getValue()).longValue());
            break;
        case BOOLEAN_TYPE:
            dos.writeBoolean(((Boolean)((TypeValueWrapper)mContent.get(name)).getValue()).booleanValue());
            break;
        case STRING_TYPE:
            dos.writeUTF((String)((TypeValueWrapper)mContent.get(name)).getValue());
            break;
        case INTEGER_ARRAY_TYPE:
            {
                Integer[] temp = ((Integer[])((TypeValueWrapper)mContent.get(name)).getValue());
                dos.writeInt(temp.length);
                for (int i = 0; i < temp.length; i++) 
                {
                    dos.writeInt(temp[i].intValue());
                }
            }
            break;
        case DOUBLE_ARRAY_TYPE:
            {
                Double[] temp = ((Double[])((TypeValueWrapper)mContent.get(name)).getValue());
                dos.writeInt(temp.length);
                for (int i = 0; i < temp.length; i++) 
                {
                    dos.writeDouble(temp[i].doubleValue());
                }
            }
            break;
        case FLOAT_ARRAY_TYPE:
            {
                Float[] temp = ((Float[])((TypeValueWrapper)mContent.get(name)).getValue());
                dos.writeInt(temp.length);
                for (int i = 0; i < temp.length; i++) 
                {
                    dos.writeFloat(temp[i].floatValue());
                }
            }
            break;
        case LONG_ARRAY_TYPE:
            {
                Long[] temp = ((Long[])((TypeValueWrapper)mContent.get(name)).getValue());
                dos.writeInt(temp.length);
                for (int i = 0; i < temp.length; i++) 
                {
                    dos.writeLong(temp[i].longValue());
                }
            }
            break;
        case BOOLEAN_ARRAY_TYPE:
            {
                Boolean[] temp = ((Boolean[])((TypeValueWrapper)mContent.get(name)).getValue());
                dos.writeInt(temp.length);
                for (int i = 0; i < temp.length; i++) 
                {
                    dos.writeBoolean(temp[i].booleanValue());
                }
            }
            break;
        case STRING_ARRAY_TYPE:
            {
                String[] temp = ((String[])((TypeValueWrapper)mContent.get(name)).getValue());
                dos.writeInt(temp.length);
                for (int i = 0; i < temp.length; i++) 
                {
                    dos.writeUTF(temp[i]);
                }
            }
            break;
        }//end switch

        return retCode;
    }

    // Decodes a single name/value entry from a DataInputStream
    private Object[] readEntry(DataInputStream dis) throws IOException 
    {

        Object[] retVal = {null, null};
        TypeValueWrapper currentValue = null;

        // First read the name and type
        String currentName = dis.readUTF();
        // Read correct value format and assign type and value to currentValue
        switch (dis.readInt())
        {
        case INTEGER_TYPE:
            currentValue = new TypeValueWrapper(new Integer(dis.readInt()));
            break;
        case DOUBLE_TYPE:
            currentValue = new TypeValueWrapper(new Double(dis.readDouble()));
            break;
        case FLOAT_TYPE:
            currentValue = new TypeValueWrapper(new Float(dis.readFloat()));
            break;
        case LONG_TYPE:
            currentValue = new TypeValueWrapper(new Long(dis.readLong()));
            break;
        case BOOLEAN_TYPE:
            currentValue = new TypeValueWrapper(new Boolean(dis.readBoolean()));
            break;
        case STRING_TYPE:
            currentValue = new TypeValueWrapper(dis.readUTF());
            break;
        case INTEGER_ARRAY_TYPE:
            {
                int arrayLength = dis.readInt();
                Integer[] temp = new Integer[arrayLength];
                for (int i = 0; i < arrayLength; i++)
                {
                    temp[i] = new Integer(dis.readInt());
                }
                currentValue = new TypeValueWrapper(temp);
            }
            break;
        case DOUBLE_ARRAY_TYPE:
            {
                int arrayLength = dis.readInt();
                Double[] temp = new Double[arrayLength];
                for (int i = 0; i < arrayLength; i++)
                {
                    temp[i] = new Double(dis.readDouble());
                }
                currentValue = new TypeValueWrapper(temp);
            }
            break;
        case FLOAT_ARRAY_TYPE:
            {
                int arrayLength = dis.readInt();
                Float[] temp = new Float[arrayLength];
                for (int i = 0; i < arrayLength; i++)
                {
                    temp[i] = new Float(dis.readFloat());
                }
                currentValue = new TypeValueWrapper(temp);
            }
            break;
        case LONG_ARRAY_TYPE:
            {
                int arrayLength = dis.readInt();
                Long[] temp = new Long[arrayLength];
                for (int i = 0; i < arrayLength; i++)
                {
                    temp[i] = new Long(dis.readLong());
                }
                currentValue = new TypeValueWrapper(temp);
            }
            break;
        case BOOLEAN_ARRAY_TYPE:
            {
                int arrayLength = dis.readInt();
                Boolean[] temp = new Boolean[arrayLength];
                for (int i = 0; i < arrayLength; i++)
                {
                    temp[i] = new Boolean(dis.readBoolean());
                }
                currentValue = new TypeValueWrapper(temp);
            }
            break;
        case STRING_ARRAY_TYPE:
            {
                int arrayLength = dis.readInt();
                String[] temp = new String[arrayLength];
                for (int i = 0; i < arrayLength; i++)
                {
                    temp[i] = dis.readUTF();
                }
                currentValue = new TypeValueWrapper(temp);
            }
            break;
        }

        retVal[0] = currentName;
        retVal[1] = currentValue;

        return retVal;
    }

    // Private wrapper class for storing value and type information
    private static class TypeValueWrapper 
    {

        private int mType;
        private Object mValue;

        // Overridden constructors for each of the supported types
        public TypeValueWrapper(Integer value)
        {
            mType = INTEGER_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Double value)
        {
            mType = DOUBLE_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Float value)
        {
            mType = FLOAT_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Long value)
        {
            mType = LONG_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Boolean value)
        {
            mType = BOOLEAN_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(String value)
        {
            mType = STRING_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Integer[] value)
        {
            mType = INTEGER_ARRAY_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Double[] value)
        {
            mType = DOUBLE_ARRAY_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Float[] value)
        {
            mType = FLOAT_ARRAY_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Long[] value)
        {
            mType = LONG_ARRAY_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(Boolean[] value)
        {
            mType = BOOLEAN_ARRAY_TYPE;
            mValue = value;
        }

        public TypeValueWrapper(String[] value)
        {
            mType = STRING_ARRAY_TYPE;
            mValue = value;
        }

        public int getType()
        {
            return mType;
        }

        public Object getValue(){
            return mValue;
        }

        public String toString()
        {
            return mValue.toString();
        }
    }
}


