/*
 * blanco Framework
 * Copyright (C) 2004-2006 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.service;

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

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.transformer.BlancoCgTransformerFactory;
import blanco.cg.valueobject.BlancoCgClass;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.commons.util.BlancoStringUtil;
import blanco.service.valueobject.BlancoServiceStructure;

/**
 * 抽象処理クラスのソースコードを自動生成します。
 * 
 * @author IGA Tosiki
 */
class BlancoServiceXml2SourceFileAbstractProcess {
    /**
     * 内部的に利用するblancoCg用ファクトリ。
     */
    private BlancoCgObjectFactory fCgFactory = null;

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

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

    /**
     * 収集された情報を元に、ソースコードを自動生成します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     * @param argDirectoryTarget
     *            ソースコードの出力先フォルダ。
     */
    public void process(final BlancoServiceStructure argProcessStructure,
            final File argDirectoryTarget) {

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

        fCgFactory = BlancoCgObjectFactory.getInstance();
        fCgSourceFile = fCgFactory.createSourceFile(argProcessStructure
                .getPackage(), "このソースコードは blanco Frameworkによって自動生成されています。");
        fCgClass = fCgFactory.createClass("Abstract"
                + argProcessStructure.getName() + "Process", "サービス定義ID["
                + argProcessStructure.getName() + "]の抽象処理クラス。");
        fCgSourceFile.getClassList().add(fCgClass);

        fCgClass.getImplementInterfaceList().add(
                fCgFactory.createType("java.lang.Runnable"));
        fCgClass.setAbstract(true);
        if (BlancoStringUtil.null2Blank(argProcessStructure.getDescription())
                .length() > 0) {
            fCgClass.getLangDoc().getDescriptionList().add(
                    "説明: " + argProcessStructure.getDescription() + "<br>");
        }
        fCgClass.getLangDoc().getDescriptionList().add(
                "このクラスは、Javaで書かれたアプリケーションをアプリケーションサーバ上に常駐させるための仕組みの一部です。<br>");
        fCgClass.getLangDoc().getDescriptionList().add(
                "このクラスを継承して " + argProcessStructure.getName()
                        + "Process というクラスを作り、その中に具体的な処理を記載してください。");

        expandMethodRun(argProcessStructure);
        expandMethodExecute(argProcessStructure);
        expandMethodStop(argProcessStructure);

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

    /**
     * run メソッドを展開します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     */
    private void expandMethodRun(
            final BlancoServiceStructure argProcessStructure) {

        final BlancoCgMethod method = fCgFactory.createMethod("run",
                "処理がスレッドとして動作する際のエントリポイント。");
        fCgClass.getMethodList().add(method);

        method.setFinal(true);
        method.getLangDoc().getDescriptionList().add(
                "java.lang.Runnable がスレッドとして実行された際に、このメソッドが呼び出されます。");

        final List listLine = method.getLineList();

        listLine.add("System.out.println(\"" + argProcessStructure.getName()
                + "Process: begin.\");");
        listLine.add("");
        listLine.add("try {");
        listLine.add("execute();");
        listLine.add("} catch (Exception ex) {");
        listLine.add("System.out.println(\"" + argProcessStructure.getName()
                + "Process: exception: \" + ex.toString());");
        listLine.add("ex.printStackTrace();");
        listLine.add("} catch (Error er) {");
        listLine.add("System.out.println(\"" + argProcessStructure.getName()
                + "Process: error: \" + er.toString());");
        listLine.add("er.printStackTrace();");
        listLine.add("}");
        listLine.add("");
        listLine.add("System.out.println(\"" + argProcessStructure.getName()
                + "Process: end.\");");
    }

    /**
     * execute メソッドを展開します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     */
    private void expandMethodExecute(
            final BlancoServiceStructure argProcessStructure) {

        final BlancoCgMethod method = fCgFactory.createMethod("execute",
                "実際の処理内容を記述するメソッド。");
        fCgClass.getMethodList().add(method);

        method.setAbstract(true);
        method.getLangDoc().getDescriptionList().add(
                "このメソッドを実装して、実際の処理記述を行います。");
    }

    /**
     * stop メソッドを展開します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     */
    private void expandMethodStop(
            final BlancoServiceStructure argProcessStructure) {

        final BlancoCgMethod method = fCgFactory.createMethod("stop",
                "処理が停止される際に呼び出されるメソッド。");
        fCgClass.getMethodList().add(method);

        method.getLangDoc().getDescriptionList().add(
                "停止処理を記述します。特別な停止処理がない場合には、このメソッドを上書きする必要はありません。");

        final List listLine = method.getLineList();
        listLine.add("// 特に何も処理は行いません。");
        listLine.add("System.out.println(\"" + argProcessStructure.getName()
                + "Process: stop.\");");
    }
}
