/* $Id: LPCData.java,v 1.1.1.1 1998/10/27 20:34:03 borg Exp $ */
/* Copyright (c) 1997 George Reese */
package com.imaginary.mud;

import java.util.Hashtable;
import java.util.Vector;

/**
 * The LPCData class represents the Java value of an LPC string that
 * represents some LPC data type.  You construct it using the string
 * representing the LPC constant data.
 * <BR>
 * Last modified $Date: 1998/10/27 20:34:03 $
 * @version $Revision: 1.1.1.1 $
 * @author George Reese (borg@imaginary.com)
 */
public class LPCData {
    private Object value;

    /**
     * Constructs a new LPCData object from a string containing the
     * representation of an LPC data type.  The typical use might be:
     * <PRE>
     * String str = "([\"house\":1,])";
     * LPCData d = new LPCData(str);
     * Hashtable h = d.getHashtable();
     * </PRE>
     * @param str the string representing an LPC constant
     * @exception COM.imaginary.text.LPCDataFormatException a bad LPC string was
     * passed
     */
    public LPCData(String str) throws LPCDataFormatException {
        value =  toJava(str, false);
    }

    /**
     * Constructs a new LPCData object from a StringBuffer containing the
     * representation of an LPC data type. 
     * @param str the StringBuffer representing an LPC constant
     * @exception COM.imaginary.text.LPCDataFormatException a bad LPC string was
     * passed
     */
    public LPCData(StringBuffer str) throws LPCDataFormatException {
        value =  toJava(new String(str), false);
    }

    private Object toJava(String str, boolean flag)
    throws LPCDataFormatException {
        Vector data = new Vector(2);

        data.addElement(null);
        data.addElement("");
        if( str == null ) {
            if( ! flag ) {
                return "";
            }
            else {
                return data;
            }
        }
        str = str.trim();
        if( str.length() < 1 ) {
            if( !flag ) {
                return "";
            }
            else {
                return data;
            }
        }
        else if( str.length() == 1 ) {
            try {
                int x = Integer.parseInt(str);

                if( !flag ) {
                    return new Integer(x);
                }
                else {
                    data.setElementAt(new Integer(x), 0);
                    return data;
                }
            }
            catch( NumberFormatException e ) {
                throw new LPCDataFormatException("Invalid LPC Data in string: " +
					      str);
            }
        }
        if( str.charAt(0) == '(' ) {
            switch(str.charAt(1)) {
                case '{':
                {
                    Vector v = new Vector();

                    str = str.substring(2, str.length());
                    while( str.charAt(0) != '}' ) {
                        Vector tmp = (Vector)toJava(str, true);

                        v.addElement(tmp.elementAt(0));
                        str = ((String)tmp.elementAt(1)).trim();
                        if( str.length() < 1 || (str.charAt(0) != ',' &&
						 str.charAt(0) != '}') ) {
                            throw new LPCDataFormatException("Invalid LPC Data " +
							  "in string: " + str);
                        }
                        else if( str.charAt(0) == ',' ) {
                            str = str.substring(1, str.length());
                            str = str.trim();
                        }
                    }
                    if( str.charAt(1) != ')' ) {
                        str = str.substring(2, str.length());
                        str = str.trim();
                        if( str.charAt(0) != ')' ) {
                            throw new LPCDataFormatException("Illegal array " +
							  "terminator.");
                        }
                        else {
                            data.setElementAt(str.substring(1, str.length()),
					      1);
                        }
                    }
                    else {
                        data.setElementAt(str.substring(2,str.length()), 1);
                    }
                    if( !flag ) return v;
                    data.setElementAt(v, 0);
                    return data;
                }

                case '[':
                {
                    Hashtable h = new Hashtable();

                    str = str.substring(2, str.length());
                    while( str.charAt(0) != ']' ) {
                        Vector tmp = (Vector)toJava(str, true);
                        Object key, value;

                        str = (String)tmp.elementAt(1);
                        str = str.trim();
                        if( str.charAt(0) != ':' ) {
                            throw new LPCDataFormatException("Invalid mapping " +
							  "format: " + str);
                        }
                        else {
                            str = str.substring(1, str.length());
                        }
                        key = tmp.elementAt(0);
                        tmp = (Vector)toJava(str, true);
                        value = tmp.elementAt(0);
                        str = (String)tmp.elementAt(1);
                        h.put(key, value);
                        str = str.trim();
                        if( str.charAt(0) != ',' && str.charAt(0) != ']' ) {
                            throw new LPCDataFormatException("Invalid mapping " +
							  "format: " + str);
                        }
                        else if( str.charAt(0) != ']' ) {
                            str = str.substring(1, str.length());
                            str = str.trim();
                        }
                    }
                    if( str.charAt(1) != ')' ) {
                        str = str.substring(2, str.length()).trim();
                        if( str.charAt(0) != ')' ) {
                            throw new LPCDataFormatException("Invalid mapping " +
							  "format: " + str);
                        }
                        else {
			    data.setElementAt(str.substring(1,
							  str.length()).trim(),
					      1);
			}
                    }
                    else {
			data.setElementAt(str.substring(2,
							str.length()).trim(),
					  1);
		    }
                    if( !flag ) {
                        return h;
                    }
                    data.setElementAt(h, 0);
                    return data;
                }

                default:
                throw new LPCDataFormatException("Invalid LPC Data in string: " +
					      str);
            }
        }
        else if( str.charAt(0) == '"' ) {
            String tmp = "";
            char prior = '\0';
            char next = str.charAt(1);

            while( next != '"' || (next == '"' && str.charAt(0) == '\\') ) {
                if( next == '"' && str.charAt(0) == '\\' && prior == '\\') {
                    break;
                }
                if( next != '\\' || str.charAt(0) == '\\') {
                    tmp += next;
                }
                prior = str.charAt(0);
                str = str.substring(1, str.length());
                next = str.charAt(1);
            }
            if( !flag ) {
                return tmp;
            }
            if( str.length() > 2 ) {
                str = str.substring(2, str.length()).trim();
            }
            data.setElementAt(tmp, 0);
            data.setElementAt(str, 1);
            return data;
        }
        else if( Character.isDigit(str.charAt(0)) || str.charAt(0) == '-' ) {
            String tmp;
            int x;

            if( str.length() > 1 && str.startsWith("0x" ) ) {
                tmp = "0x";
                str = str.substring(2, str.length());
            }
            else if( str.length() > 1 && str.startsWith("-") ) {
                tmp = "-";
                str = str.substring(1, str.length());
            }
            else {
                tmp = "";
            }
            while( !str.equals("") && (Character.isDigit(str.charAt(0))) ) {
                tmp += str.charAt(0);
              //  tmp += str.substring(0, 1);
                if( str.length() > 1 ) {
                    str = str.substring(1, str.length());
                }
                else {
                    str = "";
                }
            }
            try {
                x = Integer.parseInt(tmp);
            }
            catch( NumberFormatException e ) {
                throw new LPCDataFormatException("Invalid number format: " + tmp);
            }
            if( !flag ) {
                return new Integer(x);
            }
            data.setElementAt(new Integer(x), 0);
            data.setElementAt(str, 1);
            return data;
        }
        throw new LPCDataFormatException("Gobbledygook in string.");
    }

    /**
     * @return a float value for the LPC float this object represents
     */
    public float getFloat() {
	return ((Float)value).floatValue();
    }
    
    /**
     * @return a Hashtable value for the LPC mapping this object represents
     */
    public Hashtable getHashtable() {
	return (Hashtable)value;
    }

    /**
     * @return an int value for the LPC int this object represents
     */
    public int getInt() {
	return ((Integer)value).intValue();
    }

    /**
     * @return an Integer value for the LPC int this object represents
     */
    public Integer getInteger() {
	return (Integer)value;
    }

    /**
     * @return an Object
     */
    public Object getObject() {
	return value;
    }
    
    /**
     * @return a String value for the LPC string this object represents
     */
    public String getString() {
	return (String)value;
    }

    /**
     * @return a Vector value for the LPC array this object represents
     */
    public Vector getVector() {
	return (Vector)value;
    }
}