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

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

import blanco.commons.util.BlancoStringUtil;
import blanco.nlpack.generator.BlancoNLpackGeneratorConstants;
import blanco.nlpack.generator.message.BlancoNLpackGeneratorMessage;
import blanco.nlpack.generator.resourcebundle.BlancoNLpackGeneratorResourceBundle;
import blanco.nlpack.generator.task.valueobject.BlancoNLpackGeneratorTranslateXliffByNLpackProcessInput;
import blanco.properties.BlancoPropertiesDirectoryParser;
import blanco.properties.BlancoPropertiesUtil;
import blanco.properties.manifest.valueobject.BlancoPropertiesManifest;
import blanco.xliff.BlancoXliffUtil;
import blanco.xliff.valueobject.BlancoXliff;
import blanco.xliff.valueobject.BlancoXliffAltTrans;
import blanco.xliff.valueobject.BlancoXliffNote;
import blanco.xliff.valueobject.BlancoXliffTarget;
import blanco.xliff.valueobject.BlancoXliffTransUnit;

public class BlancoNLpackGeneratorTranslateXliffByNLpackProcessImpl extends
        BlancoPropertiesDirectoryParser implements
        BlancoNLpackGeneratorTranslateXliffByNLpackProcess {
    private BlancoNLpackGeneratorTranslateXliffByNLpackProcessInput fInput = null;

    /**
     * メッセージオブジェクト。
     */
    private final BlancoNLpackGeneratorMessage fMsg = new BlancoNLpackGeneratorMessage();

    private final BlancoNLpackGeneratorResourceBundle fBundle = new BlancoNLpackGeneratorResourceBundle();

    private String fPrevBundleSymbolicName = null;

    private BlancoXliff fXliff = null;

    /**
     * クラスをインスタンス化して処理を実行する際のエントリポイントです。
     * 
     * @param input
     *            処理の入力パラメータ。
     * @return 処理の実行結果。
     * @throws IOException
     *             入出力例外が発生した場合。
     * @throws IllegalArgumentException
     *             入力値に不正が見つかった場合。
     */
    public int execute(
            final BlancoNLpackGeneratorTranslateXliffByNLpackProcessInput input)
            throws IOException, IllegalArgumentException {
        fInput = input;

        // キャッシュのクリア。
        fPrevBundleSymbolicName = null;

        // 自ロケールのみを処理対象とします。
        setProcessTargetLocale(true);

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

        if (new File(fInput.getXliffdir()).exists() == false) {
            new File(fInput.getXliffdir()).mkdirs();
        }

        parse(new File(fInput.getSourcedir()));

        return 0;
    }

    @Override
    protected void beginProperties(String bundleURI, Properties inputProps,
            String argPropertiesNameWithPath, BufferedWriter bufPropsWriter)
            throws IOException {
        final String nextBundleSymbolicName = BlancoPropertiesUtil
                .getHostFromBabelURI(getBundleURIWithoutLocale(bundleURI));
        if (nextBundleSymbolicName.equals(fPrevBundleSymbolicName)) {
            // キャッシュがヒットしました。リロードしません。
        } else {
            fXliff = BlancoXliffUtil.getXliffInstance(new File(fInput
                    .getXliffdir()), nextBundleSymbolicName);
            fPrevBundleSymbolicName = nextBundleSymbolicName;
        }
    }

    @Override
    protected boolean processPropertiesKey(final String bundleURI,
            final Properties inputProps, final String key,
            final BufferedWriter bufPropsWriter) throws IOException {
        if (BlancoPropertiesUtil.getFileFromBabelURI(
                getBundleURIWithoutLocale(bundleURI)).equals(
                "/nl_fragment.properties")) {
            return false;
        }

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

        final String uri = getBundleURIWithoutLocale(bundleURI) + "?key=" + key;

        final BlancoXliffTransUnit transUnit = getTransUnitInstance(fXliff, uri);
        if (transUnit != null) {
            if (BlancoStringUtil.null2Blank(transUnit.getSource()).equals(
                    BlancoStringUtil.null2Blank(localizedValue))) {
                // source と target とが同一の値の場合には セットしません。
                return false;
            }

            // 言語パックから翻訳をおこなうので、source文字列が一致するかどうかの判定は行いません。(行うことができません)
            setTarget(transUnit, localizedValue);

            setAltTransTarget("nlpack", transUnit, transUnit.getSource(),
                    localizedValue);
            return true;
        } else {
            System.out.println("指定のXLIFF trans-unit は存在しません: " + uri);
            return false;
        }
    }

    @Override
    protected void endProperties(String bundleURI, Properties inputProps,
            BlancoPropertiesManifest manifest, byte[] bufPropsBytes,
            boolean isReplaced) throws IOException {
        if (isReplaced) {
            switch (BlancoXliffUtil.saveXliffInstance(fXliff, new File(fInput
                    .getXliffdir()), BlancoPropertiesUtil
                    .getHostFromBabelURI(getBundleURIWithoutLocale(bundleURI)))) {
            case 1:
                if (fInput.getVerbose()) {
                    System.out
                            .println("xliff: trans: nlpack: create: "
                                    + BlancoPropertiesUtil
                                            .getHostFromBabelURI(getBundleURIWithoutLocale(bundleURI)));
                }
                break;
            case 2:
                if (fInput.getVerbose()) {
                    System.out
                            .println("xliff: trans: nlpack: update: "
                                    + BlancoPropertiesUtil
                                            .getHostFromBabelURI(getBundleURIWithoutLocale(bundleURI)));
                }
                break;
            case 0:
                break;
            }
        }
    }

    private BlancoXliffTransUnit getTransUnitInstance(final BlancoXliff xliff,
            final String id) {
        BlancoXliffTransUnit transUnit = BlancoXliffUtil
                .getTransUnit(xliff, id);
        if (transUnit != null) {
            // 指定されたidによる trans-unit が既にあれば それを返却。
            return transUnit;
        }

        // 存在しない場合は処理しません。
        return null;
    }

    private void setTarget(final BlancoXliffTransUnit transUnit,
            final String outputValue) {
        final BlancoXliffTarget target = new BlancoXliffTarget();
        transUnit.setTarget(target);
        target.setTarget(outputValue);

        // フラグはセットしないように変更されました。
        // 機械的にセットされたので、レビュー必要フラグをセットします。
        // target.setState("needs-review-translation");
    }

    /**
     * targetをセットします。
     * 
     * @param transUnit
     * @param targetString
     * @return
     */
    static boolean setAltTransTarget(final String tool_id,
            final BlancoXliffTransUnit transUnit, final String sourceString,
            final String targetString) {
        boolean isModified = false;

        if (BlancoXliffUtil.getAltTrans(transUnit, tool_id, BlancoStringUtil
                .null2Blank(sourceString), BlancoStringUtil
                .null2Blank(targetString)) == null) {
            isModified = true;
            final BlancoXliffAltTrans altTransNew = new BlancoXliffAltTrans();
            transUnit.getAltTransList().add(altTransNew);
            altTransNew.setToolId(tool_id);
            altTransNew.setSource(sourceString);
            final BlancoXliffTarget target = new BlancoXliffTarget();
            altTransNew.setTarget(target);
            target.setTarget(targetString);

            final BlancoXliffNote note = new BlancoXliffNote();
            note.setFrom(BlancoNLpackGeneratorConstants.PRODUCT_NAME_LOWER
                    + ".version");
            note.setText(BlancoNLpackGeneratorConstants.VERSION);
            altTransNew.getNoteList().add(note);
        }

        return isModified;
    }

    /**
     * URIからロケールを除去します。
     * 
     * クエリには対応しません。
     * 
     * @param bundleName
     * @return
     */
    private String getBundleURIWithoutLocale(final String bundleName) {
        String host = BlancoPropertiesUtil.getHostFromBabelURI(bundleName);
        if (host.endsWith(".nl_" + fBundle.getTargetLocale())) {
            host = host.substring(0, host.length()
                    - (".nl_" + fBundle.getTargetLocale()).length());
        } else if (host.endsWith(".nl1")) {
            host = host.substring(0, host.length() - ".nl1".length());
        } else if (host.endsWith(".nls1")) {
            host = host.substring(0, host.length() - ".nls1".length());
        }

        String path = BlancoPropertiesUtil.getPathFromBabelURI(bundleName);
        if (path.endsWith("_" + fBundle.getTargetLocale() + ".properties")) {
            path = path.substring(0, path.length()
                    - ("_" + fBundle.getTargetLocale() + ".properties")
                            .length())
                    + ".properties";
        }

        String result = "babel://" + host + path;

        return result;
    }
}
