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

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import blanco.commons.util.BlancoStringUtil;
import blanco.xliff.BlancoXliffUtil;
import blanco.xliff.util.task.valueobject.BlancoXliffUtilCleanProcessInput;
import blanco.xliff.valueobject.BlancoXliff;
import blanco.xliff.valueobject.BlancoXliffAltTrans;
import blanco.xliff.valueobject.BlancoXliffFile;
import blanco.xliff.valueobject.BlancoXliffNote;
import blanco.xliff.valueobject.BlancoXliffTransUnit;

public class BlancoXliffUtilCleanProcessImpl implements
        BlancoXliffUtilCleanProcess {

    private BlancoXliff fXliff = null;

    private BlancoXliffUtilCleanProcessInput fInput = null;

    private int fTotalTransUnitCount = 0;

    private int fActiveTransUnitCount = 0;

    private int fUpdateXlfCount = 0;

    public int execute(final BlancoXliffUtilCleanProcessInput 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")) {
                process(fileXliffdir, files[index]);
            }
        }

        System.out.println("xliff: clean: update=" + fUpdateXlfCount);
        System.out.println("- trans-unit (total=" + fTotalTransUnitCount
                + ", active=" + fActiveTransUnitCount + ")");

        return 0;
    }

    private void process(final File fileXliffdir, final File fileTarget)
            throws IOException {

        final String bundleSymbolicName = fileTarget.getName().substring(0,
                fileTarget.getName().length() - ".xlf".length());

        fXliff = BlancoXliffUtil.getXliffInstance(fileXliffdir,
                bundleSymbolicName);

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

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

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

            // 全 trans-unit
            fTotalTransUnitCount++;

            if (transUnit.getTranslate() == false) {
                // 除外項目。
            } else {
                // 翻訳対象 trans-unit
                fActiveTransUnitCount++;
            }

            // ここでクリーンナップ処理を実施。
            // ポイント: translate 属性の値にかかわらず処理を実施。
            cleanAction(transUnit);
            cleanAltTrans(transUnit);
        }
    }

    /**
     * 同じ tool-id で複数の alt-trans が存在する場合、最後の(もっとも末尾にある)ものだけを残し、他は削除します。
     * 
     * @param transUnit
     */
    private void cleanAltTrans(final BlancoXliffTransUnit transUnit) {
        // tool-idが重複する alt-trans を検索。
        final Map<String, String> mapPrev = new HashMap<String, String>();
        final Map<String, BlancoXliffAltTrans> mapDup = new HashMap<String, BlancoXliffAltTrans>();
        for (int indexAltTrans = 0; indexAltTrans < transUnit.getAltTransList()
                .size(); indexAltTrans++) {
            final BlancoXliffAltTrans altTrans = transUnit.getAltTransList()
                    .get(indexAltTrans);
            if (BlancoStringUtil.null2Blank(altTrans.getToolId()).length() == 0) {
                // tool-idが設定されていないものはスキップします。
                continue;
            }

            if (mapPrev.get(altTrans.getToolId()) != null) {
                // 重複しています。
                mapDup.put(mapPrev.get(altTrans.getToolId()), altTrans);
            }
            mapPrev.put(altTrans.getToolId(), String.valueOf(indexAltTrans));
        }

        // 重複分を削除
        for (int indexAltTrans = transUnit.getAltTransList().size() - 1; indexAltTrans >= 0; indexAltTrans--) {
            if (mapDup.get(String.valueOf(indexAltTrans)) != null) {
                // 重複していたものです。
                transUnit.getAltTransList().remove(indexAltTrans);
            }
        }

        // omegat 翻訳分を削除
        for (int indexAltTrans = transUnit.getAltTransList().size() - 1; indexAltTrans >= 0; indexAltTrans--) {
            final BlancoXliffAltTrans altTrans = transUnit.getAltTransList()
                    .get(indexAltTrans);
            if (BlancoStringUtil.null2Blank(altTrans.getToolId()).equals(
                    "omegat")) {
                // OmegaTが訳出したalt-trans は削除します。
                transUnit.getAltTransList().remove(indexAltTrans);
            }
        }
    }

    /**
     * blancoNLpackGenerator がワーク的に付与する actionメモを削除します。
     * 
     * @param transUnit
     */
    private void cleanAction(final BlancoXliffTransUnit transUnit) {
        // blanconlpackgenerator.actionを検索。
        for (int indexNote = transUnit.getNoteList().size() - 1; indexNote >= 0; indexNote--) {
            final BlancoXliffNote note = transUnit.getNoteList().get(indexNote);
            if (BlancoStringUtil.null2Blank(note.getFrom()).length() == 0) {
                // fromが設定されていないものはスキップします。
                continue;
            }

            if (note.getFrom().equals("blanconlpackgenerator.action")) {
                transUnit.getNoteList().remove(indexNote);
            }
        }
    }
}
