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

 Copyright (C) 2020 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.matching;

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import org.omegat.core.data.EntryKey;
import org.omegat.core.data.IProject;
import org.omegat.core.events.IStopped;
import org.omegat.core.matching.external.IExternalMemory;
import org.omegat.tokenizer.ITokenizer;
import org.omegat.util.OConsts;
import org.omegat.util.TMXProp;
import org.omegat.util.Preferences;

/**
 * Matcher which builds an array 
 *
 * @author Thomas Cordonnier
 */
public class FindMatchesArray extends FindMatchesKeep {
    /** Result list. */
    private LinkedList<NearString> result = new LinkedList<NearString>();
    private final int maxCount;

    public FindMatchesArray(ITokenizer sourceTokenizer, final IExternalMemory[] externalMemories, String memoryPath, int maxCount, boolean allowSeparateSegmentMatch, boolean searchExactlyTheSame) {
        super(sourceTokenizer, externalMemories, memoryPath, allowSeparateSegmentMatch, searchExactlyTheSame); 
        this.maxCount = maxCount;
    }
    
    /**
     * @param searchExactlyTheSame
     *            allows to search similarities with the same text as source segment. This mode used only for
     *            separate sentence match in paragraph project, i.e. where source is just part of current
     *            source.
     */
    public FindMatchesArray(ITokenizer sourceTokenizer, final IExternalMemory[] externalMemories, int maxCount, boolean allowSeparateSegmentMatch, boolean searchExactlyTheSame) {
        super(sourceTokenizer, externalMemories, allowSeparateSegmentMatch, searchExactlyTheSame);
        this.maxCount = maxCount;
    }

    @Override public final int maxCount() { return this.maxCount; }    
    @Override protected NearString lastKeptResult() { return result.isEmpty() ? null : result.getLast(); }
        
    private int remaining;
    
    public List<NearString> search(final IProject project, final String searchText,
            final boolean requiresTranslation, final boolean fillSimilarityData, final IStopped stop)
            throws StoppedException {
        result.clear(); remaining = maxCount;
        doSearch(project, searchText, requiresTranslation, fillSimilarityData, stop);
        
        if (fillSimilarityData)
            // fill similarityStem data only for result
            for (NearString near : result) buildSimilarityData(near);
        
        return result;
    }
    
    /**
     * Compare one entry with original entry.
     * 
     * @param candEntry
     *            entry to compare
     */
    protected void doInsertion(final NearString added) {
       /**
        * Add near string into result list. Near strings sorted by selected key
        */
        if (result.isEmpty()) {
            result.add(added);
            return;
        }
        // find position for new data
        for (ListIterator<NearString> I = result.listIterator(); I.hasNext(); ) {
            NearString st = I.next();
            if (Preferences.isPreferenceDefault(Preferences.EXT_TMX_MERGE, true) && added.source.equals(st.source)
                    && (added.translation == null && st.translation == null || added.translation != null
                            && added.translation.equals(st.translation))) {
                // Consolidate identical matches from different sources into a single NearString with
                // multiple project entries.
                I.set(NearString.merge(st, added));
                return;
            }
            
            if (st.composedScoreForSorting(this.sortKey) < added.composedScoreForSorting(this.sortKey)) { 
                I.previous(); // insert before st
                I.add(added);
                if (--remaining < 0) result.removeLast();
                return;
            }
        }
    }
}
