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

import java.io.File;
import java.io.IOException;

import blanco.commons.util.BlancoStringUtil;
import blanco.tmx.BlancoTmxSerializer;
import blanco.tmx.valueobject.BlancoTmx;
import blanco.tmx.valueobject.BlancoTmxTu;
import blanco.tmx.valueobject.BlancoTmxTuv;
import blanco.xliff.BlancoXliffUtil;
import blanco.xliff.valueobject.BlancoXliff;
import blanco.xliff.valueobject.BlancoXliffAltTrans;
import blanco.xliff.valueobject.BlancoXliffFile;
import blanco.xliff.valueobject.BlancoXliffTransUnit;
import blanco.xliff2tmx.message.BlancoXliff2TmxMessage;
import blanco.xliff2tmx.task.valueobject.BlancoXliff2TmxProcessInput;

/**
 * XLIFF を TMX に変換します。
 * 
 * @author IGA Tosiki
 */
public class BlancoXliff2TmxProcessImpl implements BlancoXliff2TmxProcess {
    private BlancoXliff2TmxProcessInput fInput = null;

    private final BlancoXliff2TmxMessage fMsg = new BlancoXliff2TmxMessage();

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

        final File sourceDir = new File(fInput.getSourcedir());
        if (sourceDir.exists() == false) {
            throw new IllegalArgumentException(fMsg.getMbxl2t01(sourceDir
                    .getAbsolutePath()));
        }
        if (sourceDir.isDirectory() == false) {
            throw new IllegalArgumentException(fMsg.getMbxl2t02(sourceDir
                    .getAbsolutePath()));
        }

        final boolean isTargetDirSet = BlancoStringUtil.null2Blank(
                input.getTargetdir()).length() > 0;
        final boolean isTargetFileSet = BlancoStringUtil.null2Blank(
                input.getTargetfile()).length() > 0;
        if (isTargetDirSet == false && isTargetFileSet == false) {
            throw new IllegalArgumentException(fMsg.getMbxl2t03());
        }
        if (isTargetDirSet && isTargetFileSet) {
            throw new IllegalArgumentException(fMsg.getMbxl2t04());
        }

        if (isTargetDirSet) {
            final File targetDir = new File(fInput.getTargetdir());
            if (targetDir.exists() == false) {
                if (targetDir.mkdirs() == false) {
                    throw new IllegalArgumentException(fMsg
                            .getMbxl2t05(targetDir.getAbsolutePath()));
                }
            }
            if (targetDir.isDirectory() == false) {
                throw new IllegalArgumentException(fMsg.getMbxl2t06(targetDir
                        .getAbsolutePath()));
            }

            if (sourceDir.getCanonicalPath().equals(
                    targetDir.getCanonicalPath())) {
                throw new IllegalArgumentException(fMsg.getMbxl2t07(sourceDir
                        .getAbsolutePath(), targetDir.getAbsolutePath()));
            }

        }
        if (isTargetFileSet) {
            final File targetFile = new File(fInput.getTargetfile());
            if (targetFile.exists()) {
                if (targetFile.canWrite() == false) {
                    throw new IllegalArgumentException(fMsg
                            .getMbxl2t08(targetFile.getAbsolutePath()));
                }
            }
            if (targetFile.getParentFile().exists() == false) {
                if (targetFile.getParentFile().mkdirs() == false) {
                    throw new IllegalArgumentException(fMsg
                            .getMbxl2t09(targetFile.getAbsolutePath()));
                }
            }
        }

        final File[] sourceFiles = sourceDir.listFiles();
        if (sourceFiles == null) {
            return 0;
        }

        BlancoTmx tmx = new BlancoTmx();
        for (int index = 0; index < sourceFiles.length; index++) {
            if (sourceFiles[index].isFile() == false) {
                continue;
            }
            if (sourceFiles[index].getName().endsWith(".xlf")) {
                if (isTargetDirSet) {
                    // 処理毎に初期化します。
                    tmx = new BlancoTmx();
                }

                processXliff(sourceFiles[index], sourceDir, tmx);

                if (isTargetDirSet) {
                    final String bundleSymbolicName = sourceFiles[index]
                            .getName().substring(
                                    0,
                                    sourceFiles[index].getName().length()
                                            - ".xlf".length());
                    final BlancoTmxSerializer serializer = new BlancoTmxSerializer();
                    serializer.serialize(tmx, new File(fInput.getTargetdir()
                            + "/" + bundleSymbolicName + ".tmx"));
                }
            }
        }

        if (isTargetFileSet) {
            final BlancoTmxSerializer serializer = new BlancoTmxSerializer();
            serializer.serialize(tmx, new File(fInput.getTargetfile()));
        }

        return 0;
    }

    private void processXliff(final File fileSource, final File sourceDir,
            final BlancoTmx tmx) 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 = xliffSource.getFileList().get(
                    indexFile);
            for (int indexTransUnit = 0; indexTransUnit < file.getBody()
                    .getTransUnitList().size(); indexTransUnit++) {
                final BlancoXliffTransUnit sourceUnit = file.getBody()
                        .getTransUnitList().get(indexTransUnit);
                processUnit(sourceUnit, tmx);
            }
        }
    }

    /**
     * transUnit を処理します。
     * 
     * @param sourceUnit
     *            入力となる transUnit。
     * @param tmx
     *            出力先 TMX。
     */
    private void processUnit(final BlancoXliffTransUnit sourceUnit,
            final BlancoTmx tmx) {
        if (sourceUnit.getTranslate() == false) {
            return;
        }

        if (BlancoStringUtil.null2Blank(sourceUnit.getSource()).length() == 0) {
            return;
        }
        if (sourceUnit.getTarget() == null
                || BlancoStringUtil.null2Blank(
                        sourceUnit.getTarget().getTarget()).length() == 0) {
            return;
        }

        if (fInput.getCheckalttranspleiades()) {
            // 無視条件の追加！
            // Pleiades と 翻訳が一致していることを確認する処理。
            boolean isEqualPleiades = false;
            for (int index = 0; index < sourceUnit.getAltTransList().size(); index++) {
                final BlancoXliffAltTrans altTrans = sourceUnit
                        .getAltTransList().get(index);
                if ("pleiades".equals(altTrans.getToolId()) == false) {
                    continue;
                }
                if (sourceUnit.getTarget().getTarget().equals(
                        altTrans.getTarget().getTarget())) {
                    isEqualPleiades = true;
                }
            }
            if (isEqualPleiades == false) {
                // Pleiadesと一致しないのでTMX化対象から除外します。
                return;
            }
        }

        final BlancoTmxTu tu = new BlancoTmxTu();
        tu.setTuid(sourceUnit.getId());
        tmx.getBody().getTuList().add(tu);

        {
            final BlancoTmxTuv tuv = new BlancoTmxTuv();
            tu.getTuvList().add(tuv);
            tuv.setLang("en_US");
            tuv.setSeg(sourceUnit.getSource());
        }
        {
            final BlancoTmxTuv tuv = new BlancoTmxTuv();
            tu.getTuvList().add(tuv);
            tuv.setLang("ja_JP");
            tuv.setSeg(sourceUnit.getTarget().getTarget());
        }
    }
}
