/*******************************************************************************
 * Copyright (c) 2008 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) 2008 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.nlpack.generator;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

import blanco.commons.util.BlancoFileUtil;
import blanco.commons.util.BlancoStringUtil;
import blanco.nlpack.generator.csv.io.BlancoCsvIOException;
import blanco.nlpack.generator.csv.io.BlancoNLpackGeneratorResultCsvWriter;
import blanco.nlpack.generator.csv.io.BlancoNLpackGeneratorResultDetailCsvWriter;
import blanco.nlpack.generator.csv.record.BlancoNLpackGeneratorResultCsvRecord;
import blanco.nlpack.generator.csv.record.BlancoNLpackGeneratorResultDetailCsvRecord;
import blanco.nlpack.generator.message.BlancoNLpackGeneratorMessage;
import blanco.nlpack.generator.resourcebundle.BlancoNLpackGeneratorResourceBundle;
import blanco.nlpack.generator.task.valueobject.BlancoNLpackGeneratorProcessInput;
import blanco.properties.BlancoPropertiesDirectoryParser;
import blanco.properties.BlancoPropertiesUtil;
import blanco.properties.manifest.BlancoPropertiesManifestWriter;
import blanco.properties.manifest.valueobject.BlancoPropertiesManifest;

/**
 * Javaアプリケーションを入力して、言語パックを出力するクラス。
 * 
 * @author IGA Tosiki
 */
public class BlancoNLpackGenerator extends BlancoPropertiesDirectoryParser {
    /**
     * メッセージオブジェクト。
     */
    private final BlancoNLpackGeneratorMessage fMsg = new BlancoNLpackGeneratorMessage();

    private final BlancoNLpackGeneratorResourceBundle fBundle = new BlancoNLpackGeneratorResourceBundle();

    /**
     * 変換のためのインスタンス。
     */
    private final BlancoNLpackGeneratorPropertiesConverter fReplace = new BlancoNLpackGeneratorPropertiesConverter();

    private BlancoNLpackGeneratorProcessInput fInput = null;

    private BlancoNLpackGeneratorResultCsvWriter fLogSummaryWriter = null;

    private BlancoNLpackGeneratorResultDetailCsvWriter fLogDetailWriter = null;

    private String fPropertiesNameWithPath = null;

    /**
     * 指定されたディレクトリのプラグインについて各国語化処理を実行します。
     * 
     * @param argInput
     *            処理への入力パラメータ。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    public void process(final BlancoNLpackGeneratorProcessInput argInput)
            throws IOException {
        fInput = argInput;

        System.out.println("babel: begin: [" + fInput.getSourcedir() + "]->["
                + fInput.getTargetdir() + "].");

        new File(fInput.getTmpdir() + "/log").mkdirs();

        {
            // 出力先ディレクトリを作成。
            final File fileTarget = new File(fInput.getTargetdir());
            if (fileTarget.exists() == false) {
                fileTarget.mkdirs();
            }
        }

        // TODO ログファイル名の外部化。
        final File fileLogSummary = new File(fInput.getTmpdir()
                + "/log/blancoNLpackGeneratorResult.csv");
        try {
            final BufferedWriter writer = new BufferedWriter(
                    new BufferedWriter(new FileWriter(fileLogSummary, true)));
            writer.write("[[" + BlancoNLpackGeneratorConstants.PRODUCT_NAME
                    + " (" + BlancoNLpackGeneratorConstants.VERSION + ")"
                    + "]]: " + fInput.getSourcedir());
            writer.newLine();

            fLogSummaryWriter = new BlancoNLpackGeneratorResultCsvWriter(writer);
            fLogSummaryWriter.writeTitle();
        } catch (IOException ex) {
            throw new IllegalArgumentException(fMsg.getMbebi004(fileLogSummary
                    .getAbsolutePath(), ex.toString()));
        }

        // TODO ログファイル名の外部化。
        final File fileLogDetail = new File(fInput.getTmpdir()
                + "/log/blancoNLpackGeneratorResultDetail.csv");
        try {
            final BufferedWriter writer = new BufferedWriter(
                    new BufferedWriter(new FileWriter(fileLogDetail, true)));
            writer.write("[[" + BlancoNLpackGeneratorConstants.PRODUCT_NAME
                    + " (" + BlancoNLpackGeneratorConstants.VERSION + ")"
                    + "]]: " + fInput.getSourcedir());
            writer.newLine();

            fLogDetailWriter = new BlancoNLpackGeneratorResultDetailCsvWriter(
                    writer);
            fLogDetailWriter.writeTitle();
        } catch (IOException ex) {
            throw new IllegalArgumentException(fMsg.getMbebi005(fileLogDetail
                    .getAbsolutePath(), ex.toString()));
        }

        try {
            if (new File(fInput.getSourcedir()).exists() == false) {
                throw new IllegalArgumentException(fMsg.getMbebi001(fInput
                        .getSourcedir()));
            }

            parse(new File(fInput.getSourcedir()));
        } finally {
            if (fLogSummaryWriter != null) {
                fLogSummaryWriter.close();
                fLogSummaryWriter = null;
            }

            if (fLogDetailWriter != null) {
                fLogDetailWriter.close();
                fLogDetailWriter = null;
            }
        }

        System.out.println("babel: end.");
    }

    @Override
    protected void beginProperties(final String bundleURI,
            final Properties inputProps,
            final String argPropertiesNameWithPath,
            final BufferedWriter bufPropsWriter) throws IOException {
        fPropertiesNameWithPath = argPropertiesNameWithPath;
        if (BlancoStringUtil.null2Blank(fBundle.getPropertiesHeader()).length() > 0) {
            // 人工的にヘッダーを付与します。
            bufPropsWriter.write(fBundle.getPropertiesHeader());
            bufPropsWriter.newLine();
            bufPropsWriter.newLine();
        }
        fReplace.resetReplaceCount();
    }

    @Override
    protected boolean processPropertiesKey(final String bundleURI,
            final Properties inputProps, final String key,
            final BufferedWriter bufPropsWriter) throws IOException {
        boolean isReplaced = false;
        final BlancoNLpackGeneratorResultDetailCsvRecord record = new BlancoNLpackGeneratorResultDetailCsvRecord();

        final String inputValue = (String) inputProps.get(key);

        if (fReplace.lookup(bundleURI, key, inputValue, bufPropsWriter, record)) {
            isReplaced = true;
        }

        bufPropsWriter.newLine();

        try {
            fLogDetailWriter.writeRecord(record);
        } catch (BlancoCsvIOException e) {
            // TOOD 例外メッセージ採番。
            throw new IOException(e.toString());
        }
        return isReplaced;
    }

    @Override
    protected void endProperties(final String bundleURI,
            final Properties inputProps,
            final BlancoPropertiesManifest manifest,
            final byte[] bufPropsBytes, final boolean isReplaced)
            throws IOException {
        final BlancoNLpackGeneratorResultCsvRecord record = new BlancoNLpackGeneratorResultCsvRecord();
        record.setBundleSymbolicName(BlancoPropertiesUtil
                .getHostFromBabelURI(bundleURI));
        record.setBundleUri(bundleURI);

        if (isReplaced) {
            final File fileTarget = new File(fInput.getTargetdir()
                    + "/"
                    + BlancoPropertiesUtil.getPluginNameWithSuffix(manifest,
                            fBundle.getTargetLocale())
                    + fPropertiesNameWithPath.substring(0,
                            fPropertiesNameWithPath.length()
                                    - ".properties".length()) + "_"
                    + fBundle.getTargetLocale() + ".properties");
            fileTarget.getParentFile().mkdirs();
            switch (BlancoFileUtil.bytes2FileIfNecessary(bufPropsBytes,
                    fileTarget)) {
            case 1:
                if (fInput.getVerbose()) {
                    System.out
                            .println(BlancoNLpackGeneratorConstants.PRODUCT_SHORT_NAME
                                    + ": create: " + bundleURI);
                }
                record.setAction("create");
                break;
            case 2:
                if (fInput.getVerbose()) {
                    System.out
                            .println(BlancoNLpackGeneratorConstants.PRODUCT_SHORT_NAME
                                    + ": update: " + bundleURI);
                }
                record.setAction("update");
                break;
            case 0:
                if (fInput.getVerbose()) {
                    System.out
                            .println(BlancoNLpackGeneratorConstants.PRODUCT_SHORT_NAME
                                    + ": none  : " + bundleURI);
                }
                record.setAction("none");
                break;
            }

            // 翻訳処理が実施された場合には MANIFEST.MF関連ファイルを生成します。
            new BlancoPropertiesManifestWriter().write(manifest, new File(
                    fInput.getTargetdir()
                            + "/"
                            + BlancoPropertiesUtil.getPluginNameWithSuffix(
                                    manifest, fBundle.getTargetLocale())));
        } else {
            if (fInput.getVerbose()) {
                System.out
                        .println(BlancoNLpackGeneratorConstants.PRODUCT_SHORT_NAME
                                + ": skip  : " + bundleURI);
            }
            record.setAction("skip");
        }

        record.setReplaceHitCount(fReplace.getReplaceHitCount());
        record.setReplaceMnemonicCount(fReplace.getReplaceMnemonicCount());
        record.setReplaceOmitCount(fReplace.getReplaceOmitCount());
        record.setReplaceMissCount(fReplace.getReplaceMissCount());
        try {
            fLogSummaryWriter.writeRecord(record);
        } catch (BlancoCsvIOException e) {
            throw new IOException(fMsg.getMbebc001(e.toString()));
        }
    }
}
