/**************************************************************************
 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.external;

import org.omegat.core.Core;
import org.omegat.core.CoreEvents;
import org.omegat.core.events.IProjectEventListener;
import org.omegat.core.matching.external.ProjectMemory;
import org.omegat.core.matching.external.IEntryCursor;
import org.omegat.core.data.*;
import org.omegat.util.TMXProp;

import java.util.regex.*;
import java.util.*;
import java.io.*;

import javax.swing.SwingUtilities;

/**
 * This project provider ensures that your recent segments will not be lost 
 * if OmegaT is stopped in a way which did not enable saving.
 *
 * To do this, we write a CSV file, in append mode.
 * 
 * @author Thomas CORDONNIER
 */
public class NoDelaySaver implements ProjectMemory.IExternalProjectMemory {

    private PrintStream out;
    
    public NoDelaySaver (java.util.Properties propList) {
        CoreEvents.registerProjectChangeListener((IProjectEventListener.PROJECT_CHANGE_TYPE eventType) -> { 
            if (eventType == IProjectEventListener.PROJECT_CHANGE_TYPE.SAVE) {
                if (out != null) { 
                    out.close();
                    File outFile = new File(Core.getProject().getProjectProperties().getProjectInternal() + "project_save.tmp");
                    outFile.delete(); out = null;
                    try { out = new PrintStream(outFile, "UTF-8"); } catch (Exception e) {}
                }
            }
        });
    }
    
    public static final int COL_TYPE = 0; // deletion or addition
    public static final int COL_SRC = 1; 
    public static final int COL_KEY = 2; // default or contents of entry key
    public static final int COL_TRA = 3; // only for addition 
    public static final int COL_AUTHOR = 4; // only for addition 
    public static final int COL_CREATION_DATE = 5; // only for addition 
    public static final int COL_CHANGER = 6; // only for addition 
    public static final int COL_CHANGE_DATE = 7; // only for addition 
    public static final int COL_NOTE = 8; // only for addition 
    
    
    /** On first call, dumps the file; next time do nothing **/
    public IEntryCursor findChanges (long timeStamp) throws Exception {
        if (out != null) return new IEntryCursor.TMXEntriesCursor(Collections.emptyList());
        
        File outFile = new File(Core.getProject().getProjectProperties().getProjectInternal() + "project_save.tmp");
        System.err.println("Using " + outFile + " for immediate save");
        List<PrepareTMXEntry> res = new ArrayList<>();
        // Need to load completely the file because it will be erased immediately
        if (outFile.exists()) {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(outFile), "UTF-8"))) {
                String line; while ((line = reader.readLine()) != null) {
                    PrepareTMXEntry nEntry = new PrepareTMXEntry(); res.add(nEntry);
                    String[] fields = line.split("\t");
                    nEntry.source = fields[COL_SRC] = fields[COL_SRC].replaceAll("\\t","\t"); 
                    if (! "default".equals(fields[COL_KEY])) {
                        String[] key = fields[COL_KEY].replaceAll("\\t","\t").split("#");
                        nEntry.otherProperties = new ArrayList<>(5);
                        nEntry.otherProperties.add(new TMXProp(ProjectTMX.PROP_FILE, key[0].replaceAll("\\t","\t").replaceAll("\\SHARP","#")));
                        if (key[1].length() > 0) nEntry.otherProperties.add(new TMXProp(ProjectTMX.PROP_ID, key[1].replaceAll("\\t","\t").replaceAll("\\SHARP","#")));
                        if (key[2].length() > 0) nEntry.otherProperties.add(new TMXProp(ProjectTMX.PROP_PATH, key[2].replaceAll("\\t","\t").replaceAll("\\SHARP","#")));
                        if (key[3].length() > 0) nEntry.otherProperties.add(new TMXProp(ProjectTMX.PROP_PREV, key[3].replaceAll("\\t","\t").replaceAll("\\SHARP","#")));
                        if (key[4].length() > 0) nEntry.otherProperties.add(new TMXProp(ProjectTMX.PROP_NEXT, key[4].replaceAll("\\t","\t").replaceAll("\\SHARP","#")));
                    }
                    if ("-".equals(fields[COL_TYPE])) nEntry.translation = null;
                    else {
                        nEntry.translation = fields[COL_TRA] = fields[COL_TRA].replaceAll("\\t","\t");
                        nEntry.changer = fields[COL_CHANGER]; nEntry.changeDate = Long.parseLong(fields[COL_CHANGE_DATE]);
                        nEntry.creator = fields[COL_AUTHOR]; nEntry.creationDate = Long.parseLong(fields[COL_CREATION_DATE]);
                        if (fields.length >= 9) nEntry.note = fields[COL_NOTE].replaceAll("\\t","\t");                        
                    }
                }
            }
            outFile.delete();
        }
        out = new PrintStream(outFile, "UTF-8"); return new IEntryCursor.TMXEntriesCursor(res);
    }

    /** 
     * Also writes to the file 
     *
     * This is a CSV file with following columns:
     * [COL_TYPE=0] - for deletion and + for addition
     * [COL_SRC=1] source
     * [COL_KEY=2] either 'default' or the entry key as '#'-separated values
     * Next columns only in case of addition
     * [COL_TRA=3] translation
     * [4] author
     * [5] creation date
     * [6] changer
     * [7] change date
     * [8] note
     */
    public void registerTranslation(SourceTextEntry ste, TMXEntry te, boolean isDefault) throws IOException {
        if (out == null) return; 
        StringBuffer buf;
        if (te == null) buf = new StringBuffer("-\t");  // removes
        else buf = new StringBuffer("+\t");
        buf.append(te.source.replaceAll("\t","\\t")).append("\t");
        if (isDefault) buf.append("default").append("\t"); 
        else {
            buf.append(ste.getKey().file == null ? "" : ste.getKey().file.replaceAll("\t","\\t").replaceAll("#","\\SHARP")).append("#");
            buf.append(ste.getKey().id == null ?  "" : ste.getKey().id.replaceAll("\t","\\t").replaceAll("#","\\SHARP")).append("#");
            buf.append(ste.getKey().path == null ? "" : ste.getKey().path.replaceAll("\t","\\t").replaceAll("#","\\SHARP")).append("#");
            buf.append(ste.getKey().prev == null ? "" : ste.getKey().prev.replaceAll("\t","\\t").replaceAll("#","\\SHARP")).append("#");
            buf.append(ste.getKey().next == null ? "" : ste.getKey().next.replaceAll("\t","\\t").replaceAll("#","\\SHARP")).append("#");
            buf.append("\t");
        }
        if (te != null) {
            buf.append(te.translation.replaceAll("\t","\\t")).append("\t");
            buf.append(te.creator).append("\t");
            buf.append(te.creationDate).append("\t");
            buf.append(te.changer).append("\t");
            buf.append(te.changeDate).append("\t");
            if (te.note != null) buf.append(te.note.replaceAll("\t","\\t")).append("\t");
        }
        out.println(buf); out.flush();
    }
}