/*
 * Copyright (C) 2004 TiongHiang Lee
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not,  write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Email: thlee@onemindsoft.org
 */

package org.onemind.commons.java.datastructure;

import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
import org.onemind.commons.java.lang.reflect.ReflectUtils;
import org.onemind.commons.java.xml.digest.*;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
 * A Sax elemenbt handler that can handle parsing properties specified in an xml file
 * This syntax of the xml is something like 
 *  <Property name="defaultvalue" value="default"/>
    <Property name="shortvalue" type="short" value="1"/>
    <Property name="intvalue" type="int" value="1"/>
    <Property name="longvalue" type="long" value="1"/>
    <Property name="floatvalue" type="float" value="1"/>
    <Property name="doublevalue" type="double" value="1"/>
    <Property name="charvalue" type="char" value="c"/>
    <Property name="stringvalue" type="string" value="string"/>    
 * @author TiongHiang Lee (thlee@onemindsoft.org)
 */
public class XmlPropertyElementDigester extends DefaultDigester implements ElementDigester
{

    private static final Map _typeMap;
    static
    {
        _typeMap = new HashMap();
        _typeMap.put("short", new Integer(Types.SMALLINT));
        _typeMap.put("int", new Integer(Types.INTEGER));
        _typeMap.put("long", new Integer(Types.BIGINT));
        _typeMap.put("float", new Integer(Types.FLOAT));
        _typeMap.put("double", new Integer(Types.DOUBLE));
        _typeMap.put("boolean", new Integer(Types.BOOLEAN));
        _typeMap.put("char", new Integer(Types.CHAR));
        _typeMap.put("string", new Integer(Types.VARCHAR));
    }

    private final Map _prop;

    public XmlPropertyElementDigester(String elementName, Map prop)
    {
        super(elementName);
        _prop = prop;
    }

    /** 
     * {@inheritDoc}
     */
    public void startDigest(SaxDigesterHandler handler, Attributes attrs) throws SAXException
    {
        String name = attrs.getValue("name");
        String type = attrs.getValue("type");
        String value = attrs.getValue("value");
        String clazz = attrs.getValue("class");
        if (name == null)
        {
            throw new SAXException("name attribute must exists on property");
        }
        if (type != null && clazz != null)
        {
            throw new SAXException("Both type and class cannot be specified on same property");
        }
        if (clazz != null)
        {
            try
            {
                Class c = ReflectUtils.getClass(clazz);
                Object obj = (Object) ReflectUtils.newInstance(c, null);
                String digest = attrs.getValue("digest");
                if (digest != null && digest.equalsIgnoreCase("true"))
                {
                    if (clazz != null)
                    {
                        if (!ElementDigester.class.isAssignableFrom(obj.getClass()))
                        {
                            throw new SAXException("Class " + clazz + " is not a subclass of ElementDigester");
                        }
                        ElementDigester dig = (ElementDigester) obj;
                        handler.addSubDigester(dig);
                        _prop.put(name, dig);
                    }
                } else
                {//just put the object as a property
                    _prop.put(name, obj);
                }
            } catch (Exception e)
            {
                throw new SAXException(e.getMessage(), e);
            }
        } else if (type != null)
        {
            Object v = null;
            Integer typeInt = (Integer) _typeMap.get(type);
            if (typeInt == null)
            {
                throw new SAXException("Unrecognized property type " + type);
            } else
            {
                switch (typeInt.intValue())
                {
                    case Types.SMALLINT :
                        v = Short.valueOf(value);
                        break;
                    case Types.INTEGER :
                        v = Integer.valueOf(value);
                        break;
                    case Types.BIGINT :
                        v = Long.valueOf(value);
                        break;
                    case Types.FLOAT :
                        v = Float.valueOf(value);
                        break;
                    case Types.DOUBLE :
                        v = Double.valueOf(value);
                        break;
                    case Types.BOOLEAN :
                        v = Boolean.valueOf(value);
                        break;
                    case Types.CHAR :
                        v = new Character(value.charAt(0));
                        break;
                    case Types.VARCHAR :
                        v = value;
                        break;
                    default :
                        throw new IllegalStateException("Unrecognized property type " + type);
                }
            }
            _prop.put(name, v);
        } else
        {
            _prop.put(name, value);
        }
    }

    /** 
     * {@inheritDoc}
     */
    public void endDigest(SaxDigesterHandler handler) throws SAXException
    {
        // TODO Auto-generated method stub
    }

    /** 
     * {@inheritDoc}
     */
    public void characters(SaxDigesterHandler handler, char[] chars, int offset, int length) throws SAXException
    {
        // TODO Auto-generated method stub
    }
}
