package org.seasar.struts;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.config.ActionConfig;
import org.apache.struts.config.ModuleConfig;
import org.seasar.framework.container.ComponentDef;
import org.seasar.framework.container.ContainerConstants;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
import org.seasar.framework.container.impl.ComponentDefImpl;
import org.seasar.struts.action.ComponentNameCreator;
import org.seasar.struts.action.ComponentNameCreatorImpl;
import org.seasar.struts.action.ProxyAction;
import org.seasar.struts.util.ClassRegister;

/**
 * S2Strutsを使用する為に必要な初期化を行う。
 * 
 * @author Satoshi Kimura
 */
public class S2StrutsInitializer {
    private static Log log = LogFactory.getLog(S2StrutsInitializer.class);

    private S2StrutsInitializer() {
    }

    /**
     * {@link S2Container}に対して、S2Strutsに必要なコンポーネントを登録する。
     */
    public synchronized static void init() {
        S2Container container = SingletonS2ContainerFactory.getContainer();
        regist(container, ComponentNameCreator.class, ComponentNameCreatorImpl.class);
    }

    private static void regist(S2Container container, Class interfaceClass, Class component) {
        if (false == container.hasComponentDef(interfaceClass)) {
            log.debug("regist " + interfaceClass + " : component=" + component);
            container.register(component);
        }
    }
    private static void regist(S2Container container, Class interfaceClass, ComponentDef component) {
        if (false == container.hasComponentDef(interfaceClass)) {
            log.debug("regist " + interfaceClass + " : component=" + component);
            container.register(component);
        }
    }

    public static void registActionClass(ActionServlet servlet) {
        ModuleConfig[] configs = getModuleConfigs(servlet);
        for (int i = 0; i < configs.length; i++) {
            registActionClass(servlet, configs[i]);
        }

    }
    public static void registActionClass(ActionServlet servlet, ModuleConfig config) {
        S2Container container = SingletonS2ContainerFactory.getContainer();
        ActionConfig[] actionConfigs = config.findActionConfigs();
        ClassRegister classRegister = (ClassRegister) container.getComponent(ClassRegister.class);
        for (int i = 0; i < actionConfigs.length; i++) {
            ActionConfig actionConfig = actionConfigs[i];
            String actionClassName = actionConfig.getType();
            if (actionClassName != null) {
                Class actionClass = classRegister.getClass(actionClassName);
                if (actionClass.isInterface() == false) {
                    ComponentDef def = new ComponentDefImpl(actionClass);
                    if (actionClass.equals(ProxyAction.class) == false) {
                        def.setInstanceMode(ContainerConstants.INSTANCE_PROTOTYPE);
                    }
                    regist(container, actionClass, def);
                }
            }
        }
    }

    private static ModuleConfig[] getModuleConfigs(ActionServlet actionServlet) {
        List values = new ArrayList();
        Enumeration names = actionServlet.getServletContext().getAttributeNames();
        while (names.hasMoreElements()) {
            values.add(names.nextElement());
        }

        Iterator keys = values.iterator();
        List moduleConfigs = new ArrayList();
        while (keys.hasNext()) {
            String name = (String) keys.next();
            Object value = actionServlet.getServletContext().getAttribute(name);

            if (value instanceof ModuleConfig) {
                moduleConfigs.add(value);
            }
        }
        return (ModuleConfig[]) moduleConfigs.toArray(new ModuleConfig[moduleConfigs.size()]);
    }

}