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

 Copyright (C) 2012 Thomas Cordonnier
               2014 Thomas Cordonnier
               2015 Thomas Cordonnier
               2016 Thomas Cordonnier
               Home page: http://www.omegat.org/
               Support center: http://groups.yahoo.com/group/OmegaT/

 This program 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 2 of the License, or
 (at your option) any later version.

 This program 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, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 **************************************************************************/
package org.omegat.gui.search;

import org.omegat.util.VarExpansion;
import org.omegat.util.OStrings;
import org.omegat.core.data.ProjectOptions;
import org.omegat.core.data.SourceTextEntry;
import org.omegat.core.search.SearchResultEntry;
import org.omegat.core.search.CrossSourceSearchResultEntry;
import org.omegat.core.search.PreTranslateSearchResultEntry;
import org.omegat.core.search.ReplaceMatch;
import org.omegat.core.search.SearchMatch;

import java.util.List;
import java.text.DateFormat;
import org.omegat.core.Core;

/**
 * This class is used to convert a SearchResultEntry to a text visible in the SearchWindow's EntryListPane
 * according to the given template containing variables.
 * 
 * @author Thomas CORDONNIER
 */
public class SearchVarExpansion extends VarExpansion<SearchResultEntry> {
    
    // ------------------------------ definitions -------------------
    
    public static final String VAR_PREAMBLE = "${preamble}";
    public static final String VAR_CREATION_ID = "${creationId}";
    public static final String VAR_CREATION_DATE = "${creationDate}";
    public static final String VAR_NOTE = "${note}";
    public static final String VAR_TARGET_REPLACED = "${replacedTarget}";
    public static final String VAR_PRE_TRANSLATION = "${preTranslation}";
    public static final String VAR_GROUP_COUNT = "${groupCount}";
    public static final String VAR_XSRC_SOURCES = "${allSources}";
    
    public static final String DEFAULT_TEMPLATE_PROJECT = VAR_PREAMBLE + "\n" 
            + VAR_SOURCE_TEXT + "\n"
            + VAR_TARGET_TEXT + "\n"
            + "\n-----------------------\n";    
    public static final String DEFAULT_TEMPLATE_DIRECTORY = VAR_PREAMBLE + "\n" 
            + VAR_SOURCE_TEXT + "\n"
            + "\n-----------------------\n";
    public static final String DEFAULT_TEMPLATE_REPLACE = VAR_PREAMBLE + "\n" 
            + VAR_TARGET_TEXT + "\n"
            + VAR_TARGET_REPLACED + "\n"
            + "\n-----------------------\n";
    public static final String DEFAULT_TEMPLATE_PRETRA = VAR_PREAMBLE + "\n" 
            + VAR_SOURCE_TEXT + "\n"
            + VAR_PRE_TRANSLATION + "\n"
            + "\n-----------------------\n";
    public static final String DEFAULT_TEMPLATE_PRETRA_SRC = 
              VAR_GROUP_COUNT + " " + org.omegat.util.OStrings.getString("SW_PRETRA_MATCH_GROUP_ENTRIES") + "\n"
            + VAR_XSRC_SOURCES + "\n"
            + "\n-----------------------\n";

    // ------------------------------ non-static part -------------------
    
    public SearchVarExpansion (ProjectOptions options, String template) {
        super(options, template);
    }

    @Override
    public String expandVariables (SearchResultEntry entry) {
        String localTemplate = this.template; // do not modify template directly, so that we can reuse for another change
        localTemplate = localTemplate.replace(VAR_PREAMBLE, entry.getPreamble());
        localTemplate = localTemplate.replace(VAR_CREATION_ID, entry.getAuthor() == null ? "" : entry.getAuthor());
        localTemplate = localTemplate.replace(VAR_CREATION_DATE, entry.getDate() == null ? "" : DateFormat.getInstance().format(entry.getDate()));
        localTemplate = localTemplate.replace(VAR_NOTE, entry.getNote() == null ? "" : entry.getNote());
        localTemplate = expandFileName(localTemplate, entry.getFileName(), 
            Core.getProject() == null ? "" : Core.getProject().getProjectProperties().getProjectRoot());
        localTemplate = localTemplate.replace("@{revisor}", entry.getRevisor() != null ? entry.getRevisor() : ""); 
        localTemplate = localTemplate.replace("@{revised}", entry.getRevisor() != null ? "revised" : ""); // boolean value of previous field: either "revised" or ""
        if (localTemplate.contains(VAR_GROUP_COUNT)) 
            try { localTemplate = localTemplate.replace(VAR_GROUP_COUNT, Integer.toString(((CrossSourceSearchResultEntry) entry).entries().size())); }
            catch (Exception e) { localTemplate = localTemplate.replace(VAR_GROUP_COUNT, entry.getMoreString()); }
        if (localTemplate.contains(VAR_XSRC_SOURCES)) 
            try { 
                CrossSourceSearchResultEntry xe = (CrossSourceSearchResultEntry) entry;
                List<SourceTextEntry> projEntries = Core.getProject().getAllEntries();
                StringBuffer buf = new StringBuffer(); 
                for (int idx: xe.entries()) 
                    buf.append("  ").append(idx).append(": ").append(projEntries.get(idx - 1).getSrcText()).append("\n");
                localTemplate = localTemplate.replace(VAR_XSRC_SOURCES, buf.toString()); 
            } catch (Exception e) { 
                localTemplate = localTemplate.replace(VAR_XSRC_SOURCES, OStrings.getString("SW_ERROR_VARIABLE").replace("{0}", VAR_XSRC_SOURCES)); 
            }
        return localTemplate;
    }
    
    private class ExpandTextVariable {
        private String varName, varValue;
        private int index; private List<SearchMatch> matches;
        
        public ExpandTextVariable(String varName, String varValue, int index, List<SearchMatch> matches) {
            this.varName = varName; this.varValue = varValue;
            this.index = index; this.matches = matches;
        }
            
        public String expandTextVariable(String localTemplate) {
            if (matches != null) for (SearchMatch match: matches) match.move(index);
            return localTemplate.replace(varName, varValue == null ? "" : varValue);
        }
        
        public void shift (ExpandTextVariable prev) {
            int diff = prev.varValue.length() - prev.varName.length();
            index += diff;
        }
    
    }
	
	public List<SearchMatch> replMatches;	// filled during call to apply
	public ReplaceDialog replaceDialog; // filled before call to apply
    
    public String apply (SearchResultEntry entry) {
        String localTemplate = this.template; // do not modify template directly, so that we can reuse for another change
        try {			
            localTemplate = expandVariables (entry);
            localTemplate = expandProperties(localTemplate, entry.getProperties());
            // Expand source and text -- do it in the reverse order they appear in template, to ensure indexes are good.
            int srcIndex = localTemplate.indexOf(VAR_SOURCE_TEXT), traIndex = localTemplate.indexOf(VAR_TARGET_TEXT);
			int replaceIndex = localTemplate.indexOf(VAR_TARGET_REPLACED), pretraIndex = localTemplate.indexOf(VAR_PRE_TRANSLATION);
            java.util.TreeMap<Integer,ExpandTextVariable> variables = new java.util.TreeMap<Integer,ExpandTextVariable>(); // sorted
            if (srcIndex >= 0) variables.put (srcIndex, new ExpandTextVariable(VAR_SOURCE_TEXT, entry.getSrcText(), srcIndex, entry.getSrcMatch()));
            if (traIndex >= 0) variables.put (traIndex, new ExpandTextVariable(VAR_TARGET_TEXT, entry.getTranslation(), traIndex, entry.getTargetMatch()));
            if (replaceIndex >= 0) 
				if (replaceDialog == null) {
					String replText = replaceDialog.buildReplacedString(entry.getTranslation(), entry.getTargetMatch());
					this.replMatches = replaceDialog.buildReplacedMatches(entry.getTranslation(), entry.getTargetMatch());
					variables.put (replaceIndex, new ExpandTextVariable(VAR_TARGET_REPLACED, replText, replaceIndex, replMatches));
				}
				else 
					variables.put (replaceIndex, new ExpandTextVariable(VAR_TARGET_REPLACED, 
						OStrings.getString("SW_ERROR_VARIABLE").replace("{0}", VAR_TARGET_REPLACED), 
						replaceIndex, java.util.Collections.singletonList(new SearchMatch(replaceIndex,5))));
			if (pretraIndex >= 0) 
				try {
					PreTranslateSearchResultEntry ptEntry = (PreTranslateSearchResultEntry) entry;
					String replText = ptEntry.getTranslationResult();
					this.replMatches = ptEntry.getHighlights();
					variables.put (pretraIndex, new ExpandTextVariable(VAR_PRE_TRANSLATION, replText, pretraIndex, replMatches));
				} catch (Exception e) {
					variables.put (pretraIndex, new ExpandTextVariable(VAR_TARGET_REPLACED, 
						OStrings.getString("SW_ERROR_VARIABLE").replace("{0}", VAR_PRE_TRANSLATION), 
						pretraIndex, java.util.Collections.singletonList(new SearchMatch(pretraIndex,5))));								
				}
            Integer[] keys = variables.navigableKeySet().toArray(new Integer[0]);
            for (int i = 0; i < keys.length; i++) {
                localTemplate = variables.get(keys[i]).expandTextVariable(localTemplate);
                for (int j = i + 1; j < keys.length; j++) variables.get(keys[j]).shift (variables.get(keys[i]));
            }
        } catch (Exception e) {
            e.printStackTrace(); // error in templating should not prevent from continuing expansion
        }
        return localTemplate;
    }
    
}
