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

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.BlancoNameUtil;
import blanco.commons.util.BlancoStringUtil;
import blanco.stringconverter.resourcebundle.BlancoStringConverterResourceBundle;
import blanco.stringconverter.valueobject.BlancoStringConverterFieldStructure;
import blanco.stringconverter.valueobject.BlancoStringConverterStructure;
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 BlancoStringConverterXml2SourceFile {
    /**
     * このプロダクトのリソースバンドルへのアクセスオブジェクト。
     */
    private final BlancoStringConverterResourceBundle fBundle = new BlancoStringConverterResourceBundle();

    /**
     * 出力対象となるプログラミング言語。
     */
    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 BlancoStringConverterStructure processStructure = parseSheet(
                    elementCommon, elementList, argDirectoryTarget);

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

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

        final BlancoStringConverterStructure processStructure = new BlancoStringConverterStructure();
        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;
            BlancoStringConverterFieldStructure field = new BlancoStringConverterFieldStructure();
            field
                    .setNo(BlancoXmlBindingUtil.getTextContent(elementField,
                            "no"));

            field.setFrom(BlancoXmlBindingUtil.getTextContent(elementField,
                    "from"));
            if (BlancoStringUtil.null2Blank(field.getFrom()).length() == 0) {
                continue;
            }

            field
                    .setTo(BlancoXmlBindingUtil.getTextContent(elementField,
                            "to"));
            if (BlancoStringUtil.null2Blank(field.getTo()).length() == 0) {
                continue;
            }

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

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

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

        return processStructure;
    }

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

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

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

        String defaultString = null;

        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
            defaultString = "new String[][] {";
            break;
        case BlancoCgSupportedLang.CS:
            defaultString = "new string[][] {";
            break;
        case BlancoCgSupportedLang.JS:
        case BlancoCgSupportedLang.RUBY:
        case BlancoCgSupportedLang.PYTHON:
            defaultString = "[";
            break;
        case BlancoCgSupportedLang.VB:
            defaultString = "{";
            break;
        case BlancoCgSupportedLang.PHP:
            defaultString = "array(";
            break;
        }

        for (int indexField = 0; indexField < argProcessStructure
                .getListField().size(); indexField++) {
            final BlancoStringConverterFieldStructure fieldLook = (BlancoStringConverterFieldStructure) argProcessStructure
                    .getListField().get(indexField);
            if (indexField != 0) {
                defaultString += ", ";
            }

            switch (fTargetLang) {
            case BlancoCgSupportedLang.JAVA:
                defaultString += "new String[] { "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getFrom())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + ", "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getTo())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang) + " }";
                break;
            case BlancoCgSupportedLang.CS:
                defaultString += "new string[] { "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getFrom())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + ", "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getTo())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang) + " }";
                break;
            case BlancoCgSupportedLang.JS:
                defaultString += "[ "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getFrom())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + ", "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getTo())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang) + " ]";
                break;
            case BlancoCgSupportedLang.VB:
                defaultString += "{ "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getFrom())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + ", "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getTo())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang) + " }";
                break;
            case BlancoCgSupportedLang.PHP:
                defaultString += "array("
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getFrom())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + ", "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getTo())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang) + ")";
                break;
            case BlancoCgSupportedLang.RUBY:
                defaultString += "[ "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getFrom())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + ", "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getTo())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang) + " ]";
                break;
            case BlancoCgSupportedLang.PYTHON:
                // Pythonでは１行が長すぎると実行時エラーがおきるようなので
                // 改行しています。
                defaultString += "[ "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getFrom())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + ", "
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgSourceUtil.escapeStringAsSource(fTargetLang,
                                fieldLook.getTo())
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang)
                        + " ]\n";
                break;
            }

            String strComment = "";
            if (fieldLook.getNo() != null) {
                strComment += fBundle
                        .getXml2sourceFileFieldNo(BlancoCgSourceUtil
                                .escapeStringAsLangDoc(fTargetLang, fieldLook
                                        .getNo()));
            }
            if (fieldLook.getDescription() != null) {
                if (strComment.length() > 0) {
                    // NoとDescriptionの間に空白を挿入。
                    strComment += " ";
                }
                strComment += fBundle
                        .getXml2sourceFileDescription(BlancoCgSourceUtil
                                .escapeStringAsLangDoc(fTargetLang, fieldLook
                                        .getDescription()));
            }

            switch (fTargetLang) {
            case BlancoCgSupportedLang.VB:
            case BlancoCgSupportedLang.RUBY:
            case BlancoCgSupportedLang.PYTHON:
                break;
            default:
                if (strComment.length() > 0) {
                    defaultString += "/* " + strComment + " */";
                }
                break;
            }
        }

        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        case BlancoCgSupportedLang.CS:
        case BlancoCgSupportedLang.VB:
            defaultString += " }";
            break;
        case BlancoCgSupportedLang.JS:
        case BlancoCgSupportedLang.RUBY:
        case BlancoCgSupportedLang.PYTHON:
            defaultString += " ]";
            break;
        case BlancoCgSupportedLang.PHP:
            defaultString += " )";
            break;
        }

        BlancoCgField cgField = null;
        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        case BlancoCgSupportedLang.CS:
        case BlancoCgSupportedLang.JS:
        case BlancoCgSupportedLang.RUBY:
        default:
            cgField = fCgFactory.createField("STRING_CONVERT_DEF",
                    getTypeString() + "[][]", "文字列置換定義。");
            break;
        case BlancoCgSupportedLang.VB:
            cgField = fCgFactory.createField("STRING_CONVERT_DEF(,)",
                    getTypeString(), "文字列置換定義。");
            break;
        case BlancoCgSupportedLang.PHP:
            cgField = fCgFactory.createField("STRING_CONVERT_DEF",
                    "array[int][int]string", "文字列置換定義。");
            break;
        }
        fCgClass.getFieldList().add(cgField);

        cgField.setAccess("public");
        switch (fTargetLang) {
        default:
            cgField.setStatic(true);
            cgField.setFinal(true);
            break;
        case BlancoCgSupportedLang.VB:
        case BlancoCgSupportedLang.PHP:
            // VBでは２次元配列を定数化できません。
            // PHPでは配列を定数化できません。
            break;
        }
        cgField.setDefault(defaultString);
    }

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

        final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                getMethodName("convert"), "文字列変換定義に従い、文字列を変換します。");
        fCgClass.getMethodList().add(cgMethod);
        cgMethod.getParameterList().add(
                fCgFactory.createParameter("argCheck", getTypeString(),
                        "変換対象の文字列。", true));
        cgMethod.setReturn(fCgFactory.createReturn(getTypeString(),
                "文字列変換定義にしたがって変換された文字列。変換定義にひとつも合致しない場合には元の文字列が戻ります。"));

        final List lineList = cgMethod.getLineList();

        lineList.add(BlancoCgLineUtil.getVariableDeclaration(fTargetLang,
                "wrkString", BlancoNameUtil.trimJavaPackage(getTypeString()),
                BlancoCgLineUtil.getStringLiteralEnclosure(fTargetLang)
                        + BlancoCgLineUtil
                                .getStringLiteralEnclosure(fTargetLang))
                + BlancoCgLineUtil.getTerminator(fTargetLang));

        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
            lineList.add(BlancoCgLineUtil.getForBeginJava(fTargetLang,
                    "int index = 0", "index < argCheck.length()", ""));
            lineList.add("final String look = argCheck.substring(index)"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.CS:
            lineList.add(BlancoCgLineUtil.getForBeginJava(fTargetLang,
                    "int index = 0", "index < argCheck.Length", ""));
            lineList.add("string look = argCheck.Substring(index)"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.JS:
            lineList.add(BlancoCgLineUtil.getForBeginJava(fTargetLang,
                    "var index = 0", "index < argCheck.length", ""));
            lineList.add("var look = argCheck.substring(index)"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.VB:
            lineList.add(BlancoCgLineUtil.getForBeginVb(fTargetLang,
                    "index As Integer = 0", "argCheck.length - 1", "0"));
            lineList.add("Dim look As String = argCheck.Substring(index)");
            break;
        case BlancoCgSupportedLang.PHP:
            fCgSourceFile.getImportList().add("mbstring.mb_strlen");
            lineList
                    .add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "arraySize = mb_strlen("
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "argCheck)"
                            + BlancoCgLineUtil.getTerminator(fTargetLang));
            lineList.add(BlancoCgLineUtil.getForBeginJava(fTargetLang,
                    BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "index = 0", BlancoCgLineUtil
                            .getVariablePrefix(fTargetLang)
                            + "index < "
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "arraySize", ""));
            lineList.add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "look = mb_substr("
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "argCheck, "
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "index)" + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.RUBY:
            lineList.add("index = 0");
            lineList.add(BlancoCgLineUtil.getWhileBeginRuby(fTargetLang,
                    "index < argCheck.length()"));
            lineList
                    .add("look = argCheck.slice(index, argCheck.length()-index)");
            break;
        case BlancoCgSupportedLang.PYTHON:
            lineList.add("index = 0");
            lineList.add(BlancoCgLineUtil.getWhileBeginRuby(fTargetLang,
                    "index < len(argCheck)"));
            lineList.add("look = argCheck[index:]");
            break;
        }

        switch (fTargetLang) {
        case BlancoCgSupportedLang.PYTHON:
            lineList.add(BlancoCgLineUtil.getVariableDeclaration(fTargetLang,
                    "isFound", getTypeBooleanDef(), "False")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        default:
            lineList.add(BlancoCgLineUtil.getVariableDeclaration(fTargetLang,
                    "isFound", getTypeBooleanDef(), "false")
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        }

        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
            lineList.add(BlancoCgLineUtil.getForBeginJava(fTargetLang,
                    "int indexDef = 0", "indexDef < STRING_CONVERT_DEF.length",
                    "indexDef++"));
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "look.startsWith(STRING_CONVERT_DEF[indexDef][0])"));
            lineList.add("wrkString += STRING_CONVERT_DEF[indexDef][1];");
            lineList.add("index += STRING_CONVERT_DEF[indexDef][0].length();");
            break;
        case BlancoCgSupportedLang.CS:
            lineList.add(BlancoCgLineUtil.getForBeginJava(fTargetLang,
                    "int indexDef = 0", "indexDef < STRING_CONVERT_DEF.Length",
                    "indexDef++"));

            // 2006.10.02 t.iga
            // C#.NETのStartsWithに濁音まわりの比較時にバグが含まれている模様。これに対応するためにJavaなどとは異なり
            // Substringを実施したうえに一致比較を行っています。
            lineList.add("string wrkStrComp = look;");
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "look.Length > STRING_CONVERT_DEF[indexDef][0].Length"));
            lineList
                    .add("wrkStrComp = wrkStrComp.Substring(0, STRING_CONVERT_DEF[indexDef][0].Length);");
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));

            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "STRING_CONVERT_DEF[indexDef][0].Equals(wrkStrComp)"));
            lineList.add("wrkString += STRING_CONVERT_DEF[indexDef][1];");
            lineList.add("index += STRING_CONVERT_DEF[indexDef][0].Length;");
            break;
        case BlancoCgSupportedLang.JS:
            lineList.add(BlancoCgLineUtil.getForBeginJava(fTargetLang,
                    "var indexDef = 0", "indexDef < " + fCgClass.getName()
                            + ".STRING_CONVERT_DEF.length", "indexDef++"));

            // 2006.10.04 t.iga
            // JavaScriptのsearchメソッドは正規表現対応であるので、これはblancoStringConverterとしては利用できません。これに対応するためにJavaなどとは異なり
            // substringを実施したうえに一致比較を行っています。
            lineList.add("var wrkStrComp = look;");
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "look.length > " + fCgClass.getName()
                            + ".STRING_CONVERT_DEF[indexDef][0].length"));
            lineList.add("wrkStrComp = wrkStrComp.substring(0, "
                    + fCgClass.getName()
                    + ".STRING_CONVERT_DEF[indexDef][0].length);");
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));

            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "wrkStrComp === " + fCgClass.getName()
                            + ".STRING_CONVERT_DEF[indexDef][0]"));
            lineList.add("wrkString += " + fCgClass.getName()
                    + ".STRING_CONVERT_DEF[indexDef][1];");
            lineList.add("index += " + fCgClass.getName()
                    + ".STRING_CONVERT_DEF[indexDef][0].length;");
            break;
        case BlancoCgSupportedLang.VB:
            lineList.add(BlancoCgLineUtil.getForBeginVb(fTargetLang,
                    "indexDef As Integer = 0", "STRING_CONVERT_DEF.length -1"));

            lineList.add("Dim wrkStrComp As String = look");
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "look.length > STRING_CONVERT_DEF(indexDef, 0).Length"));
            lineList
                    .add("wrkStrComp = wrkStrComp.substring(0, STRING_CONVERT_DEF(indexDef, 0).Length)");
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));

            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "wrkStrComp = STRING_CONVERT_DEF(indexDef, 0)"));
            lineList.add("wrkString += STRING_CONVERT_DEF(indexDef, 1)");
            lineList.add("index += STRING_CONVERT_DEF(indexDef, 0).Length");
            break;
        case BlancoCgSupportedLang.PHP:
            lineList.add(BlancoCgLineUtil.getForBeginJava(fTargetLang,
                    "$indexDef = 0",
                    "$indexDef < count($this->STRING_CONVERT_DEF)",
                    "$indexDef++"));

            lineList
                    .add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "wrkStrComp = "
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "look;");
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "mb_strlen($look) > mb_strlen($this->STRING_CONVERT_DEF["
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "indexDef][0])"));
            lineList.add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "wrkStrComp = mb_substr("
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "wrkStrComp, 0, mb_strlen($this->STRING_CONVERT_DEF["
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "indexDef][0]));");
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));

            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "wrkStrComp === $this->STRING_CONVERT_DEF["
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "indexDef][0]"));
            lineList.add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "wrkString = "
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "wrkString "
                    + BlancoCgLineUtil
                            .getStringConcatenationOperator(fTargetLang)
                    + " $this->STRING_CONVERT_DEF["
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "indexDef][1]"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            lineList.add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "index += mb_strlen($this->STRING_CONVERT_DEF["
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "indexDef][0])"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.RUBY:
            lineList.add(BlancoCgLineUtil.getForBeginRuby(fTargetLang,
                    "indexDef", "0", "STRING_CONVERT_DEF.length-1"));
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "look.index(STRING_CONVERT_DEF[indexDef][0]) == 0"));
            lineList.add("wrkString += STRING_CONVERT_DEF[indexDef][1]");
            lineList.add("index += STRING_CONVERT_DEF[indexDef][0].length()");
            break;
        case BlancoCgSupportedLang.PYTHON:
            lineList.add(BlancoCgLineUtil.getForBeginPython(fTargetLang,
                    "indexDef", "range(len(self.STRING_CONVERT_DEF))"));
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "look.find(self.STRING_CONVERT_DEF[indexDef][0]) == 0"));
            lineList.add("wrkString += self.STRING_CONVERT_DEF[indexDef][1]");
            lineList.add("index += len(self.STRING_CONVERT_DEF[indexDef][0])");
            break;
        }

        switch (fTargetLang) {
        case BlancoCgSupportedLang.PYTHON:
            lineList.add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "isFound = True"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        default:
            lineList.add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "isFound = true"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        }

        lineList.add(BlancoCgLineUtil.getForExit(fTargetLang)
                + BlancoCgLineUtil.getTerminator(fTargetLang));
        lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));
        lineList.add(BlancoCgLineUtil.getForEnd(fTargetLang));

        switch (fTargetLang) {
        case BlancoCgSupportedLang.VB:
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "isFound = False"));
            break;
        case BlancoCgSupportedLang.PYTHON:
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang,
                    "isFound == False"));
            break;
        default:
            lineList.add(BlancoCgLineUtil.getIfBegin(fTargetLang, "!"
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "isFound"));
            break;
        }

        switch (fTargetLang) {
        case BlancoCgSupportedLang.JAVA:
        case BlancoCgSupportedLang.JS:
            lineList.add("wrkString += argCheck.charAt(index)"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.CS:
        case BlancoCgSupportedLang.VB:
            lineList.add("wrkString += argCheck.Substring(index, 1)"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.PHP:
            lineList
                    .add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "wrkString = "
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "wrkString "
                            + BlancoCgLineUtil
                                    .getStringConcatenationOperator(fTargetLang)
                            + " mb_substr("
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "argCheck, "
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "index, 1)"
                            + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.RUBY:
            lineList.add("wrkString += look.slice(/./)"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        case BlancoCgSupportedLang.PYTHON:
            lineList.add("wrkString += unicode(argCheck[index:])[0].encode()"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            break;
        }

        switch (fTargetLang) {
        case BlancoCgSupportedLang.RUBY:
            lineList.add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "index = "
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "index + look.slice(/./).length()"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));
            break;
        case BlancoCgSupportedLang.PYTHON:
            lineList.add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "index = "
                    + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                    + "index + len(unicode(argCheck[index:])[0].encode())"
                    + BlancoCgLineUtil.getTerminator(fTargetLang));
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));
            break;
        default:
            lineList
                    .add(BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "index = "
                            + BlancoCgLineUtil.getVariablePrefix(fTargetLang)
                            + "index + 1"
                            + BlancoCgLineUtil.getTerminator(fTargetLang));
            lineList.add(BlancoCgLineUtil.getIfEnd(fTargetLang));
            break;
        }

        lineList.add(BlancoCgLineUtil.getForEnd(fTargetLang));
        lineList.add("");
        lineList.add(BlancoCgLineUtil.getReturn(fTargetLang, BlancoCgLineUtil
                .getVariablePrefix(fTargetLang))
                + "wrkString" + BlancoCgLineUtil.getTerminator(fTargetLang));
    }

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

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

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