/*******************************************************************************
 * 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.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import blanco.commons.util.BlancoStringUtil;
import blanco.nlpack.generator.BlancoNLpackGeneratorConstants;
import blanco.nlpack.generator.csv.io.BlancoCsvIOException;
import blanco.nlpack.generator.csv.io.BlancoNLpackGeneratorResultDetailCsvWriter;
import blanco.nlpack.generator.csv.record.BlancoNLpackGeneratorResultDetailCsvRecord;
import blanco.nlpack.generator.dictionary.BlancoNLpackGeneratorPleiadesDictionary;
import blanco.nlpack.generator.task.valueobject.BlancoNLpackGeneratorDiffXliffPleiadesToTranslationFragmentProcessInput;
import blanco.properties.BlancoPropertiesUtil;
import blanco.xliff.BlancoXliffUtil;
import blanco.xliff.valueobject.BlancoXliff;
import blanco.xliff.valueobject.BlancoXliffFile;
import blanco.xliff.valueobject.BlancoXliffNote;
import blanco.xliff.valueobject.BlancoXliffTransUnit;

public class BlancoNLpackGeneratorDiffXliffPleiadesToTranslationFragmentProcessImpl
        implements
        BlancoNLpackGeneratorDiffXliffPleiadesToTranslationFragmentProcess {
    private BlancoNLpackGeneratorDiffXliffPleiadesToTranslationFragmentProcessInput fInput = null;

    /**
     * Pleiades辞書のインスタンス。
     */
    private BlancoNLpackGeneratorPleiadesDictionary fPleiadesDictionary = new BlancoNLpackGeneratorPleiadesDictionary();

    private BlancoNLpackGeneratorResultDetailCsvWriter fWriter = null;

    private final List<BlancoNLpackGeneratorResultDetailCsvRecord> listNew = new ArrayList<BlancoNLpackGeneratorResultDetailCsvRecord>();

    private final List<BlancoNLpackGeneratorResultDetailCsvRecord> listChange = new ArrayList<BlancoNLpackGeneratorResultDetailCsvRecord>();

    /**
     * XLIFFをまたがって同じ文字列が発見された場合のために、これはフィールド変数である必要があります。
     */
    private final Map<String, BlancoXliffTransUnit> fMapProcessed = new HashMap<String, BlancoXliffTransUnit>();

    public int execute(
            final BlancoNLpackGeneratorDiffXliffPleiadesToTranslationFragmentProcessInput input)
            throws IOException, IllegalArgumentException {
        fInput = input;

        final File xliffDir = new File(fInput.getXliffdir());
        if (xliffDir.exists() == false) {
            throw new IllegalArgumentException("指定された xliffdir["
                    + xliffDir.getAbsolutePath() + "]は存在しません。");
        }
        if (xliffDir.isDirectory() == false) {
            throw new IllegalArgumentException("指定された xliffdir["
                    + xliffDir.getAbsolutePath() + "]はディレクトリではありません。");
        }

        final File targetFile = new File(fInput.getTargetfile());
        if (targetFile.getParentFile().exists() == false) {
            if (targetFile.getParentFile().mkdirs() == false) {
                throw new IllegalArgumentException("指定された targetfile["
                        + xliffDir.getAbsolutePath()
                        + "]の格納ディレクトリが無かったので作成を試みましたが失敗しました。");
            }
        }

        fWriter = new BlancoNLpackGeneratorResultDetailCsvWriter(
                new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
                        fInput.getTargetfile()), "Windows-31J")));
        try {
            fWriter.writeTitle();

            final File[] xliffFiles = xliffDir.listFiles();
            if (xliffFiles == null) {
                return 0;
            }
            for (int index = 0; index < xliffFiles.length; index++) {
                if (xliffFiles[index].isFile() == false) {
                    continue;
                }
                if (xliffFiles[index].getName().endsWith(".xlf")) {
                    processXliff(xliffFiles[index], xliffDir);
                }
            }

            // 書き出し。
            for (BlancoNLpackGeneratorResultDetailCsvRecord record : listNew) {
                try {
                    fWriter.writeRecord(record);
                } catch (BlancoCsvIOException e) {
                    throw new IOException("CSV入出力例外: " + e.toString());
                }
            }

            for (BlancoNLpackGeneratorResultDetailCsvRecord record : listChange) {
                try {
                    fWriter.writeRecord(record);
                } catch (BlancoCsvIOException e) {
                    throw new IOException("CSV入出力例外: " + e.toString());
                }
            }

        } finally {
            fWriter.close();
        }

        System.out.println("diff: xliff-pleiades: add:" + listNew.size()
                + ", change:" + listChange.size());

        return 0;
    }

    private void processXliff(final File fileSource, final File sourceDir)
            throws IOException {

        final String bundleSymbolicName = fileSource.getName().substring(0,
                fileSource.getName().length() - ".xlf".length());
        final BlancoXliff xliffSource = BlancoXliffUtil.getXliffInstance(
                fileSource.getParentFile(), bundleSymbolicName);

        for (int indexFile = 0; indexFile < xliffSource.getFileList().size(); indexFile++) {
            final BlancoXliffFile file = (BlancoXliffFile) xliffSource
                    .getFileList().get(indexFile);
            for (int indexTransUnit = 0; indexTransUnit < file.getBody()
                    .getTransUnitList().size(); indexTransUnit++) {
                final BlancoXliffTransUnit transUnit = (BlancoXliffTransUnit) file
                        .getBody().getTransUnitList().get(indexTransUnit);
                if (transUnit.getTarget() == null) {
                    continue;
                }
                if (BlancoStringUtil.null2Blank(
                        transUnit.getTarget().getTarget()).length() == 0) {
                    continue;
                }

                final String pleiadesTrans = fPleiadesDictionary
                        .lookup(transUnit.getSource());
                if (transUnit.getTarget().getTarget().equals(pleiadesTrans) == true) {
                    continue;
                }

                if (transUnit.getTranslate() == false) {
                    // translate="no" の場合には処理スキップします。
                    continue;
                }

                if (getNoteOmitTm(transUnit) != null) {
                    // 翻訳メモリ処理対象外です。
                    // System.out.println("TRACE: 翻訳メモリ処理対象外: "
                    // + sourceUnit.getId());
                    continue;
                }

                if (BlancoPropertiesUtil
                        .isPreferenceKeywords(transUnit.getId())) {
                    // プリファランス・キーワードは処理対象外です。
                    if (fInput.getVerbose()) {
                        System.out.println("uri[" + transUnit.getId()
                                + "] はプリファランス・キーワードであるため翻訳対象から除外します。");
                    }
                    continue;
                }

                if (fMapProcessed.get(transUnit.getSource()) != null) {
                    // 既に同じ文字列で登録済みです。

                    final BlancoXliffTransUnit registered = (BlancoXliffTransUnit) fMapProcessed
                            .get(transUnit.getSource());

                    // note 転送を実施！
                    for (int index = 0; index < transUnit.getNoteList().size(); index++) {
                        final BlancoXliffNote note = (BlancoXliffNote) transUnit
                                .getNoteList().get(index);
                        registered.getNoteList().add(note);
                    }

                    continue;
                }
                fMapProcessed.put(transUnit.getSource(), transUnit);

                final BlancoNLpackGeneratorResultDetailCsvRecord record = new BlancoNLpackGeneratorResultDetailCsvRecord();

                record.setBundleUri(transUnit.getId());
                if (fPleiadesDictionary.getFoundStatus() == BlancoNLpackGeneratorPleiadesDictionary.STATUS_NOT_FOUND) {
                    if (fInput.getIsoutputadd()) {
                        // フラグが立っている時だけ追加します。
                        listNew.add(record);
                    }
                    record.setAction("add");
                    record.setNote("");
                } else {
                    if (fInput.getIsoutputchange()) {
                        // フラグが立っている時だけ追加します。
                        listChange.add(record);
                    }
                    record.setAction("change");
                    record.setNote("[" + pleiadesTrans + "]");
                }

                record.setInput(transUnit.getSource());
                record.setOutput(transUnit.getTarget().getTarget());

                for (int index = 0; index < transUnit.getNoteList().size(); index++) {
                    final BlancoXliffNote note = (BlancoXliffNote) transUnit
                            .getNoteList().get(index);

                    String from = BlancoStringUtil.null2Blank(note.getFrom());
                    if (from.length() > 0) {
                        from += ":";
                    }
                    record.setNote(record.getNote() + " [" + from
                            + note.getText() + "]");
                }
            }
        }

        // xliffは書き込みはしません。
    }

    /**
     * noteを検索して取得します。
     * 
     * @param transUnit
     * @param from
     * @param textString
     * @return
     */
    private BlancoXliffNote getNoteOmitTm(final BlancoXliffTransUnit transUnit) {
        for (int index = 0; index < transUnit.getNoteList().size(); index++) {
            final BlancoXliffNote note = (BlancoXliffNote) transUnit
                    .getNoteList().get(index);
            if (BlancoStringUtil.null2Blank(note.getFrom()).equals(
                    BlancoNLpackGeneratorConstants.PRODUCT_NAME_LOWER
                            + ".omit.tm") == false) {
                // 他のfromのものはスキップします。
                continue;
            }

            // from が一致しました。
            return note;
        }

        return null;
    }
}
