/*
 * 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.io.IOException;
import java.util.ArrayList;
import java.util.List;

import blanco.commons.util.BlancoNameAdjuster;
import blanco.commons.util.BlancoStringUtil;
import blanco.db.common.stringgroup.BlancoDbSqlInfoTypeStringGroup;
import blanco.db.common.valueobject.BlancoDbSqlInfoStructure;
import blanco.jsf.db.BlancoJsfDbParser;
import blanco.jsf.message.BlancoJsfMessage;
import blanco.jsf.valueobject.BlancoJsfSqlItemStructure;
import blanco.jsf.valueobject.BlancoJsfStructure;

/**
 * 「バッチ処理定義書」Excel様式からバッチ処理を処理する抽象親クラス・ソースコードを生成。
 * 
 * このクラスは、中間XMLファイルからソースコードを自動生成する機能を担います。
 * 
 * @author IGA Tosiki
 */
public class BlancoJsfXml2SourceFile {
    /**
     * メッセージクラス。
     */
    protected final BlancoJsfMessage fMsg = new BlancoJsfMessage();

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

    /**
     * 自動生成するソースファイルの文字エンコーディングを指定します。
     * 
     * @param argEncoding
     *            自動生成するソースファイルの文字エンコーディング。
     */
    public void setEncoding(final String argEncoding) {
        fEncoding = argEncoding;
    }

    /**
     * 中間XMLファイルからソースコードを自動生成します。
     * 
     * @param argMetaXmlSourceFile
     *            メタ情報が含まれているXMLファイル。
     * @param argDirectoryTarget
     *            ソースコード生成先ディレクトリ (/mainを除く部分を指定します)。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    public List<BlancoJsfStructure> process(final File argMetaXmlSourceFile,
            final File argDirectoryTarget, final File argDirectoryTargetJee,
            final File argTmp) throws IOException {
        final List<BlancoJsfStructure> result = new ArrayList<BlancoJsfStructure>();

        final BlancoJsfStructure[] structures = new BlancoJsfXmlParser()
                .parse(argMetaXmlSourceFile);
        if (structures == null || structures.length == 0) {
            // 処理しない。
            return result;
        }

        final List<BlancoDbSqlInfoStructure> sqlInfoList = new BlancoJsfDbParser()
                .process(argTmp);

        for (int index = 0; index < structures.length; index++) {
            // メタ情報の解析結果をもとにソースコード自動生成を実行します。
            structure2Source(structures[index], sqlInfoList,
                    argDirectoryTarget, argDirectoryTargetJee);
            result.add(structures[index]);
        }

        return result;
    }

    /**
     * 与えられたクラス情報バリューオブジェクトから、Javaソースコードを自動生成します。
     * 
     * @param argStructure
     *            情報。
     * @param argDirectoryTarget
     *            ソースコードの出力先ディレクトリ
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    public void structure2Source(final BlancoJsfStructure argStructure,
            final List<BlancoDbSqlInfoStructure> sqlInfoList,
            final File argDirectoryTarget, final File argDirectoryTargetJee)
            throws IOException {
        final List<String> sqlClassNameList = getSqlClassNameList(argStructure,
                sqlInfoList);

        {
            final BlancoJsfExpandLogic expandLogic = new BlancoJsfExpandLogic();
            expandLogic.setEncoding(fEncoding);
            expandLogic.expandSourceFile(argStructure, sqlClassNameList,
                    argDirectoryTarget);
        }

        {
            final BlancoJsfExpandLogicProxy expandLogicProxy = new BlancoJsfExpandLogicProxy();
            expandLogicProxy.setEncoding(fEncoding);
            expandLogicProxy.expandSourceFile(argStructure, sqlClassNameList,
                    argDirectoryTargetJee);
        }
    }

    static List<String> getSqlClassNameList(
            final BlancoJsfStructure argProcessStructure,
            final List<BlancoDbSqlInfoStructure> sqlInfoList) {
        final List<String> result = new ArrayList<String>();
        for (BlancoJsfSqlItemStructure sqlItem : argProcessStructure
                .getSqlList()) {
            boolean isFound = false;
            for (BlancoDbSqlInfoStructure sqlinfo : sqlInfoList) {
                if (sqlItem.getName().equals(sqlinfo.getName())) {
                    String basePackage = BlancoStringUtil.null2Blank(sqlinfo
                            .getPackage());
                    if (basePackage.length() == 0) {
                        basePackage = "noname";
                    }
                    final String sqlClassName = basePackage
                            + ".query."
                            + BlancoNameAdjuster.toClassName(sqlItem.getName())
                            + BlancoNameAdjuster
                                    .toUpperCaseTitle(new BlancoDbSqlInfoTypeStringGroup()
                                            .convertToString(sqlinfo.getType()));
                    result.add(sqlClassName);
                    isFound = true;
                    break;
                }
            }
            if (isFound == false) {
                throw new IllegalArgumentException("JSF処理定義書 ["
                        + argProcessStructure.getName() + "] の SQL定義ID ["
                        + sqlItem.getName() + "] が見つかりません。");
            }
        }
        return result;
    }
}
