package org.omegat.core.matching;

import java.util.List;

import org.omegat.core.StringData;
import org.omegat.core.StringEntry;
import org.omegat.util.OConsts;
import org.omegat.util.Token;

import blanco.omegat.util.matching.OmegaTWrapper;

public class FuzzyMatcherWrapper extends FuzzyMatcher {

    private static FuzzyMatcherWrapper fuzzyMatcherWrapper = new FuzzyMatcherWrapper();

    private FuzzyMatcherWrapper() {
        super(OmegaTWrapper.getCommandThread().getTransFrame(), OmegaTWrapper
                .getCommandThread());
    }

    public static FuzzyMatcherWrapper getInstance() {
        return fuzzyMatcherWrapper;
    }

    public void match(List tuStrings, List tmStrings, String tmxname) {

        int tmtotal = tmStrings.size();
        int total = tuStrings.size();

        for (int i = 0; i < tmtotal; i++) {

            StringEntry strEntry = (StringEntry) tmStrings.get(i);
            List strTokens = strEntry.getSrcTokenList();
            int strTokensSize = strTokens.size();
            if (strTokensSize == 0) // HP: maybe also test on
                // strTokensComplete.size(), if
                // strTokensSize is 0
                continue; // HP: perhaps that would result in better
            // number/non-word matching too
            List strTokensAll = strEntry.getSrcTokenListAll(); // HP: includes
            // non-word
            // tokens

            for (int j = 0; j < total; j++) {
                StringEntry candEntry = (StringEntry) tuStrings.get(j);
                List candTokens = candEntry.getSrcTokenList();
                int candTokensSize = candTokens.size();
                if (candTokensSize == 0)
                    continue;

                int ld = LevenshteinDistance.compute(strTokens, candTokens);
                int similarity = (100 * (Math
                        .max(strTokensSize, candTokensSize) - ld))
                        / Math.max(strTokensSize, candTokensSize);

                // System.out.println("similarity:" + similarity);
                // System.out.println("FUZZY_MATCH_THRESHOLD:"
                // + OConsts.FUZZY_MATCH_THRESHOLD);

                if (similarity < OConsts.FUZZY_MATCH_THRESHOLD)
                    continue;

                // determine Levenshtein distance/adjusted similarity across the
                // complete
                // list of tokens, including numbers, tags, and other non-word
                // tokens
                // fix for bug 1449988
                List candTokensAll = candEntry.getSrcTokenListAll();
                int ldAll = LevenshteinDistance.compute(strTokensAll,
                        candTokensAll);
                int simAdjusted = (100 * (Math.max(strTokensAll.size(),
                        candTokensAll.size()) - ldAll))
                        / Math.max(strTokensAll.size(), candTokensAll.size());
                // end fix 1449988

                // byte[] similarityData = buildSimilarityData(candTokens,
                // strTokens);
                byte[] similarityData = buildSimilarityData(candTokensAll,
                        strTokensAll); // fix for bug 1586397
                candEntry.addNearString(strEntry, similarity, simAdjusted,
                        similarityData, tmxname);
            }
        }

    }

    private byte[] buildSimilarityData(List sourceTokens, List matchTokens) {
        int len = matchTokens.size();
        byte[] result = new byte[len];

        boolean leftfound = true;
        for (int i = 0; i < len; i++) {
            result[i] = 0;

            Token righttoken = null;
            if (i + 1 < len)
                righttoken = (Token) matchTokens.get(i + 1);
            boolean rightfound = (i + 1 == len)
                    || sourceTokens.contains(righttoken);

            Token token;
            token = (Token) matchTokens.get(i);
            boolean found = sourceTokens.contains(token);

            if (found && (!leftfound || !rightfound))
                result[i] = StringData.PAIR;
            else if (!found)
                result[i] = StringData.UNIQ;

            leftfound = found;
        }
        return result;

    }

}
