/*
 * $Revision: 223 $ $Date: 2007-10-14 17:07:40 +0900 $
 * Copyright (C) 2004-2005 SUGIMOTO Ken-ichi
 */

package feat2.xmlcommand;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * <p>XMLをオブジェクトに変換するクラス。このクラスで読み取れる形式は次のとおり。</p><pre>
 * &lt;command&gt;
 * 　　&lt;object class="クラス名" name="親オブジェクトのプロパティ名"&gt;
 * 　　　　&lt;property name="プロパティ名"&gt;プロパティの値&lt;/property&gt;
 * 　　　　&lt;property ...&gt; ... &lt;/property&gt;
 * 　　　　&lt;object ... &gt; ... &lt;/object&gt;
 * 　　&lt;/object&gt;
 * &lt;/command&gt;
 * </pre>
 */
public class ObjectHandler
        extends DefaultHandler {

    private static final Log log = LogFactory.getLog(ObjectHandler.class);

    private HashMap[] objectStack;
    private int stackPointer;
    //private Map classMap;
    private String currentProperty;
    private String featureName;
    private String commandName;

    public ObjectHandler() {
        objectStack = new HashMap[10];
        stackPointer = 0;
        //this.classMap = classMap;
        currentProperty = null;
    }

    public void startElement(String uri, String localName, String qName,
                             Attributes attributes)
            throws SAXException {

        log.debug("startElement:"+qName);

        if ( qName.equals("command") ) {
            commandName = attributes.getValue("commandname");
            featureName = attributes.getValue("featurename");
        }

        if (qName.equals("object")) {
            if (objectStack.length > stackPointer) {
                HashMap obj = new HashMap();
                if ( getCurrentObject() != null && attributes.getValue("name") != null ) {
                    getCurrentObject().put(attributes.getValue("value"), obj);
                }
                objectStack[stackPointer++] = obj;
            }
        }

        if ( qName.equals("property") ) {
            if ( attributes.getValue("name") != null ) {
                String isNull = attributes.getValue("isNull");
                if ( isNull != null && isNull.equals("true") )
                    currentProperty = null;
                else
                    currentProperty = attributes.getValue("name");
            }
        }

    }

    /*private Object newInstance(String objectName) throws
            CommandException {

        String className = (String) classMap.get(objectName);
        // クラス名マッピングが定義されていなかったらエラー
        if ( className == null )
            throw new CommandException("mapping ga teigi sarete inai.");
        try {
            Class clazz = getClass().getClassLoader().loadClass(
                    className);
            Object obj = clazz.newInstance();
            return obj;
        }
        catch (ClassNotFoundException ex) {
            throw new CommandException("ClassNotFoundException - "+ex.getMessage());
        }
        catch (InstantiationException ex) {
            throw new CommandException("InstantiationException - "+ex.getMessage());
        }
        catch (IllegalAccessException ex) {
            throw new CommandException("IllegalAccessException - "+ex.getMessage());
        }
    }*/

    private HashMap getCurrentObject() {
        if ( stackPointer > 0 )
            return objectStack[stackPointer-1];
        else
            return null;
    }

    public void characters(char[] ch, int start, int length) throws
            SAXException {

        String value = new String(ch, start, length);

        log.debug("property:"+currentProperty+"="+value);

        /*p("もとの文字列:" + value);
        value = Utils.urlDecode(value, "UTF8");
        p("characters:" + value);*/

        try {

            Utils.setPropertyString(getCurrentObject(), currentProperty, value);

        }
        catch (InvocationTargetException ex) {
            throw new SAXException(ex);
        }
        catch (NoSuchMethodException ex) {
            throw new SAXException(ex);
        }
        catch (IllegalAccessException ex) {
            throw new SAXException(ex);
        }

    }

    public void endElement(String uri, String localName, String qName) {
        log.debug("emdElement:"+qName);
        if ( stackPointer > 0 && qName.equals("object") ) {
            stackPointer--;
        }
    }

    /**
     * このハンドラが読み取ったオブジェクトツリーの先頭オブジェクトを返す。
     * @return Object
     */
    public Map getObject() {
        return objectStack[0];
    }

    public String getCommandName() {
        return commandName;
    }

    public String getFeatureName() {
        return featureName;
    }


}
