/**************************************************************************
 OmegaT - Computer Assisted Translation (CAT) tool 
          with fuzzy matching, translation memory, keyword search, 
          glossaries, and translation leveraging into updated projects.

 Copyright (C) 2010 Alex Buloichik
               2012 Thomas CORDONNIER
               2013 Aaron Madlon-Kay, Thomas Cordonnier
               2014 Alex Buloichik
               2015-2019 Thomas Cordonnier
               Home page: http://www.omegat.org/
               Support center: http://groups.yahoo.com/group/OmegaT/

 This file is part of OmegaT.

 OmegaT is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 OmegaT is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 **************************************************************************/
package org.omegat.core.data;

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

import org.omegat.core.Core;
import org.omegat.core.matching.external.IBrowsableMemory;
import org.omegat.core.matching.external.IEntryCursor;
import org.omegat.core.search.TextExpression;
import org.omegat.core.segmentation.Segmenter;
import org.omegat.util.FileUtil;
import org.omegat.util.Language;
import org.omegat.util.Preferences;
import org.omegat.util.StringUtil;
import org.omegat.util.TMXReader2;
import org.omegat.util.TMXProp;

/**
 * Class for store data from TMX from /tm/ folder. They are used only for fuzzy matches.
 * 
 * @author Alex Buloichik (alex73mail@gmail.com)
 * @author Thomas CORDONNIER
 * @author Aaron Madlon-Kay
 */
public class ExternalTMX implements IBrowsableMemory {

    private final String name;

    private final List<PrepareTMXEntry> entries;

    public ExternalTMX(final ProjectProperties props, final File file, final boolean extTmxLevel2,
            final boolean useSlash) throws Exception {
        this (props.isSentenceSegmentingEnabled(), props.getSourceLanguage(), props.getTargetLanguage(),
            file, extTmxLevel2, useSlash);
    }
    
    public ExternalTMX(final boolean isSentenceSegmentingEnabled, final Language srcLang, final Language traLang,
            final File file, final boolean extTmxLevel2, final boolean useSlash) throws Exception {		
        String path = file.getPath();
        if ((path.charAt(0) == '/') /* unix */ || (path.charAt(1) == ':') /* windows */) {
            String base = Core.getProject().getProjectProperties().getTMRoot();
            if (path.startsWith(base)) path = path.substring(base.length());
        }
        this.name = path;
        entries = new ArrayList<PrepareTMXEntry>();

        TMXReader2.LoadCallback loader = new TMXReader2.LoadCallback() {
            final String prefForeign = Preferences.getPreferenceDefault(Preferences.EXT_TMX_KEEP_FOREIGN_MATCH, "30 false");
            
            public boolean onEntry(TMXReader2.ParsedTu tu, TMXReader2.ParsedTuv tuvSource,
                    TMXReader2.ParsedTuv tuvTarget, boolean isParagraphSegtype) {
                if (tuvSource == null) return false;

                if (tuvTarget != null) addTuv(tu, tuvSource, tuvTarget, false, isParagraphSegtype); // add only target Tuv
                else if (! prefForeign.endsWith("false")) {
                    if (prefForeign.contains(";")) {
                        String[] langs = prefForeign.split(";");
                        for (int i = 0; i < langs.length - 1; i++) {
                            String[] parts = langs[i].split(" ");
                            TMXReader2.ParsedTuv tuv1 = tu.getTuvByLang(parts[0]);
                            if (tuv1 != null) { 
                                addTuv(tu, tuvSource, tuv1, true, isParagraphSegtype); 
                                if (! langs[i].contains("with-cascade")) return true; 
                            }
                        }
                    }
                    // add all non-source Tuv
                    for (int i = 0; i < tu.tuvs.size(); i++) 
                        if (tu.tuvs.get(i) != tuvSource) addTuv(tu, tuvSource, tu.tuvs.get(i), true, isParagraphSegtype);
                    
                }
                return true;
            }

            private void addTuv(TMXReader2.ParsedTu tu, TMXReader2.ParsedTuv tuvSource,
                    TMXReader2.ParsedTuv tuvTarget, boolean isForeign, boolean isParagraphSegtype) {
                String changer = StringUtil.nvl(tuvTarget.changeid, tuvTarget.creationid, tu.changeid,
                        tu.creationid);
                String creator = StringUtil.nvl(tuvTarget.creationid, tu.creationid);
                long changed = StringUtil.nvlLong(tuvTarget.changedate, tuvTarget.creationdate, tu.changedate,
                        tu.creationdate);
                long created = StringUtil.nvlLong(tuvTarget.creationdate, tu.creationdate);

                List<String> sources = new ArrayList<String>();
                List<String> targets = new ArrayList<String>();
                Core.getSegmenter().segmentEntries(isSentenceSegmentingEnabled && isParagraphSegtype,
                        srcLang, tuvSource.text, traLang, tuvTarget.text,
                        sources, targets);

                for (int i = 0; i < sources.size(); i++) {
                    PrepareTMXEntry te = new PrepareTMXEntry();
                    te.source = sources.get(i);
                    te.translation = targets.get(i);
                    te.changer = changer;
                    te.changeDate = changed;
                    te.creator = creator;
                    te.creationDate = created;
                    te.note = tu.note;
                    if (isForeign) {
                        if ((te.otherProperties = tu.props) == null) te.otherProperties = new ArrayList<TMXProp>();
                        te.otherProperties.add(new TMXProp("x-target-lang", tuvTarget.lang));
                    }
                    else te.otherProperties = tu.props;
                    entries.add(te);
                }
            }
        };

        TMXReader2 reader = new TMXReader2();
        reader.readTMX(file, srcLang, traLang,
                isSentenceSegmentingEnabled, false, extTmxLevel2, useSlash, loader);
    }

    public String getMemoryName() {
        return name;
    }

    public String getProviderName() {
        return "tmx file";
    }

    public List<PrepareTMXEntry> findMatchingTranslations (Language sLang, Language tLang, String text, int minScore, int maxCount) {
        return entries; // filtering will be done by matches finder
    }

    public IEntryCursor.TMXEntriesCursor browseAllEntries() {
        return new IEntryCursor.TMXEntriesCursor(entries);
    }
    
    public Iterable<PrepareTMXEntry> search(int numberOfResults, TextExpression searchSource, TextExpression searchTarget, TextExpression searchNotes, boolean andSearch,
        TextExpression author, // NOTE: does not take DGT-specific "translator" fields, because they would be meaningless for external providers
        long dateAfter, long dateBefore) {
        return entries;
    }	
    	
    /**
     * Check if TMX is in specified path.
     */
    public static boolean isInPath(File path, File tmxFile) {
        try {
            FileUtil.computeRelativePath(path, tmxFile);
            return true;
        } catch (IOException ex) {
            return false;
        }
    }
}
