<scriptlet>
<implements type="Automation" id="dispatcher">
  <property name="PluginEvent">
    <get/>
  </property>
  <property name="PluginDescription">
    <get/>
  </property>
  <property name="PluginFileFilters">
    <get/>
  </property>
  <property name="PluginIsAutomatic">
    <get/>
  </property>
  <property name="PluginExtendedProperties">
    <get/>
  </property>
  <method name="PluginOnEvent"/>
  <method name="PrediffBufferW"/>
  <method name="ShowSettingsDialog"/>
</implements>

<script language="VBS">

'/////////////////////////////////////////////////////////////////////////////
'    This is a plugin for WinMerge.
'    It does almost the same thing as Substitution filters.
'    Copyright (C) 2018-2023 Takashi Sawanaka
'
'    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., 675 Mass Ave, Cambridge, MA 02139, USA.
'

Option Explicit

Const RegKeyPath = "Plugins\PrediffLineFilter.sct/"
Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")
Dim wsh: Set wsh = CreateObject("WScript.Shell")
Dim mergeApp

Function regRead(Key, DefaultValue)
	regRead = DefaultValue
	On Error Resume Next
	If IsEmpty(mergeApp) Then
		regRead = wsh.RegRead("HKCU\Software\Thingamahoochie\WinMerge\" & Replace(Key, "/", "\"))
	Else
		regRead = mergeApp.GetOption(Key, DefaultValue)
	End If
End Function

Sub regWrite(Key, Value, TypeNm)
	On Error Resume Next
	If IsEmpty(mergeApp) Then
		wsh.RegWrite "HKCU\Software\Thingamahoochie\WinMerge\" &  Replace(Key, "/", "\"), Value, TypeNm
	Else
		mergeApp.SaveOption Key, Value
	End If
End Sub

Function get_PluginEvent()
  get_PluginEvent = "BUFFER_PREDIFF"
End Function

Function get_PluginDescription()
  get_PluginDescription = "Prediff Line Filter"
End Function

Function get_PluginFileFilters()
  get_PluginFileFilters = "\.nomatch(\..*)?$"
End Function

Function get_PluginIsAutomatic()
  get_PluginIsAutomatic = True
End Function

Function get_PluginExtendedProperties()
  get_PluginExtendedProperties = "MenuCaption=Apply Prediff Substitution Filters"
End Function

Sub PluginOnEvent(eventType, obj)
  Set mergeApp = obj
End Sub

Function SafeUBound(ary)
  On Error Resume Next
  SafeUBound = -1
  SafeUBound = UBound(ary)
End Function

Function PrediffBufferW(pText, pSize, pbChanged)
  On Error Resume Next
  Dim re, pattern, replaceText, ignoreCase
  Dim count, i, j
  Dim lines
  Set re = New RegExp
  If pText = "" Then
    pbChanged = False
    PrediffBufferW = True
    Exit Function
  End If
  lines = Split(pText, vbLf)
  count = regRead(RegKeyPath & "Count", 0)
  For i = 1 To count
    If regRead(RegKeyPath & "Enabled" & i, True) Then
      If regRead(RegKeyPath & "UseRegExp" & i, True) Then
        re.Global = True
        re.Pattern = regRead(RegKeyPath & "Pattern" & i, "")
        re.IgnoreCase = regRead(RegKeyPath & "IgnoreCase" & i, False)
        replaceText = regRead(RegKeyPath & "ReplaceText" & i, "")
        For j = 0 To SafeUBound(lines)
          lines(j) = re.Replace(lines(j), replaceText)
        Next
      Else
        pattern = regRead(RegKeyPath & "Pattern" & i, "")
        replaceText = regRead(RegKeyPath & "ReplaceText" & i, "")
        ignoreCase = regRead(RegKeyPath & "IgnoreCase" & i, False)
        For j = 0 To SafeUBound(lines)
          If ignoreCase Then
            lines(j) = Replace(lines(j), pattern, replaceText, 1, -1, vbTextCompare)
          Else
            lines(j) = Replace(lines(j), pattern, replaceText, 1, -1, vbBinaryCompare)
          End If
        Next
      End If
    End If
  Next
  pText = Join(lines, vbLf)
  pSize = Len(pText)
  pbChanged = True
  PrediffBufferW = True
End Function

Function Translate(text)
  Dim re: Set re = CreateObject("VBScript.RegExp")
  re.Pattern = "\${([^}]+)}"
  re.Global = True
  Translate = text
  Dim match
  Dim matches:Set matches = re.Execute(text)
  if IsEmpty(mergeApp) Then
    For Each match in matches
      Translate = Replace(Translate, match.Value, match.Submatches(0))
    Next
  Else
    For Each match in matches
      Translate = Replace(Translate, match.Value, mergeApp.Translate(match.Submatches(0)))
    Next
  End If
End Function

Function ShowSettingsDialog()
  Dim tname: tname = fso.BuildPath(fso.GetSpecialFolder(2), fso.GetTempName() & ".hta")
  Dim jsonfile: jsonfile = fso.BuildPath(fso.GetSpecialFolder(2), fso.GetTempName() & ".json")
  Dim tfile: Set tfile = fso.CreateTextFile(tname, True, True)
  Dim mshta
  tfile.Write Translate(getResource("dialog1"))
  tfile.Close
  exportSettingsToJSONFile jsonfile
  mshta = wsh.ExpandEnvironmentStrings("%SystemRoot%\System32\mshta.exe")
  If Not fso.FileExists(mshta) Then
    mshta = wsh.ExpandEnvironmentStrings("%SystemRoot%\SysWOW64\mshta.exe")
  End If
  Run wsh, """" & mshta & """ """ & tname & """  """ & jsonfile  & """"
  importSettingsFromJSONFile jsonfile
  fso.DeleteFile tname
  fso.DeleteFile jsonfile
End Function

Sub Run(sh, cmd)
  sh.Run cmd, 1, True
End Sub

</script>

<script language="JScript">

var REGKEY_PATH = "Plugins\\PrediffLineFilter.sct/";

function exportSettingsToJSONFile(filepath)
{
	var key_defvalues = {"Count" : 0};
	var count = regRead(REGKEY_PATH + "Count", 0);
	for (var i = 1; i < count + 1; i++) {
        	key_defvalues["Enabled" + i] = true;
		key_defvalues["IgnoreCase" + i] = false;
		key_defvalues["UseRegExp" + i] = false;
		key_defvalues["Pattern" + i] = "";
		key_defvalues["ReplaceText" + i] = "";
	}
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	var ts = fso.OpenTextFile(filepath, 2, true, -1);
	var json = "{";
	for (var key in key_defvalues) {
		var val = regRead(REGKEY_PATH + key, key_defvalues[key]);
		json += '"' + (REGKEY_PATH + key).replace(/\\/g, "\\\\") + '" : ' + ((typeof val == "string") ? ('"' + val.replace(/[\\"']/g, '\\$&') + '"') : val) + ',';
	}
	json = json.substr(0, json.length - 1) + "}";
	ts.WriteLine(json);
	ts.Close();
}

function importSettingsFromJSONFile(filepath)
{
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	var ts = fso.OpenTextFile(filepath, 1, true, -1);
	var json = ts.ReadAll();
	var settings = eval("(" + json + ")");
	ts.Close();
	for (var key in settings) {
		regWrite(key, settings[key], (typeof settings[key] === "string") ? "REG_SZ" : "REG_DWORD");
	}
}

</script>

<resource id="dialog1">
<![CDATA[
<!DOCTYPE html>
<html>
  <head>
    <HTA:APPLICATION ID="objHTA">
    <title>${PrediffLineFilter.sct WinMerge Plugin Options}</title>
    <meta content="text/html" charset="UTF-16">
    <style>
    body { background-color: #f2f2f2; font-family: Arial, sans-serif; }
    .container { margin: 2em; }
    ul { list-style-type: none; margin: 0; padding: 0; }
    li ul li { padding-left: 2em }
    .btn-container-top { margin-bottom: 0.5em; text-align: left; }
    .btn-container { margin-top: 1.5em; text-align: right; }
    input[type="button"] { border: none; padding: 0.6em 2em; height: 2.5em; text-align: center; }
    .btn { color: #fff; background-color: #0c5; }
    .btn:hover { background-color: #0b4; }
    .btn-ok { color: #fff; background-color: #05c; }
    .btn-ok:hover { background-color: #04b; }
    .btn-cancel { color: #333; background-color: #ddd; }
    .btn-cancel:hover { background-color: #ccc; }
    #table1 { border-collapse: collapse; border: 1px solid #ccc; }
    </style>
    <script type="text/javascript">
      var REGKEY_PATH = "Plugins\\PrediffLineFilter.sct/";
      var jsonFilePath;
      var settings;

      function jsonStringify(obj) {
        if (obj === null) {
          return "null";
        }
        if (typeof obj === "undefined") {
          return undefined;
        }
        if (typeof obj === "number" || typeof obj === "boolean") {
          return obj.toString();
        }
        if (typeof obj === "string") {
          return '"' + escapeString(obj) + '"';
        }
        if (typeof obj === "object") {
          var pairs = [];
          for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
              pairs.push('"' + escapeString(key) + '":' + jsonStringify(obj[key]));
            }
          }
          return "{" + pairs.join(",") + "}";
        }
      }

      function escapeString(str) {
        return str.replace(/[\\"']/g, '\\$&');
      }

      function regRead(key, defaultValue) {
        return settings.hasOwnProperty(key) ? settings[key] : defaultValue;
      }

      function regWrite(key, value, type) {
        settings[key] = (type === "REG_DWORD") ? Number(value) : String(value);
      }

      function loadSettingsFromJSONFile(filepath) {
        var fso = new ActiveXObject("Scripting.FileSystemObject");
        var ts = fso.OpenTextFile(jsonFilePath, 1, true, -1);
        var json = ts.ReadAll();
        var settings = eval("(" + json + ")");
        ts.Close();
        return settings;
      }

      function saveSettingsToJSONFile(filepath, settings) {
        var fso = new ActiveXObject("Scripting.FileSystemObject");
        var ts = fso.OpenTextFile(filepath, 2, true, -1);
        ts.WriteLine(jsonStringify(settings));
        ts.Close();
      }

      function insertRow(r) {
        if (r == -1) {
          r = table1.rows.length;
        }
        var newRow = table1.insertRow(r);
        newRow.insertCell(-1).innerHTML = '<input type="checkbox" name="chkEnabled" ' + (regRead(REGKEY_PATH + "Enabled" + r, true) ? 'checked' : '') + ' />';
        newRow.insertCell(-1).innerHTML = '<input type="checkbox" name="chkIgnoreCase" ' + (regRead(REGKEY_PATH + "IgnoreCase" + r, false) ? 'checked' : '') + ' />';
        newRow.insertCell(-1).innerHTML = '<input type="checkbox" name="chkUseRegExp" ' + (regRead(REGKEY_PATH + "UseRegExp" + r, false) ? 'checked' : '') + ' />';
        newRow.insertCell(-1).innerHTML = '<input class="textbox" type="text" name="txtPattern" value="" />'
        newRow.insertCell(-1).innerHTML = '<input class="textbox" type="text" name="txtReplaceText" value="" />'
        newRow.cells[3].childNodes[0].value = regRead(REGKEY_PATH + "Pattern" + r,  "");
        newRow.cells[4].childNodes[0].value = regRead(REGKEY_PATH + "ReplaceText" + r,  "");
      }

      function deleteRow(r) {
        if (table1.rows.length > 2) {
          table1.deleteRow(r);
        }
      }

      function onload() {
        jsonFilePath = objHTA.commandLine.split('"')[3];
        settings = loadSettingsFromJSONFile(jsonFilePath);

        var dpi = window.screen.deviceXDPI;
        var w = 800 * dpi / 96, h = 600 * dpi / 96;
        window.resizeTo(w, h);
        window.moveTo((screen.width - w) / 2, (screen.height - h) / 2);

        var count = regRead(REGKEY_PATH + "Count", 1);
        for (var i = 0; i < count; i++) {
          insertRow(-1);
        }
      }

      function btnOk_onclick() {
        regWrite(REGKEY_PATH + "Count", table1.rows.length - 1, "REG_DWORD");
        for (var i = 0; i < table1.rows.length - 1; i++) {
          regWrite(REGKEY_PATH + "Enabled" + (i + 1), document.getElementsByName("chkEnabled")[i].checked, "REG_DWORD");
          regWrite(REGKEY_PATH + "IgnoreCase" + (i + 1), document.getElementsByName("chkIgnoreCase")[i].checked, "REG_DWORD");
          regWrite(REGKEY_PATH + "UseRegExp" + (i + 1), document.getElementsByName("chkUseRegExp")[i].checked, "REG_DWORD");
          regWrite(REGKEY_PATH + "Pattern" + (i + 1), document.getElementsByName("txtPattern")[i].value, "REG_SZ");
          regWrite(REGKEY_PATH + "ReplaceText" + (i + 1), document.getElementsByName("txtReplaceText")[i].value, "REG_SZ");
        }

        saveSettingsToJSONFile(jsonFilePath, settings);

        window.close();
      }

      function btnCancel_onclick() {
        saveSettingsToJSONFile(jsonFilePath, "{}");

        window.close();
      }

    </script>
  </head>
  <body onload="onload();">
    <div class="container">
      <div class="btn-container-top">
        <ul>
          <li>
            <input type="button" class="btn" value="${Add}" onclick="insertRow(-1)" />
            <input type="button" class="btn" value="${Delete}" onclick="deleteRow(-1)" />
          </li>
        </ul>
      </div>
      <ul>
        <li>
          <table id="table1" border="1">
            <tr>
              <th>
                <label>${Enabled}</label>
              </th>
              <th>
                <label>${Ignore Case}</label>
              </th>
              <th>
                <label>${Use RegExp}</label>
              </th>
              <th>
                <label>${Find what}</label>
              </th>
              <th>
                <label>${Replace with}</label>
              </th>
            </tr>
          </table>
        </li>
      </ul>
      <div class="btn-container">
        <input type="button" class="btn-ok" onclick="btnOk_onclick();" value="${OK}" />
        <input type="button" class="btn-cancel" onclick="btnCancel_onclick();" value="${Cancel}" />
      </div>
    </div>
  </body>
</html>
]]>
</resource>

</scriptlet>
