package blanco.terasoluna.blogic;

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

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.transformer.java.BlancoCgJavaSourceTransformer;
import blanco.cg.valueobject.BlancoCgClass;
import blanco.cg.valueobject.BlancoCgField;
import blanco.cg.valueobject.BlancoCgInterface;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgParameter;
import blanco.cg.valueobject.BlancoCgReturn;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.cg.valueobject.BlancoCgType;
import blanco.commons.util.BlancoNameAdjuster;
import blanco.terasoluna.blogic.valueobject.BlancoTerasolunaBLogicStructure;

public class BlancoTerasolunaBLogic {
    private BlancoCgObjectFactory fCgFactory;

    private BlancoTerasolunaBLogicStructure fStructure;

    public void process(final BlancoTerasolunaBLogicStructure argStructure) {
        fStructure = argStructure;

        fCgFactory = BlancoCgObjectFactory.getInstance();

        generateBLogicProxy();
        generateBLogicInterface();

        if (fStructure.getUseProxy()) {
            generateAbstractBLogic();
        }
    }

    private void generateBLogicProxy() {
        final BlancoCgSourceFile cgSource = fCgFactory.createSourceFile(
                fStructure.getPackage(), null);
        final BlancoCgClass cgClass = fCgFactory
                .createClass(
                        BlancoNameAdjuster.toClassName(fStructure.getName())
                                + "BLogicProxy",
                        "["
                                + fStructure.getName()
                                + "] ["
                                + fStructure.getDescription()
                                + "]ビジネスロジックのプロキシクラス。TERASOLUNAに依存する記述について、可能な限り このクラスに集約されています。");
        cgSource.getClassList().add(cgClass);
        final BlancoCgType cgType = fCgFactory
                .createType("jp.terasoluna.fw.service.thin.BLogic<"
                        + fStructure.getInput() + ">");
        cgClass.getImplementInterfaceList().add(cgType);

        {
            final BlancoCgMethod cgMethod = fCgFactory.createMethod("execute",
                    "ビジネスロジックのエントリポイント。");
            cgClass.getMethodList().add(cgMethod);
            final BlancoCgParameter cgParameter = fCgFactory.createParameter(
                    "input", fStructure.getInput(), "ビジネスロジックの入力。");
            cgMethod.getParameterList().add(cgParameter);
            cgSource.getImportList().add(fStructure.getInput());

            final BlancoCgReturn cgReturn = fCgFactory.createReturn(
                    "jp.terasoluna.fw.service.thin.BLogicResult",
                    "TERASOLUNA で定められたビジネスロジックの出力。");
            cgMethod.setReturn(cgReturn);

            final List<java.lang.String> listLine = cgMethod.getLineList();
            listLine.add("final BLogicResult result = new BLogicResult();");
            listLine.add("");
            listLine.add("// この箇所でコンパイルエラーが出る場合には、多くの場合 ["
                    + BlancoNameAdjuster.toClassName(fStructure.getName())
                    + "BLogicImpl] クラスが作成されていないことが原因と考えられます。");
            listLine.add("final Abstract"
                    + BlancoNameAdjuster.toClassName(fStructure.getName())
                    + "BLogic impl = new "
                    + BlancoNameAdjuster.toClassName(fStructure.getName())
                    + "BLogicImpl();");
            listLine.add("");
            listLine.add("result.setResultObject(impl.execute(input));");
            listLine.add("result.setResultString(impl.getResultString());");
            listLine.add("return result;");

        }

        new BlancoCgJavaSourceTransformer().transform(cgSource, new File(
                "blanco/main"));
    }

    private void generateBLogicInterface() {
        final BlancoCgSourceFile cgSource = fCgFactory.createSourceFile(
                fStructure.getPackage(), null);
        final BlancoCgInterface cgInterface = fCgFactory
                .createInterface(BlancoNameAdjuster.toClassName(fStructure
                        .getName())
                        + "BLogic", "[" + fStructure.getName() + "] ["
                        + fStructure.getDescription() + "]ビジネスロジックのインタフェース。");
        cgSource.getInterfaceList().add(cgInterface);

        {
            final BlancoCgMethod cgMethod = fCgFactory.createMethod("execute",
                    "ビジネスロジックのエントリポイント。");
            cgInterface.getMethodList().add(cgMethod);
            final BlancoCgParameter cgParameter = fCgFactory.createParameter(
                    "input", fStructure.getInput(), "ビジネスロジックの入力。");
            cgMethod.getParameterList().add(cgParameter);
            cgSource.getImportList().add(fStructure.getInput());

            final BlancoCgReturn cgReturn = fCgFactory.createReturn(fStructure
                    .getOutput(), "ビジネスロジックの出力。");
            cgMethod.setReturn(cgReturn);
            cgSource.getImportList().add(fStructure.getOutput());
        }

        new BlancoCgJavaSourceTransformer().transform(cgSource, new File(
                "blanco/main"));
    }

    private void generateAbstractBLogic() {
        final BlancoCgSourceFile cgSource = fCgFactory.createSourceFile(
                fStructure.getPackage(), null);
        final BlancoCgClass cgClass = fCgFactory.createClass("Abstract"
                + BlancoNameAdjuster.toClassName(fStructure.getName())
                + "BLogic", "[" + fStructure.getName() + "] ["
                + fStructure.getDescription()
                + "]ビジネスロジックの抽象クラス。Strutsの遷移先や DAO層の記述などが含まれます。");
        cgSource.getClassList().add(cgClass);

        cgClass.setAbstract(true);
        final BlancoCgType cgType = fCgFactory.createType(fStructure
                .getPackage()
                + "."
                + BlancoNameAdjuster.toClassName(fStructure.getName())
                + "BLogic");
        cgClass.getImplementInterfaceList().add(cgType);

        {
            final BlancoCgField cgField = fCgFactory.createField(
                    "fResultString", "java.lang.String",
                    "ビジネスロジックの結果文字列。StrutsのForwardで利用される。");
            cgClass.getFieldList().add(cgField);
            cgField.setDefault("\"success\"");
        }

        {
            final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                    "getResultString", "ビジネスロジックの結果文字列を取得する。");
            cgClass.getMethodList().add(cgMethod);
            final BlancoCgReturn cgReturn = fCgFactory.createReturn(
                    "java.lang.String", "ビジネスロジックの結果文字列。StrutsのForwardで利用される。");
            cgMethod.setReturn(cgReturn);
            cgMethod.getLineList().add("return fResultString;");
        }

        {
            final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                    "setResultString", "ビジネスロジックの結果文字列を設定する。");
            cgClass.getMethodList().add(cgMethod);
            final BlancoCgParameter cgParameter = fCgFactory.createParameter(
                    "argResult", "java.lang.String",
                    "ビジネスロジックの結果文字列。StrutsのForwardで利用される。");
            cgMethod.getParameterList().add(cgParameter);
            cgMethod.getLineList().add("fResultString = argResult;");
        }

        // DAO 層
        if (fStructure.getUseQueryDao()) {
            {
                final BlancoCgField cgField = fCgFactory.createField(
                        "fQueryDao", "jp.terasoluna.fw.dao.QueryDAO",
                        "TERASOLUNA QueryDAO オブジェクト。");
                cgClass.getFieldList().add(cgField);
            }

            {
                final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                        "getQueryDao", "TERASOLUNA QueryDAO オブジェクトを取得する。");
                cgClass.getMethodList().add(cgMethod);
                final BlancoCgReturn cgReturn = fCgFactory.createReturn(
                        "jp.terasoluna.fw.dao.QueryDAO",
                        "TERASOLUNA QueryDAO オブジェクト。");
                cgMethod.setReturn(cgReturn);
                cgMethod.getLineList().add("return fQueryDao;");
            }

            {
                final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                        "setQueryDao", "TERASOLUNA QueryDAO オブジェクトを設定する。");
                cgClass.getMethodList().add(cgMethod);
                final BlancoCgParameter cgParameter = fCgFactory
                        .createParameter("argDao",
                                "jp.terasoluna.fw.dao.QueryDAO",
                                "TERASOLUNA QueryDAO オブジェクト");
                cgMethod.getParameterList().add(cgParameter);
                cgMethod.getLineList().add("fQueryDao = argDao;");
            }
        }

        if (fStructure.getUseUpdateDao()) {
            {
                final BlancoCgField cgField = fCgFactory.createField(
                        "fUpdateDao", "jp.terasoluna.fw.dao.UpdateDAO",
                        "TERASOLUNA UpdateDAOオブジェクト。");
                cgClass.getFieldList().add(cgField);
            }

            {
                final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                        "getUpdateDao", "TERASOLUNA UpdateDAO オブジェクトを取得する。");
                cgClass.getMethodList().add(cgMethod);
                final BlancoCgReturn cgReturn = fCgFactory.createReturn(
                        "jp.terasoluna.fw.dao.UpdateDAO",
                        "TERASOLUNA UpdateDAO オブジェクト。");
                cgMethod.setReturn(cgReturn);
                cgMethod.getLineList().add("return fUpdateDao;");
            }

            {
                final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                        "setUpdateDao", "TERASOLUNA UpdateDAO オブジェクトを設定する。");
                cgClass.getMethodList().add(cgMethod);
                final BlancoCgParameter cgParameter = fCgFactory
                        .createParameter("argDao",
                                "jp.terasoluna.fw.dao.UpdateDAO",
                                "TERASOLUNA UpdateDAO オブジェクト");
                cgMethod.getParameterList().add(cgParameter);
                cgMethod.getLineList().add("fUpdateDao = argDao;");
            }
        }

        new BlancoCgJavaSourceTransformer().transform(cgSource, new File(
                "blanco/main"));
    }
}
