/* :name=Calculate SDLXLIFF differences		:description=Generate a sdlxliff with track changes
 * 
 * Open current file
 *
 * @author  Thomas Cordonnier
 * @date    2018-02-22
 * @version 0.2
 */

import static javax.swing.JOptionPane.*

import org.omegat.core.Core
import org.omegat.core.matching.DiffDriver
import org.omegat.filters2.FilterContext
import org.omegat.filters2.master.FilterMaster
import org.omegat.gui.main.ProjectUICommands
import org.omegat.util.Preferences
import org.omegat.util.StaticUtils

//import bmsi.util.Diff

def srcFile = project.projectProperties.sourceRoot + editor.currentFile
if (! srcFile) {
    showMessageDialog null, 'Can only be used with opened project', 'Error', ERROR_MESSAGE
    return
}

def makedirRecursive(File file) { 
    if (! file.exists()) { 
        if (! file.parentFile.exists()) makedirRecursive(file.parentFile);
        file.mkdir();
    }
}

def author =  Preferences.getPreferenceDefault(Preferences.TEAM_AUTHOR, System.getProperty("user.name"))
def currentDate = new Date().format("MM/dd/yyyy HH:mm:ss")
def scriptDate = new Date(new File(Preferences.getPreference(Preferences.SCRIPTS_DIRECTORY) + "/calc-sdlxliff-diff.groovy").lastModified()).format("MM/dd/yyyy HH:mm:ss")

try {
  Thread.start {
    //ProjectUICommands.projectPatternCompile(StaticUtils.escapeNonRegex(editor.currentFile))
    project.compileProject(StaticUtils.escapeNonRegex(editor.currentFile))
    console.println "compile proj ok"
        
    String oriText = new File(srcFile).getText('UTF-8')
    String newText = new File(project.projectProperties.targetRoot + editor.currentFile).getText('UTF-8')
    String diffText = newText
    
    if (! (diffText =~ /<doc-info/)) 
        diffText = diffText.replaceFirst('<file', '<doc-info xmlns="http://sdl.com/FileTypes/SdlXliff/1.0"><rev-defs></rev-defs></doc-info><file')
    else if (! (diffText =~ /<rev-defs/)) 
        diffText = diffText.replaceFirst('</doc-info>', '<rev-defs></rev-defs></doc-info>')
    
    oriText.eachMatch( /<trans-unit id="([0-9A-Fa-f\-]{9,36})">(.+?)<\/trans-unit>/ ) {
        def id = it[1]
        def contents = it[2]
        
        console.print "Translation unit " + it[1] + ": "
        
        def oriTarget
        if ((m = contents =~ /<target[^>]*?>(.+?)<\/target>/)) oriTarget = m.group(1)
        
        def newTarget
        if ((m = newText =~ /(?s)<trans-unit id="${id}">(.+?)<\/trans-unit>/)) newTarget = m.group(1)
        if (newTarget == null) newTarget = "";
        if ((m = newTarget =~ /<target[^>]*?>(.+?)<\/target>/)) newTarget = m.group(1)
        oriTarget = oriTarget.replaceAll(/\&gt;/, '>').replaceAll(/\&quot;/, '"')
        newTarget = newTarget.replaceAll(/\&gt;/, '>').replaceAll(/\&quot;/, '"')
        oriTarget = oriTarget.replaceAll(/<(\w+x)\s*(.+?)><\/\1>/, "<${1} ${2} />")
        newTarget = newTarget.replaceAll(/<(\w+x)\s*(.+?)><\/\1>/, "<${1} ${2} />")		
        oriTarget = oriTarget.replaceAll(/(<mrk mtype="seg" mid="\d+")\/>/) { it[1] + "></mrk>" }
        newTarget = newTarget.replaceAll(/(<mrk mtype="seg" mid="\d+")\/>/) { it[1] + "></mrk>" }
	
        if (oriTarget.equals(newTarget)) { console.println "Same target"; return }
    
        StringBuilder rawText = new StringBuilder()
        def r = DiffDriver.render(oriTarget, newTarget, true)
        for ( run in r.formatting)
            if (run.type == DiffDriver.Type.NOCHANGE) rawText.append (r.getRunText(run));
            else {
                def toStr = r.getRunText(run)

                // Check whenever tags are correctly balanced
                java.util.Stack<String> stack = new java.util.Stack<String>()
                try {
                    toStr.eachMatch( /<(.+?)>/ ) {
                        if (! it[1].endsWith("/")) // empty tags can be ignored
                            if ((m = (it[1] =~ /^([\w\-]+)(\s|>)/))) stack.push(m.group()); // open tag
                            else if (it[1].startsWith("/")) {	// closing tag
								String tag = stack.pop(); if (tag.contains(" ")) tag = tag.substring(0, tag.indexOf(" "));
								if (! it[1].substring(1).trim().equals(tag)) throw new Exception("Wrong closing tag");
							}
                    }
                    if (! stack.empty()) // close all tags, they will be reopened later
						for (int i = stack.size(); i >= 0; i--)	{	// do not pop because stack will be re-used later
							String tag = stack.pop(); if (tag.contains(" ")) tag = tag.substring(0, tag.indexOf(" "));
							toStr += "</" + tag + ">";
						}
                } catch (Exception e) {
                    // Not correctly balanced. Remove all tags
                    toStr = toStr.replaceAll (/<(.+?)>/, ''); stack.clear(); 
                }				
				
				if (toStr.length() > 0) 
                    if (rawText.lastIndexOf(">") > rawText.lastIndexOf("<")) {
                        // Generate a difference
                        def uuid = java.util.UUID.randomUUID()
                        diffText = diffText.replaceFirst('</rev-defs>', 
                            "<rev-def id=\"${uuid}\" "
                            + ((run.type == DiffDriver.Type.DELETE) ? " type=\"Delete\"" : "")
                            + " author=\"${author}\" date=\"${currentDate}\"/>"
                            + '</rev-defs>')
                        rawText.append("<mrk mtype=\"x-sdl-" + (run.type == DiffDriver.Type.DELETE ? "deleted":"added") + "\" sdl:revid=\"${uuid}\">");
                        rawText.append(toStr); 
                        rawText.append("</mrk>");
						if (! stack.empty())
							for (int i = 0; i < stack.size(); i++) rawText.append("<" + stack.get(i) + ">");	// this time in normal order!!!
                    }
                    else if (run.type == DiffDriver.Type.DELETE) rawText.append (toStr) // show original, not new
				
            }
        console.println ("Difference : " + rawText)

        String revisedText = rawText.toString().replaceAll('<<mrk.+?</mrk>', '<')
    
        diffText = diffText.replaceFirst(/<trans-unit id="${id}">(.+?)<target>(.+?)<\/target>(.+?)<\/trans-unit>/) { m ->
            "<trans-unit id=\"${id}\">" + m[1] + "<target>" + revisedText + "</target>" + m[3] + "</trans-unit>"				
        }
    }
    
    def exportfile = project.projectProperties.projectRoot.toString() + "\\sdlxliff-compare\\" + editor.currentFile
    makedirRecursive (new File(exportfile).parentFile)
    new File (exportfile).withWriter('UTF-8') { out -> 
		out << diffText 
		out << "<!-- calc-sdlxliff-diff.groovy " << scriptDate << " -->"
	}
 }


} catch (Exception e) {
    e.printStackTrace();
}