/*
 * 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.stringgroup;

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

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.BlancoCgSupportedLang;
import blanco.cg.transformer.BlancoCgTransformerFactory;
import blanco.cg.util.BlancoCgLineUtil;
import blanco.cg.util.BlancoCgSourceUtil;
import blanco.cg.valueobject.BlancoCgClass;
import blanco.cg.valueobject.BlancoCgField;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.commons.util.BlancoNameAdjuster;
import blanco.commons.util.BlancoStringUtil;
import blanco.stringgroup.resourcebundle.BlancoStringGroupResourceBundle;
import blanco.stringgroup.valueobject.BlancoStringGroupFieldStructure;
import blanco.stringgroup.valueobject.BlancoStringGroupStructure;
import blanco.xml.bind.BlancoXmlBindingUtil;
import blanco.xml.bind.BlancoXmlUnmarshaller;
import blanco.xml.bind.valueobject.BlancoXmlDocument;
import blanco.xml.bind.valueobject.BlancoXmlElement;

/**
 * 「文字列グループ定義書」Excel様式から文字列グループを処理するクラス・ソースコードを生成。
 * 
 * このクラスは、中間XMLファイルからソースコードを自動生成する機能を担います。
 * 
 * @author IGA Tosiki
 */
public class BlancoStringGroupXml2SourceFile {
    /**
     * このプロダクトのリソースバンドルへのアクセスオブジェクト。
     */
    private final BlancoStringGroupResourceBundle fBundle = new BlancoStringGroupResourceBundle();

    /**
     * 出力対象となるプログラミング言語。
     */
    private int fTargetLang = BlancoCgSupportedLang.NOT_DEFINED;

    /**
     * 内部的に利用するblancoCg用ファクトリ。
     */
    private BlancoCgObjectFactory fCgFactory = null;

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

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

    /**
     * 中間XMLファイルからソースコードを自動生成します。
     * 
     * @param argMetaXmlSourceFile
     *            メタ情報が含まれているXMLファイル。
     * @param argTargetLang
     *            出力対象となるプログラミング言語。
     * @param argDirectoryTarget
     *            ソースコード生成先ディレクトリ (/mainを除く部分を指定します)。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    public void process(final File argMetaXmlSourceFile,
            final String argTargetLang, final File argDirectoryTarget)
            throws IOException {

        fTargetLang = new BlancoCgSupportedLang().convertToInt(argTargetLang);
        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        case BlancoCgSupportedLang.CS:
        case BlancoCgSupportedLang.JS:
        case BlancoCgSupportedLang.VB:
        case BlancoCgSupportedLang.PHP:
        case BlancoCgSupportedLang.RUBY:
        case BlancoCgSupportedLang.PYTHON:
            break;
        default:
            throw new IllegalArgumentException(fBundle
                    .getXml2sourceFileErr002(argTargetLang));
        }

        // メタ情報を解析してバリューオブジェクトのツリーを取得します。
        final BlancoXmlDocument documentMeta = new BlancoXmlUnmarshaller()
                .unmarshal(argMetaXmlSourceFile);

        // ルートエレメントを取得します。
        final BlancoXmlElement elementRoot = BlancoXmlBindingUtil
                .getDocumentElement(documentMeta);
        if (elementRoot == null) {
            // ルートエレメントが無い場合には処理中断します。
            return;
        }

        // sheet(Excelシート)のリストを取得します。
        final List listSheet = BlancoXmlBindingUtil.getElementsByTagName(
                elementRoot, "sheet");
        final int sizeListSheet = listSheet.size();
        for (int index = 0; index < sizeListSheet; index++) {
            // おのおののシートを処理します。
            final BlancoXmlElement elementSheet = (BlancoXmlElement) listSheet
                    .get(index);

            // 共通情報を取得します。
            final BlancoXmlElement elementCommon = BlancoXmlBindingUtil
                    .getElement(elementSheet, fBundle
                            .getMeta2xmlElementCommon());
            if (elementCommon == null) {
                // commonが無い場合には、このシートの処理をスキップします。
                continue;
            }

            final String name = BlancoXmlBindingUtil.getTextContent(
                    elementCommon, "name");
            if (BlancoStringUtil.null2Blank(name).trim().length() == 0) {
                // nameが空の場合には処理をスキップします。
                continue;
            }

            // 一覧情報を取得します。
            final BlancoXmlElement elementList = BlancoXmlBindingUtil
                    .getElement(elementSheet, fBundle.getMeta2xmlElementList());

            // シートから詳細な情報を取得します。
            final BlancoStringGroupStructure processStructure = parseSheet(
                    elementCommon, elementList, argDirectoryTarget);

            if (processStructure != null) {
                // メタ情報の解析結果をもとにソースコード自動生成を実行します。
                expandSourceFile(processStructure, argDirectoryTarget);
            }
        }
    }

    /**
     * sheetエレメントを展開します。
     * 
     * @param argElementCommon
     *            現在処理しているCommonノード。
     * @param argElementList
     *            現在処理しているListノード。
     * @param argDirectoryTarget
     *            ソースコードの出力先フォルダ。
     * @return 収集されたメタ情報構造データ。
     */
    private BlancoStringGroupStructure parseSheet(
            final BlancoXmlElement argElementCommon,
            final BlancoXmlElement argElementList, final File argDirectoryTarget) {

        final BlancoStringGroupStructure processStructure = new BlancoStringGroupStructure();
        processStructure.setName(BlancoXmlBindingUtil.getTextContent(
                argElementCommon, "name"));
        processStructure.setPackage(BlancoXmlBindingUtil.getTextContent(
                argElementCommon, "package"));

        if (BlancoStringUtil.null2Blank(processStructure.getPackage()).trim()
                .length() == 0) {
            throw new IllegalArgumentException(fBundle
                    .getXml2sourceFileErr001(processStructure.getName()));
        }

        if (BlancoXmlBindingUtil
                .getTextContent(argElementCommon, "description") != null) {
            processStructure.setDescription(BlancoXmlBindingUtil
                    .getTextContent(argElementCommon, "description"));
        }

        if (BlancoXmlBindingUtil.getTextContent(argElementCommon, "suffix") != null) {
            processStructure.setSuffix(BlancoXmlBindingUtil.getTextContent(
                    argElementCommon, "suffix"));
        }

        if (argElementList == null) {
            return null;
        }

        // 一覧の内容を取得します。
        final List listField = BlancoXmlBindingUtil.getElementsByTagName(
                argElementList, "field");
        for (int indexField = 0; indexField < listField.size(); indexField++) {
            final Object nodeField = listField.get(indexField);

            if (nodeField instanceof BlancoXmlElement == false) {
                continue;
            }

            final BlancoXmlElement elementField = (BlancoXmlElement) nodeField;
            BlancoStringGroupFieldStructure field = new BlancoStringGroupFieldStructure();
            field
                    .setNo(BlancoXmlBindingUtil.getTextContent(elementField,
                            "no"));

            field.setValue(BlancoXmlBindingUtil.getTextContent(elementField,
                    "value"));
            if (BlancoStringUtil.null2Blank(field.getValue()).length() == 0) {
                continue;
            }

            field.setConstant(BlancoXmlBindingUtil.getTextContent(elementField,
                    "constant"));

            field.setDescription(BlancoXmlBindingUtil.getTextContent(
                    elementField, "description"));

            // 既に同じ内容が登録されていないかどうかのチェック。
            for (int indexPast = 0; indexPast < processStructure.getListField()
                    .size(); indexPast++) {
                final BlancoStringGroupFieldStructure fieldPast = (BlancoStringGroupFieldStructure) processStructure
                        .getListField().get(indexPast);
                if (fieldPast.getValue().equals(field.getValue())) {
                    throw new IllegalArgumentException(fBundle
                            .getXml2sourceFileErr003(
                                    processStructure.getName(), field
                                            .getValue()));
                }
            }

            processStructure.getListField().add(field);
        }

        return processStructure;
    }

    /**
     * 収集された情報を元に、ソースコードを自動生成します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     * @param argDirectoryTarget
     *            ソースコードの出力先フォルダ。
     */
    private void expandSourceFile(
            final BlancoStringGroupStructure 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(argProcessStructure.getName()
                + BlancoStringUtil.null2Blank(argProcessStructure.getSuffix()),
                BlancoStringUtil.null2Blank(argProcessStructure
                        .getDescription()));
        fCgSourceFile.getClassList().add(fCgClass);

        expandField(argProcessStructure);
        expandMethodMatch(argProcessStructure);
        expandMethodMatchIgnoreCase(argProcessStructure);
        expandMethodConvertToInt(argProcessStructure);

        // TODO 現在 Java言語にしか対応していません。
        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
            expandMethodConvertToString(argProcessStructure);
            break;
        }

        BlancoCgTransformerFactory.getSourceTransformer(fTargetLang).transform(
                fCgSourceFile, fileBlancoMain);
    }

    /**
     * 定数フィールドを展開します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     */
    private void expandField(
            final BlancoStringGroupStructure argProcessStructure) {

        boolean isProcessed = false;
        for (int indexField = 0; indexField < argProcessStructure
                .getListField().size(); indexField++) {
            final BlancoStringGroupFieldStructure fieldLook = (BlancoStringGroupFieldStructure) argProcessStructure
                    .getListField().get(indexField);
            if (BlancoStringUtil.null2Blank(fieldLook.getConstant()).length() == 0) {
                continue;
            }

            String description = "";
            // ここから個別の文字に対する処理を記述します。
            if (fieldLook.getNo() != null) {
                description += fBundle.getXml2sourceFileFieldNo(fieldLook
                        .getNo()
                        + " ");
            }
            if (fieldLook.getDescription() != null) {
                description += fBundle.getXml2sourceFileDescription(fieldLook
                        .getDescription());
            }

            final BlancoCgField cgField = fCgFactory.createField(fieldLook
                    .getConstant().toUpperCase(), getTypeInt(), description);
            fCgClass.getFieldList().add(cgField);

            cgField.setAccess("public");
            cgField.setStatic(true);
            cgField.setFinal(true);
            cgField.setDefault(Integer.toString(indexField + 1));
            isProcessed = true;
        }

        if (isProcessed) {
            final BlancoCgField cgField = fCgFactory.createField("NOT_DEFINED",
                    getTypeInt(), "未定義。文字列グループ以外の文字列または定数が未定義のもの。");
            fCgClass.getFieldList().add(cgField);

            cgField.setAccess("public");
            cgField.setStatic(true);
            cgField.setFinal(true);
            cgField.setDefault("-1");
        }
    }

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

        final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                getMethodName("match"), "文字列グループに含まれる文字列であるかどうかを判定します。");
        fCgClass.getMethodList().add(cgMethod);
        cgMethod.getParameterList().add(
                fCgFactory.createParameter("argCheck", getTypeString(),
                        "チェックを行いたい文字列。"));
        cgMethod.setReturn(fCgFactory.createReturn(getTypeBoolean(),
                "文字列グループに含まれていればture。グループに含まれない文字列であればfalse。"));

        final List lineList = cgMethod.getLineList();

        for (int indexField = 0; indexField < argProcessStructure
                .getListField().size(); indexField++) {
            final BlancoStringGroupFieldStructure fieldLook = (BlancoStringGroupFieldStructure) argProcessStructure
                    .getListField().get(indexField);

            // ここから個別の文字に対する処理を記述します。
            if (fieldLook.getNo() != null) {
                lineList.add(BlancoCgLineUtil
                        .getSingleLineCommentPrefix(fTargetLang)
                        + fBundle.getXml2sourceFileFieldNo(fieldLook.getNo()));
            }
            if (fieldLook.getDescription() != null) {
                lineList.add(BlancoCgLineUtil
                        .getSingleLineCommentPrefix(fTargetLang)
                        + fBundle.getXml2sourceFileDescription(fieldLook
                                .getDescription()));
            }

            switch (fTargetLang) {
            case BlancoCgSupportedLang.JAVA:
            case BlancoCgSupportedLang.CS:
                lineList
                        .add(BlancoCgLineUtil
                                .getIfBegin(
                                        fTargetLang,
                                        BlancoCgLineUtil
                                                .getStringLiteralEnclosure(fTargetLang)
                                                + BlancoCgSourceUtil
                                                        .escapeStringAsSource(
                                                                fTargetLang,
                                                                fieldLook
                                                                        .getValue())
                                                + BlancoCgLineUtil
                                                        .getStringLiteralEnclosure(fTargetLang)
                                                + "."
                                                + getMethodName("equals")
                                                + "(argCheck)"));
                break;
            case BlancoCgSupportedLang.JS:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " == argCheck"));
                break;
            case BlancoCgSupportedLang.VB:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " = argCheck"));
                break;
            case BlancoCgSupportedLang.PHP:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " === $argCheck"));
                break;
            case BlancoCgSupportedLang.RUBY:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " == argCheck"));
                break;
            case BlancoCgSupportedLang.PYTHON:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " == argCheck"));
                break;
            }

            switch (fTargetLang) {
            case BlancoCgSupportedLang.PYTHON:
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "True")
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            default:
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "true")
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            }
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));
        }
        switch (fTargetLang) {
        case BlancoCgSupportedLang.PYTHON:
            lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "False")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        default:
            lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "false")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        }
    }

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

        final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                getMethodName("matchIgnoreCase"),
                "文字列グループに含まれる文字列であるかどうかを、大文字小文字を区別せず判定します。");
        fCgClass.getMethodList().add(cgMethod);
        cgMethod.getParameterList().add(
                fCgFactory.createParameter("argCheck", getTypeString(),
                        "チェックを行いたい文字列。"));
        cgMethod.setReturn(fCgFactory.createReturn(getTypeBoolean(),
                "文字列グループに含まれていればture。グループに含まれない文字列であればfalse。"));

        final List lineList = cgMethod.getLineList();

        for (int indexField = 0; indexField < argProcessStructure
                .getListField().size(); indexField++) {
            final BlancoStringGroupFieldStructure fieldLook = (BlancoStringGroupFieldStructure) argProcessStructure
                    .getListField().get(indexField);

            // ここから個別の文字に対する処理を記述します。
            if (fieldLook.getNo() != null) {
                lineList.add(BlancoCgLineUtil
                        .getSingleLineCommentPrefix(fTargetLang)
                        + fBundle.getXml2sourceFileFieldNo(fieldLook.getNo()));
            }
            if (fieldLook.getDescription() != null) {
                lineList.add(BlancoCgLineUtil
                        .getSingleLineCommentPrefix(fTargetLang)
                        + fBundle.getXml2sourceFileDescription(fieldLook
                                .getDescription()));
            }

            switch (fTargetLang) {
            case BlancoCgSupportedLang.JAVA:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + "." + getMethodName("equalsIgnoreCase")
                                + "(argCheck)"));
                break;
            case BlancoCgSupportedLang.CS:
                lineList
                        .add(BlancoCgLineUtil
                                .getIfBegin(
                                        fTargetLang,
                                        BlancoCgLineUtil
                                                .getStringLiteralEnclosure(fTargetLang)
                                                + BlancoCgSourceUtil
                                                        .escapeStringAsSource(
                                                                fTargetLang,
                                                                fieldLook
                                                                        .getValue())
                                                + BlancoCgLineUtil
                                                        .getStringLiteralEnclosure(fTargetLang)
                                                + "."
                                                + getMethodName("equals")
                                                + "(argCheck, StringComparison.CurrentCultureIgnoreCase)"));
                fCgSourceFile.getImportList().add("System.StringComparison");
                break;
            case BlancoCgSupportedLang.JS:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + ".toUpperCase() == argCheck.toUpperCase()"));
                break;
            case BlancoCgSupportedLang.VB:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + ".ToUpper() = argCheck.ToUpper()"));
                break;
            case BlancoCgSupportedLang.PHP:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        "strtoupper("
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + ") === strtoupper($argCheck)"));
                break;
            case BlancoCgSupportedLang.RUBY:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + ".upcase() == argCheck.upcase()"));
                break;
            case BlancoCgSupportedLang.PYTHON:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + ".upper() == argCheck.upper()"));
                break;
            }
            switch (fTargetLang) {
            case BlancoCgSupportedLang.PYTHON:
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "True")
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            default:
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "true")
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            }
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));
        }
        switch (fTargetLang) {
        case BlancoCgSupportedLang.PYTHON:
            lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "False")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        default:
            lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "false")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        }
    }

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

        final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                getMethodName("convertToInt"), "文字列から定数に変換します。");
        fCgClass.getMethodList().add(cgMethod);

        cgMethod.getLangDoc().getDescriptionList().add(
                "定数が未定義の場合や 与えられた文字列が文字列グループ外の場合には NOT_DEFINED を戻します。");
        cgMethod.getParameterList().add(
                fCgFactory.createParameter("argCheck", getTypeString(),
                        "変換を行いたい文字列。"));
        cgMethod.setReturn(fCgFactory.createReturn(getTypeInt(), "定数に変換後の値。"));

        final List lineList = cgMethod.getLineList();

        for (int indexField = 0; indexField < argProcessStructure
                .getListField().size(); indexField++) {
            final BlancoStringGroupFieldStructure fieldLook = (BlancoStringGroupFieldStructure) argProcessStructure
                    .getListField().get(indexField);

            if (BlancoStringUtil.null2Blank(fieldLook.getConstant()).length() == 0) {
                // 定数が未定義のものはスキップします。
                continue;
            }

            // ここから個別の文字に対する処理を記述します。
            if (fieldLook.getNo() != null) {
                lineList.add(BlancoCgLineUtil
                        .getSingleLineCommentPrefix(fTargetLang)
                        + fBundle.getXml2sourceFileFieldNo(fieldLook.getNo()));
            }
            if (fieldLook.getDescription() != null) {
                lineList.add(BlancoCgLineUtil
                        .getSingleLineCommentPrefix(fTargetLang)
                        + fBundle.getXml2sourceFileDescription(fieldLook
                                .getDescription()));
            }

            switch (fTargetLang) {
            case BlancoCgSupportedLang.JAVA:
            case BlancoCgSupportedLang.CS:
                lineList
                        .add(BlancoCgLineUtil
                                .getIfBegin(
                                        fTargetLang,
                                        BlancoCgLineUtil
                                                .getStringLiteralEnclosure(fTargetLang)
                                                + BlancoCgSourceUtil
                                                        .escapeStringAsSource(
                                                                fTargetLang,
                                                                fieldLook
                                                                        .getValue())
                                                + BlancoCgLineUtil
                                                        .getStringLiteralEnclosure(fTargetLang)
                                                + "."
                                                + getMethodName("equals")
                                                + "(argCheck)"));
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, fieldLook
                        .getConstant().toUpperCase())
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            case BlancoCgSupportedLang.JS:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " == argCheck"));
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, fCgClass
                        .getName()
                        + "." + fieldLook.getConstant().toUpperCase())
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            case BlancoCgSupportedLang.VB:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " = argCheck"));
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, fieldLook
                        .getConstant().toUpperCase())
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            case BlancoCgSupportedLang.PHP:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " === $argCheck"));
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "self::"
                        + fieldLook.getConstant().toUpperCase())
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            case BlancoCgSupportedLang.RUBY:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " == argCheck"));
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, fieldLook
                        .getConstant().toUpperCase())
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            case BlancoCgSupportedLang.PYTHON:
                lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                        BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                                + BlancoCgSourceUtil.escapeStringAsSource(
                                        fTargetLang, fieldLook.getValue())
                                + BlancoCgLineUtil
                                        .getStringLiteralEnclosure(fTargetLang)
                                + " == argCheck"));
                lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "self."
                        + fieldLook.getConstant().toUpperCase())
                        + BlancoCgLineUtil.getTerminator(fTargetLang));
                break;
            }
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));
        }

        lineList.add("");
        lineList.add(BlancoCgLineUtil.getSingleLineCommentPrefix(fTargetLang)
                + "該当する定数が見つかりませんでした。");

        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        case BlancoCgSupportedLang.CS:
        case BlancoCgSupportedLang.VB:
        case BlancoCgSupportedLang.RUBY:
        default:
            lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, "NOT_DEFINED")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.JS:
            lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, fCgClass
                    .getName()
                    + ".NOT_DEFINED")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.PHP:
            lineList.add(BlancoCgLineUtil.getReturn(fTargetLang,
                    "self::NOT_DEFINED")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.PYTHON:
            lineList.add(BlancoCgLineUtil.getReturn(fTargetLang,
                    "self.NOT_DEFINED")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        }
    }

    /**
     * convertToStringメソッドを展開します。
     * 
     * TODO Java言語にのみ対応しています。他の言語には対応していません。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     */
    private void expandMethodConvertToString(
            final BlancoStringGroupStructure argProcessStructure) {

        final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                getMethodName("convertToString"), "定数から文字列に変換します。");
        fCgClass.getMethodList().add(cgMethod);

        cgMethod.getLangDoc().getDescriptionList().add("定数と対応づく文字列に変換します。");
        cgMethod.getParameterList().add(
                fCgFactory.createParameter("argCheck", getTypeInt(),
                        "変換を行いたい文字定数。"));
        cgMethod.setReturn(fCgFactory.createReturn(getTypeString(),
                "文字列に変換後の値。NOT_DEFINEDの場合には長さ0の文字列。"));

        final List lineList = cgMethod.getLineList();

        for (int indexField = 0; indexField < argProcessStructure
                .getListField().size(); indexField++) {
            final BlancoStringGroupFieldStructure fieldLook = (BlancoStringGroupFieldStructure) argProcessStructure
                    .getListField().get(indexField);

            if (BlancoStringUtil.null2Blank(fieldLook.getConstant()).length() == 0) {
                continue;
            }

            if (fieldLook.getNo() != null) {
                lineList.add(BlancoCgLineUtil
                        .getSingleLineCommentPrefix(fTargetLang)
                        + fBundle.getXml2sourceFileFieldNo(fieldLook.getNo()));
            }
            if (fieldLook.getDescription() != null) {
                lineList.add(BlancoCgLineUtil
                        .getSingleLineCommentPrefix(fTargetLang)
                        + fBundle.getXml2sourceFileDescription(fieldLook
                                .getDescription()));
            }

            lineList.add("if (argCheck == "
                    + fieldLook.getConstant().toUpperCase() + ") {");
            lineList.add("return "
                    + BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                    + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                            fieldLook.getValue())
                    + BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            lineList.add("}");
        }

        lineList.add(BlancoCgLineUtil.getSingleLineCommentPrefix(fTargetLang)
                + "未定義。");
        lineList.add("if (argCheck == NOT_DEFINED) {");
        lineList.add("return "
                + BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                + BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                + BlancoCgLineUtil.getTerminator(fTargetLang));
        lineList.add("}");

        lineList.add("");
        lineList.add(BlancoCgLineUtil.getSingleLineCommentPrefix(fTargetLang)
                + "いずれにも該当しませんでした。");
        lineList.add("throw new IllegalArgumentException("
                + BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                + "与えられた値("
                + BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                + " + argCheck + "
                + BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                + ")は文字列グループ[" + argProcessStructure.getName()
                + "]では定義されない値です。"
                + BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang) + ")"
                + BlancoCgLineUtil.getTerminator(fTargetLang));
    }

    /**
     * プログラミング言語処理系に合った boolean 型の名称を取得します。
     * 
     * 型の読み替え。
     * 
     * @return
     */
    private final String getTypeBoolean() {
        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        default:
            return "boolean";
        case BlancoCgSupportedLang.CS:
            return "bool";
        case BlancoCgSupportedLang.JS:
            return "boolean";
        case BlancoCgSupportedLang.VB:
            return "Boolean";
        }
    }

    /**
     * プログラミング言語処理系に合った String 型の名称を取得します。
     * 
     * 型の読み替え。
     * 
     * @return
     */
    private final String getTypeString() {
        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        default:
            return "java.lang.String";
        case BlancoCgSupportedLang.CS:
            return "string";
        case BlancoCgSupportedLang.JS:
            return "string";
        case BlancoCgSupportedLang.VB:
            return "String";
        case BlancoCgSupportedLang.PHP:
            return "string";
        }
    }

    private final String getTypeInt() {
        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        case BlancoCgSupportedLang.CS:
        case BlancoCgSupportedLang.JS:
        default:
            return "int";
        case BlancoCgSupportedLang.VB:
            return "Integer";
        case BlancoCgSupportedLang.PHP:
            return "integer";
        }
    }

    /**
     * プログラミング言語処理系に合った メソッドの名前変形をおこないます。
     * 
     * メソッド名の読み替え。
     * 
     * @param argMethodName
     *            メソッド名。
     * @return
     */
    private final String getMethodName(final String argMethodName) {
        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        default:
            return argMethodName;
        case BlancoCgSupportedLang.CS:
        case BlancoCgSupportedLang.VB:
            return BlancoNameAdjuster.toUpperCaseTitle(argMethodName);
        case BlancoCgSupportedLang.JS:
            return argMethodName;
        }
    }
}
