/*
 * blancoIg
 * Copyright (C) 2004-2005 Yasuo Nakanishi
 * 
 * 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.
 */
package blanco.struts.expander.action;

import java.util.Iterator;

import blanco.ig.expander.Scope;
import blanco.ig.expander.Type;
import blanco.ig.expander.Value;
import blanco.ig.expander.implementor.ImplementData;
import blanco.ig.expander.method.MethodExpander;
import blanco.struts.definition.form.Form;
import blanco.struts.definition.form.FormEvent;

/**
 * @author Yasuo Nakanishi
 */
public class DispatchMethod extends MethodExpander {
    private String _eventParameterName = null;

    private String _methodName = null;

    private Form _form = null;

    private Type _formType = null;

    public DispatchMethod(String methodName, String eventParameterName,
            Type formType, Form form) {
        super(methodName);
        _methodName = methodName;
        _eventParameterName = eventParameterName;
        _form = form;
        _formType = formType;
    }

    public void setupSignature() {
        setScope(Scope.PUBLIC);

        addException(new Type("java.lang.Exception"));

        getJavaDoc().addParameter("mapping", "ActionMappingオブジェクト。");
        addArgument(new Value(
                new Type("org.apache.struts.action.ActionMapping"), "mapping"));
        // フォームだけは自分が関連する具象クラスをセットします。
        getJavaDoc().addParameter("form", "Strutsから渡される ActionForm オブジェクト。");
        addArgument(new Value(new Type("org.apache.struts.action.ActionForm"),
                "form"));
        getJavaDoc().addParameter("request", "Servletから得られるrequestオブジェクト。");
        addArgument(new Value(
                new Type("javax.servlet.http.HttpServletRequest"), "request"));
        getJavaDoc().addParameter("response", "Servletから得られるresponseオブジェクト。");
        addArgument(new Value(
                new Type("javax.servlet.http.HttpServletResponse"), "response"));
        if (_form.isUsingDb()) {
            getJavaDoc().addParameter("connection", "データベース接続オブジェクト。");
            addArgument(new Value(new Type("java.sql.Connection"), "connection"));
        }

        setScope(Scope.PUBLIC);
        setFinal(true);
        setReturnType(new Type("org.apache.struts.action.ActionForward"));

        getJavaDoc().addLine("リクエストについてイベントの振り分けを実行します。");
        getJavaDoc().addLine(_methodName + " メソッド。");
    }

    public void implement() {
        getData().addLine("ActionForward result = null;");
        getData().addLine(
                _form.getName() + " actionForm = (" + _form.getName()
                        + ") form;");
        getData().addLine("");
        getData().addLine(
                "String event = request.getParameter(\"" + _eventParameterName
                        + "\");");
        getData().addLine("if (event == null || event.equals(\"\")) {");
        getData().addLine(
                "event = (String) request.getAttribute(\""
                        + _eventParameterName + "\");");
        getData().addLine("}");
        getData().addLine("if (event == null || event.equals(\"\")){");
        getData().addLine("String message = \"イベントIDがUIから渡されませんでした。\";");
        getData().addLine("throw new Exception(message);");
        getData().addLine("}");
        getData().addLine("");

        if (_form.isUsingDb()) {
            getData()
                    .addLine(
                            "init(mapping, actionForm, request, response, connection);");
        } else {
            getData().addLine("init(mapping, actionForm, request, response);");
        }
        getData().addLine("");
        getData().addLine("if (event.equals(\"load\")){");
        if (_form.isUsingDb()) {
            getData()
                    .addLine(
                            "result = onLoad(mapping, actionForm, request, response, connection);");
        } else {
            getData().addLine(
                    "result = onLoad(mapping, actionForm, request, response);");
        }

        Iterator eventIterator = _form.getEventIterator();
        // 2005.05.26 t.iga イベントIDによる振り分けを実施
        while (eventIterator.hasNext()) {
            FormEvent formEvent = (FormEvent) eventIterator.next();

            getData().addLine(
                    "} else if (event.equals(\"" + formEvent.getName()
                            + "\")) {");

            callOnEvent(getData(), formEvent);

            if (formEvent.getKoumokuNihongoMei() != null
                    && formEvent.getKoumokuNihongoMei().length() > 0) {
                // 2005.05.26 t.iga 項目日本語名が入っている場合には、そちらでも比較します。
                getData().addLine(
                        "} else if (event.equals(\""
                                + formEvent.getKoumokuNihongoMei() + "\")) {");
                getData().addLine("// 「項目日本語名」の指定があるのでイベント振り分け条件に利用します.");

                callOnEvent(getData(), formEvent);
            }
        }
        getData().addLine("} else {");
        getData().addLine("String message = \"不正なイベントIDがUIから渡されました。イベントID:\";");
        getData().addLine("message += event;");
        getData().addLine("throw new Exception(message);");
        getData().addLine("}");

        // saveTokenが有効な場合に生成します。
        if (_form.isSaveToken()) {
            getData().addLine("");
            getData().addLine(
                    "// Action設定 の Token保存 が有効に設定されているので Tokenを保存します。");
            getData().addLine("saveToken(request);");
            getData().addLine("");
        }
        getData().addLine("return result;");
    }

    /**
     * OnEventを実装します。
     * 
     * @param si
     * @param result
     * @param parameters
     * @param formEvent
     */
    private void callOnEvent(ImplementData si, FormEvent formEvent) {
        if (formEvent.isCheckToken()) {
            si.addLine("// Token確認の仕組みをここに挿入");
            si.addLine("// Token確認 の設定が有効になっています");
            si.addLine("if (!isTokenValid(request, true)) {");
            si.addLine("// Token が無効な場合のエラー処理を行います（業務APで実装）");

            String strLine = "result = foundInvalidTokenOnClick"
                    + getNameAdjuster().toTitleCase(formEvent.getName())
                    + "(mapping, actionForm, request, response";
            if (_form.isUsingDb()) {
                strLine += ", connection";
            }
            strLine += ");";
            si.addLine(strLine);

            si.addLine("if (result != null) {");
            si.addLine("return result;");
            si.addLine("}");
            si.addLine("}");
        }

        String eventMethod = EventMethod.createEventName(formEvent.getName());
        if (_form.isUsingDb()) {
            si.addLine("result = " + eventMethod
                    + "(mapping, actionForm, request, response, connection);");
        } else {
            si.addLine("result = " + eventMethod
                    + "(mapping, actionForm, request, response);");
        }
    }
}
