/*******************************************************************************
 * Copyright (c) 2009 IGA Tosiki, NTT DATA BUSINESS BRAINS Corp.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IGA Tosiki (NTT DATA BUSINESS BRAINS Corp.) - initial API and implementation
 *******************************************************************************/
/*
 * blanco Framework
 * Copyright (C) 2009 NTT DATA BUSINESS BRAINS CORPORATION
 * 
 * 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.eclipsenls;

import java.io.File;
import java.io.IOException;

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.transformer.BlancoCgTransformerFactory;
import blanco.cg.valueobject.BlancoCgClass;
import blanco.cg.valueobject.BlancoCgField;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.commons.util.BlancoJavaSourceUtil;
import blanco.commons.util.BlancoNameAdjuster;
import blanco.commons.util.BlancoStringUtil;
import blanco.eclipsenls.valueobject.BlancoEclipseNlsFieldStructure;
import blanco.eclipsenls.valueobject.BlancoEclipseNlsStructure;

/**
 * 「Eclipse NLS 定義書」Excel様式からメッセージを処理するクラス・ソースコードを生成。
 * 
 * このクラスは、中間XMLファイルからソースコードを自動生成する機能を担います。
 * 
 * @author IGA Tosiki
 */
public class BlancoEclipseNlsXml2SourceFile {
    /**
     * 内部的に利用するblancoCg用ファクトリ。
     */
    private BlancoCgObjectFactory fCgFactory = null;

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

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

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

    public void setEncoding(final String argEncoding) {
        fEncoding = argEncoding;
    }

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

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

    /**
     * 指定のシートの記述内容を展開します。
     * 
     * @param argStructure
     *            タスクの構造。
     * @param argDirectoryTarget
     *            出力先ディレクトリ
     */
    public void structure2Source(final BlancoEclipseNlsStructure argStructure,
            final File argDirectoryTarget) {
        // 従来と互換性を持たせるため、/mainサブフォルダに出力します。
        final File fileBlancoMain = new File(argDirectoryTarget
                .getAbsolutePath()
                + "/main");

        fCgFactory = BlancoCgObjectFactory.getInstance();
        fCgSourceFile = fCgFactory.createSourceFile(argStructure.getPackage(),
                "このソースコードは blanco Frameworkによって自動生成されています。");
        fCgSourceFile.setEncoding(fEncoding);
        fCgClass = fCgFactory.createClass(BlancoNameAdjuster
                .toClassName(argStructure.getName()), BlancoStringUtil
                .null2Blank(argStructure.getDescription()));
        fCgSourceFile.getClassList().add(fCgClass);

        fCgClass.getExtendClassList().add(
                fCgFactory.createType("org.eclipse.osgi.util.NLS"));

        fCgClass.getLangDoc().getDescriptionList().add(
                "このクラスは、Eclipse NLS のためのクラスです。");

        {
            final BlancoCgField field = new BlancoCgField();
            field.setName("BUNDLE_NAME");
            field.setType(fCgFactory.createType("java.lang.String"));
            field.setDescription("プロパティファイルの基底名をパッケージ名修飾付きにした名称。");
            field.setDefault("\"" + argStructure.getPackage() + "."
                    + argStructure.getBaseName() + "\"");
            field.setFinal(true);
            field.setAccess("private");
            field.setStatic(true);
            fCgClass.getFieldList().add(field);
        }

        {
            final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                    "staticInitializer", "フィールドの初期化処理を実施します。");
            fCgClass.getMethodList().add(cgMethod);
            cgMethod.setStaticInitializer(true);
            cgMethod.getLineList().add(
                    "NLS.initializeMessages(BUNDLE_NAME, " + fCgClass.getName()
                            + ".class);");
        }

        {
            final BlancoCgMethod cgMethod = fCgFactory.createMethod(fCgClass
                    .getName(), "コンストラクタを隠します。");
            fCgClass.getMethodList().add(cgMethod);
            cgMethod.setConstructor(true);
            cgMethod.setAccess("private");
        }

        for (int indexField = 0; indexField < argStructure.getFieldList()
                .size(); indexField++) {
            final BlancoEclipseNlsFieldStructure fieldLook = argStructure
                    .getFieldList().get(indexField);
            expandFieldEclipseNls(argStructure, fieldLook);
        }

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

    /**
     * NLS のフィールドを展開します。
     * 
     * @param argProcessStructure
     *            メタファイルから収集できた処理構造データ。
     */
    private void expandFieldEclipseNls(
            final BlancoEclipseNlsStructure argProcessStructure,
            final BlancoEclipseNlsFieldStructure fieldLook) {
        final String fieldName = fieldLook.getName();

        final BlancoCgField cgField = fCgFactory.createField(fieldName,
                "java.lang.String", "Eclipse NLS 定義ID["
                        + argProcessStructure.getName() + "]、キー["
                        + fieldLook.getName() + "]の文字列です。");
        fCgClass.getFieldList().add(cgField);
        cgField.setAccess("public");
        cgField.setStatic(true);
        // Eclipse NLS ではデフォルト値の設定が無効であるように判断。

        cgField.getLangDoc().getDescriptionList().add(
                "文字列["
                        + BlancoJavaSourceUtil.escapeStringAsJavaDoc(fieldLook
                                .getMessage()
                                + "]"));
    }
}
