/*
 * blanco Framework
 * Copyright (C) 2004-2009 IGA Tosiki
 * 
 * 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.jsf;

import java.io.File;
import java.util.List;

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.transformer.BlancoCgTransformerFactory;
import blanco.cg.valueobject.BlancoCgInterface;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.commons.util.BlancoNameAdjuster;
import blanco.commons.util.BlancoNameUtil;
import blanco.commons.util.BlancoStringUtil;
import blanco.jsf.valueobject.BlancoJsfBeanItemStructure;
import blanco.jsf.valueobject.BlancoJsfStructure;

/**
 * 処理(blancoJsf)のためのメインクラス。
 * 
 * 処理インタフェースを展開します。
 */
class BlancoJsfExpandLogic {
    /**
     * 内部的に利用するblancoCg用ファクトリ。
     */
    private BlancoCgObjectFactory fCgFactory = null;

    /**
     * 内部的に利用するblancoCg用ソースファイル情報。
     */
    private BlancoCgSourceFile fCgSourceFile = null;

    /**
     * 内部的に利用するblancoCg用クラス情報。
     */
    private BlancoCgInterface fCgInterface = null;

    /**
     * 自動生成するソースファイルの文字エンコーディング。
     */
    private String fEncoding = null;

    public void setEncoding(final String argEncoding) {
        fEncoding = argEncoding;
    }

    /**
     * 収集された情報を元に、ソースコードを自動生成します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     * @param argRuntimePackage
     *            ランタイムパッケージ。nullおよび長さ0の文字列の場合は定義書ごとにランタイムクラスを生成。
     * @param argTargetLang
     *            出力対象プログラミング言語。
     * @param argDirectoryTarget
     *            ソースコードの出力先フォルダ。
     */
    public void expandSourceFile(final BlancoJsfStructure argProcessStructure,
            final List<String> sqlClassNameList, final File argDirectoryTarget) {

        // 従来と互換性を持たせるため、/mainサブフォルダに出力します。
        final File fileBlancoMain = new File(argDirectoryTarget
                .getAbsolutePath()
                + "/main");

        fCgFactory = BlancoCgObjectFactory.getInstance();
        fCgSourceFile = fCgFactory.createSourceFile(argProcessStructure
                .getPackage(), null);
        fCgSourceFile.setEncoding(fEncoding);
        fCgInterface = fCgFactory.createInterface(
                getProcessInterfaceName(argProcessStructure), BlancoStringUtil
                        .null2Blank(argProcessStructure.getDescription()));
        fCgSourceFile.getInterfaceList().add(fCgInterface);

        fCgInterface.setDescription("処理 ["
                + getProcessInterfaceName(argProcessStructure) + "]インタフェース。");
        fCgInterface.getLangDoc().getDescriptionList().add(
                "このインタフェースを継承して [" + argProcessStructure.getPackage()
                        + "]パッケージに["
                        + getProcessInterfaceName(argProcessStructure)
                        + "]クラスを作成して実際のバッチ処理を実装してください。<br>");
        fCgInterface.getLangDoc().getDescriptionList().add("");

        expandMethodExecute(argProcessStructure, sqlClassNameList);

        BlancoCgTransformerFactory.getJavaSourceTransformer().transform(
                fCgSourceFile, fileBlancoMain);
    }

    /**
     * execute メソッドを展開します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     */
    private void expandMethodExecute(
            final BlancoJsfStructure argProcessStructure,
            final List<String> sqlClassNameList) {
        final BlancoCgMethod method = fCgFactory.createMethod("execute",
                "クラスをインスタンス化して処理を実行する際のエントリポイントです。");
        fCgInterface.getMethodList().add(method);
        method.setFinal(true);

        for (BlancoJsfBeanItemStructure bean : argProcessStructure
                .getBeanList()) {
            // TODO 入力、出力、入出力への対応。
            String name = BlancoNameUtil.trimJavaPackage(bean.getName());
            method.getParameterList().add(
                    fCgFactory.createParameter("arg" + name, bean.getName(),
                            "処理の入力パラメータ。"));
        }

        // TODO SQL の処理が未対応。
        for (String sqlClassName : sqlClassNameList) {
            String name = BlancoNameUtil.trimJavaPackage(sqlClassName);
            method.getParameterList().add(
                    fCgFactory.createParameter("arg" + name, sqlClassName,
                            "処理の入力パラメータ。"));
        }

        if (argProcessStructure.getForward()) {
            // 戻り値ありなら String
            method.setReturn(fCgFactory.createReturn("java.lang.String",
                    "処理の実行結果。success, error などの遷移先に関する文字列を返却。"));
        }

        method.getThrowList().add(
                fCgFactory.createException("java.io.IOException",
                        "入出力例外が発生した場合。"));
        method.getThrowList().add(
                fCgFactory
                        .createException("java.lang.IllegalArgumentException",
                                "入力値に不正が見つかった場合。"));
    }

    private String getProcessInterfaceName(final BlancoJsfStructure argStructure) {
        return BlancoNameAdjuster.toClassName(argStructure.getName())
                + argStructure.getSuffix();
    }
}
