package blanco.omegat.util.task;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.omegat.core.StringEntry;
import org.omegat.core.matching.FuzzyMatcherWrapper;
import org.omegat.core.matching.NearString;
import org.omegat.util.Language;
import org.omegat.util.TMXReader;

import blanco.commons.util.BlancoStringUtil;
import blanco.omegat.util.matching.OmegaTWrapper;
import blanco.omegat.util.task.valueobject.BlancoOmegatTranslateXliffProcessInput;
import blanco.xliff.BlancoXliffUtil;
import blanco.xliff.valueobject.BlancoXliff;
import blanco.xliff.valueobject.BlancoXliffAltTrans;
import blanco.xliff.valueobject.BlancoXliffFile;
import blanco.xliff.valueobject.BlancoXliffTarget;
import blanco.xliff.valueobject.BlancoXliffTransUnit;

public class BlancoOmegatTranslateXliffProcessImpl implements
        BlancoOmegatTranslateXliffProcess {
    private BlancoOmegatTranslateXliffProcessInput fInput = null;

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

        OmegaTWrapper.getCommandThread();

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

        // xliffdir, xlifffile が排他かつ必須で設定されていることをチェック。
        if (BlancoStringUtil.null2Blank(fInput.getXliffdir()).length() == 0) {
            if (BlancoStringUtil.null2Blank(fInput.getXlifffile()).length() == 0) {
                throw new IllegalArgumentException(
                        "xliffdir, xlifffileのいずれか一方は指定する必要があります。");
            }
            // xlifffile のケース
            final File file = new File(fInput.getXlifffile());
            if (file.exists() == false) {
                throw new IllegalArgumentException("指定された xlifffile["
                        + file.getAbsolutePath() + "]は存在しません。");
            }
            if (file.isFile() == false) {
                throw new IllegalArgumentException("指定された xlifffile["
                        + file.getAbsolutePath() + "]はファイルではありません。");
            }
        } else {
            if (BlancoStringUtil.null2Blank(fInput.getXlifffile()).length() > 0) {
                throw new IllegalArgumentException(
                        "xliffdir, xlifffileのいずれか一方のみ指定する必要があります。");
            }
            // xliffdir のケース
            final File dir = new File(fInput.getXliffdir());
            if (dir.exists() == false) {
                throw new IllegalArgumentException("指定された xliffdir["
                        + dir.getAbsolutePath() + "]は存在しません。");
            }
            if (dir.isDirectory() == false) {
                throw new IllegalArgumentException("指定された xliffdir["
                        + dir.getAbsolutePath() + "]はディレクトリではありません。");
            }
        }

        final List<StringEntry> tmxEntryList = loadTmx(dirTmx);
        System.out.println("TMエントリ数: " + tmxEntryList.size());
        if (tmxEntryList.size() == 0) {
            throw new IllegalArgumentException("TMが1件もないので処理続行できません。");
        }
        translate(tmxEntryList);

        return 0;
    }

    private List<StringEntry> loadTmx(final File dirTmx) throws IOException {
        final TMXReader reader = new TMXReader("UTF-8", new Language("en_US"),
                new Language("ja_JP"));

        final File[] fileTmxs = dirTmx.listFiles();
        if (fileTmxs == null) {
            return new ArrayList<StringEntry>();
        }
        for (int index = 0; index < fileTmxs.length; index++) {
            final File fileTmx = fileTmxs[index];
            if (fileTmx.isFile() == false) {
                continue;
            }

            reader.loadFile(fileTmx.getAbsolutePath(), false);
        }

        final int num = reader.numSegments();
        final ArrayList<StringEntry> tmxEntryList = new ArrayList<StringEntry>(
                num);

        for (int i = 0; i < num; i++) {
            String src = reader.getSourceSegment(i);
            String trans = reader.getTargetSegment(i);

            StringEntry se = new StringEntry(src);
            se.setTranslation(trans);
            tmxEntryList.add(se);
        }

        return tmxEntryList;
    }

    private void translate(final List<StringEntry> tmxEntryList)
            throws IOException {
        if (BlancoStringUtil.null2Blank(fInput.getXliffdir()).length() > 0) {
            final File dirXliff = new File(fInput.getXliffdir());
            final File[] xliffFiles = dirXliff.listFiles();
            if (xliffFiles == null) {
                return;
            }
            for (int index = 0; index < xliffFiles.length; index++) {
                if (xliffFiles[index].isFile() == false) {
                    continue;
                }
                if (xliffFiles[index].getName().endsWith(".xlf")) {
                    processXliff(xliffFiles[index], tmxEntryList);
                }
            }
        } else {
            final File fileXliff = new File(fInput.getXlifffile());
            processXliff(fileXliff, tmxEntryList);
        }
    }

    private void processXliff(final File fileTarget,
            final List<StringEntry> tmxEntryList) throws IOException {
        final File dirTmx = new File(fInput.getTmxdir());

        final FuzzyMatcherWrapper fuzzyMatcher = FuzzyMatcherWrapper
                .getInstance();

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

        int xliffCount = 0;
        for (int indexFile = 0; indexFile < xliffTarget.getFileList().size(); indexFile++) {
            if (fInput.getVerbose()) {
                System.out.println(bundleSymbolicName + ": file: " + indexFile
                        + " / " + xliffTarget.getFileList().size());
            }
            final BlancoXliffFile file = (BlancoXliffFile) xliffTarget
                    .getFileList().get(indexFile);
            for (int indexTransUnit = 0; indexTransUnit < file.getBody()
                    .getTransUnitList().size(); indexTransUnit++) {
                if (++xliffCount % 10 == 0) {
                    if (fInput.getVerbose()) {
                        System.out.println(bundleSymbolicName + ": "
                                + xliffCount);
                    }
                }

                final BlancoXliffTransUnit targetUnit = (BlancoXliffTransUnit) file
                        .getBody().getTransUnitList().get(indexTransUnit);
                if (targetUnit.getTranslate() == false) {
                    continue;
                }
                if (BlancoStringUtil.null2Blank(targetUnit.getSource())
                        .length() == 0) {
                    continue;
                }
                if (targetUnit.getTarget() != null
                        && BlancoStringUtil.null2Blank(
                                targetUnit.getTarget().getTarget()).length() > 0) {
                    if (fInput.getSkipiftargetexist()) {
                        continue;
                    }
                }

                // この trans-unit をマージします。
                final List<StringEntry> tuStrings = new ArrayList<StringEntry>();

                final StringEntry tuEntry = new StringEntry(targetUnit
                        .getSource());
                tuStrings.add(tuEntry);

                fuzzyMatcher.match(tuStrings, tmxEntryList, dirTmx.getName());

                if (tuEntry.getNearListTranslated().size() > 0) {
                    for (int indexMatch = 0; indexMatch < tuEntry
                            .getNearListTranslated().size(); indexMatch++) {
                        final NearString nearString = (NearString) tuEntry
                                .getNearListTranslated().get(indexMatch);

                        boolean isFound = false;
                        for (int index = 0; index < targetUnit
                                .getAltTransList().size(); index++) {
                            final BlancoXliffAltTrans altTrans = (BlancoXliffAltTrans) targetUnit
                                    .getAltTransList().get(index);
                            if (altTrans.getSource().equals(
                                    nearString.str.getSrcText())) {
                                isFound = true;
                            }
                        }
                        if (isFound == false) {
                            final BlancoXliffAltTrans altTrans = new BlancoXliffAltTrans();
                            targetUnit.getAltTransList().add(altTrans);
                            altTrans.setToolId(fInput.getToolId());
                            altTrans.setMatchQuality(String
                                    .valueOf(nearString.score)
                                    + "%");
                            altTrans.setOrigin(fInput.getOrigin());
                            altTrans.setSource(nearString.str.getSrcText());
                            final BlancoXliffTarget target = new BlancoXliffTarget();
                            altTrans.setTarget(target);
                            target.setTarget(nearString.str.getTranslation());
                        }
                    }
                }
            }
        }

        // マージ結果を保存します。
        switch (BlancoXliffUtil.saveXliffInstance(xliffTarget, fileTarget
                .getParentFile(), bundleSymbolicName)) {
        case 1:
            // 基本的に、こちらには入らない見込み。
            if (fInput.getVerbose()) {
                System.out.println("xliff: omegat: create: "
                        + bundleSymbolicName);
            }
            break;
        case 2:
            if (fInput.getVerbose()) {
                System.out.println("xliff: omegat: update: "
                        + bundleSymbolicName);
            }
            break;
        case 0:
            if (fInput.getVerbose()) {
                System.out.println("xliff: omegat: skip  : "
                        + bundleSymbolicName);
            }
            break;
        }

        System.out.println("XLIFFエントリ数: " + xliffCount);
    }
}
