/*******************************************************************************
 * 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.File;
import java.io.IOException;

import blanco.commons.util.BlancoNameUtil;
import blanco.nlpack.generator.BlancoNLpackGeneratorConstants;
import blanco.nlpack.generator.dictionary.BlancoNLpackGeneratorOmitDictionary;
import blanco.nlpack.generator.task.valueobject.BlancoNLpackGeneratorOmitXliffProcessInput;
import blanco.xliff.BlancoXliffUtil;
import blanco.xliff.valueobject.BlancoXliff;
import blanco.xliff.valueobject.BlancoXliffFile;
import blanco.xliff.valueobject.BlancoXliffNote;
import blanco.xliff.valueobject.BlancoXliffTool;
import blanco.xliff.valueobject.BlancoXliffTransUnit;

public class BlancoNLpackGeneratorOmitXliffProcessImpl implements
        BlancoNLpackGeneratorOmitXliffProcess {
    private BlancoNLpackGeneratorOmitXliffProcessInput fInput = null;

    private int fOmitU = 0;

    private int fOmitS = 0;

    private int fOmitP = 0;

    /**
     * blancoNLpackGeneratorとしての除外辞書インスタンス。
     */
    private BlancoNLpackGeneratorOmitDictionary fOmitDictionary = new BlancoNLpackGeneratorOmitDictionary();

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

        final File fileXliffdir = new File(input.getXliffdir());
        final File[] files = fileXliffdir.listFiles();
        if (files == null) {
            return 0;
        }
        for (int index = 0; index < files.length; index++) {
            if (files[index].isFile() == false) {
                continue;
            }
            if (files[index].getName().endsWith(".xlf")) {
                try {
                    process(fileXliffdir, files[index]);
                } catch (IllegalArgumentException ex) {
                    System.out.println("ファイル[" + files[index].getAbsolutePath()
                            + "]の処理中に例外が発生しました。");
                    throw ex;
                }
            }
        }

        return 0;
    }

    private void process(final File fileXliffdir, final File fileTarget)
            throws IOException {
        fOmitU = 0;
        fOmitS = 0;
        fOmitP = 0;

        final String bundleSymbolicName = fileTarget.getName().substring(0,
                fileTarget.getName().length() - ".xlf".length());
        final BlancoXliff xliff = BlancoXliffUtil.getXliffInstance(
                fileXliffdir, bundleSymbolicName);

        for (int indexFile = 0; indexFile < xliff.getFileList().size(); indexFile++) {
            final BlancoXliffFile file = (BlancoXliffFile) xliff.getFileList()
                    .get(indexFile);
            processFile(file);
        }

        switch (BlancoXliffUtil.saveXliffInstance(xliff, fileXliffdir,
                bundleSymbolicName)) {
        case 1:
            // 基本的に、こちらには入らない見込み。
            if (fInput.getVerbose()) {
                System.out
                        .println("xliff: omit: create: " + bundleSymbolicName);
            }
            break;
        case 2:
            if (fInput.getVerbose()) {
                System.out.println("xliff: omit: update: " + bundleSymbolicName
                        + " u=" + fOmitU + ", p=" + fOmitP + ", s=" + fOmitS);
            }
            break;
        }
    }

    private void processFile(final BlancoXliffFile file) throws IOException {
        boolean isToolModified = false;
        for (int index = 0; index < file.getBody().getTransUnitList().size(); index++) {
            final BlancoXliffTransUnit transUnit = (BlancoXliffTransUnit) file
                    .getBody().getTransUnitList().get(index);

            if (false) {
                // まったく関係のない ニモーニック変換のみのtargetを発見するための処理。: begin
                if (transUnit.getTarget() != null
                        && transUnit.getTarget().getTarget() != null
                        && transUnit.getTarget().getState() != null) {
                    if (transUnit.getTarget().getState().equals(
                            "needs-review-translation")) {
                        if (transUnit.getSource().indexOf("&") >= 0
                                && transUnit.getTarget().getTarget().indexOf(
                                        "(&") >= 0) {
                            int input = transUnit.getTarget().getTarget()
                                    .length();
                            int output = transUnit.getTarget().getTarget()
                                    .getBytes("UTF-8").length;
                            if (input == output) {
                                // これは ニモーニックでは？
                                transUnit.getTarget().setState(
                                        "needs-translation");
                            }
                        }
                    }
                }
                // まったく関係のない ニモーニック変換のみのtargetを発見するための処理。: end
            }

            if (transUnit.getTarget() != null) {
                // 既に targetは存在する。
                if (fInput.getIsforceiftargetexist() == false) {
                    // この trans-unit は処理対象外とします。
                    continue;
                }
            }

            final String[] split = BlancoNameUtil.splitString(
                    transUnit.getId(), '?');

            if (fOmitDictionary.checkOmitURI(split[0])
                    || fOmitDictionary.checkOmitURI(transUnit.getId())) {
                // URIベースのomit判定で除外対象とわかった場合。
                if (transUnit.getTranslate()) {
                    fOmitU++;
                    isToolModified = true;
                    transUnit.setTranslate(false);
                    transUnit.getNoteList().add(getNoteForAction("omit.u"));
                }
                continue;
            }

            if (transUnit.getSource() != null
                    && fOmitDictionary.checkOmitPhrase(transUnit.getSource())) {
                // 文字列だけを見た場合にフレーズ除外対象とわかった場合。
                if (transUnit.getTranslate()) {
                    fOmitP++;
                    isToolModified = true;
                    transUnit.setTranslate(false);
                    transUnit.getNoteList().add(getNoteForAction("omit.p"));
                }
                continue;
            }

            if (fOmitDictionary.checkOmitString(transUnit.getSource())) {
                // 文字列だけを見た場合に除外対象とわかった場合。
                if (transUnit.getTranslate()) {
                    fOmitS++;
                    isToolModified = true;
                    transUnit.setTranslate(false);
                    transUnit.getNoteList().add(getNoteForAction("omit.s"));
                }
                continue;
            }

            if (fOmitDictionary.checkOmitStringPattern(transUnit.getSource())) {
                // FIXME これを常に実行してよいのかどうか不明。
                // 文字列を見て良くある除外パターンと合致した場合。
                if (transUnit.getTranslate() && transUnit.getTarget() == null) {
                    // targetがない場合にのみ適用。
                    fOmitS++;
                    isToolModified = true;
                    transUnit.setTranslate(false);
                    transUnit.getNoteList().add(getNoteForAction("omit.s"));
                }
                continue;
            }
        }

        if (isToolModified) {
            final BlancoXliffTool tool = new BlancoXliffTool();
            tool.setToolId("blanconlpackgenerator");
            tool.setToolName("blancoNLpackGenerator");
            BlancoXliffUtil.setTool(file.getHeader(), tool);
        }
    }

    private BlancoXliffNote getNoteForAction(final String action) {
        final BlancoXliffNote note = new BlancoXliffNote();
        note.setFrom(BlancoNLpackGeneratorConstants.PRODUCT_NAME_LOWER
                + ".action");
        note.setText(action);
        return note;
    }
}
