<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="PluginUnpackedFileExtension">
		<get/>
	</property>
	<property name="PluginExtendedProperties">
		<get/>
	</property>
	<method name="PluginOnEvent"/>
	<method name="UnpackFile"/>
	<method name="PackFile"/>
	<method name="IsFolder"/>
	<method name="UnpackFolder"/>
	<method name="PackFolder"/>
	<method name="ShowSettingsDialog"/>
</implements>

<script language="VBS">

'/////////////////////////////////////////////////////////////////////////////
'    This is a plugin for WinMerge.
'    It will display the text content of MS Excel files.
'    Copyright (C) 2005-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\CompareMSExcelFiles.sct/"
Const pbGroup = 6
Dim MsgCannotGetMacros
MsgCannotGetMacros = "${Cannot get Macros." & vbCrLf & _
	"   To allow WinMerge to compare macros, use MS Office to alter the settings in the Macro Security for the current application." & vbCrLf & _
	"   The Trust access to Visual Basic Project feature should be turned on to use this feature in WinMerge." & vbCrLf & "}"

Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")
Dim wsh: Set wsh = CreateObject("WScript.Shell")
Dim mergeApp

Function isAccessibleVBAProject(wbk)
	Dim count
	count = -1
	On Error Resume Next
	count = wbk.VBProject.VBComponents.Count
	isAccessibleVBAProject = (count > 0)
End Function

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 writeObjectProperties(fo, items)
	On Error Resume Next
	Dim o
	For Each o In items
		fo.WriteLine o.Name & ": " & o.Value
	Next
End Function

Function QuoteIfNeeded(str)
	Dim fQuote
	If InStr(str, vbTab) > 0 Then
		fQuote = True
	ElseIf InStr(str, """") > 0 Then
		fQuote = True
	ElseIf InStr(str, vbLf) > 0 Then
		fQuote = True
	End If
	If fQuote Then
		QuoteIfNeeded = """" & Replace(str, """", """""") & """"
	Else
		QuoteIfNeeded = str
	End If
End Function

Function writeCellValues(fo, sht)
	Dim varCells, row, col, ary()
	varCells = sht.UsedRange.Value
	If TypeName(varCells) = "String" Then
		fo.WriteLine QuoteIfNeeded(varCells)
	ElseIf Not IsEmpty(varCells) Then
		ReDim ary(UBound(varCells, 2))
		On Error Resume Next
		For row = 1 To UBound(varCells, 1)
			For col = 1 To UBound(varCells, 2)
				ary(col - 1) = QuoteIfNeeded(CStr(varCells(row, col)))
				If Err.Number <> 0 Then
					ary(col - 1) = "Error" & Err.Number
					Err.Clear
				End If
			Next
			fo.WriteLine Join(ary, vbTab)
		Next
	End If
End Function

Function GetAddr(row, col)
    Dim c
    c = col - 1
    Do
        GetAddr = Chr(65 + (c Mod 26)) & GetAddr
        c = (c \ 26) - 1
    Loop While c >= 0
    GetAddr = GetAddr & row
End Function

Function writeFormulas(fo, sht)
	Dim row, col, rowOffset, colOffset, varCells, formula
	rowOffset = sht.UsedRange.Row
	colOffset = sht.UsedRange.Column
	varCells = sht.UsedRange.Formula
	If TypeName(varCells) = "String" Then
		fo.WriteLine GetAddr(rowOffset - 1, colOffset - 1) & ": " & varCells
	Else
		For row = 1 To UBound(varCells, 1)
			For col = 1 To UBound(varCells, 2)
				formula = varCells(row, col)
				If Left(formula, 1) = "=" Then 
					fo.WriteLine GetAddr(row + rowOffset - 1, col + colOffset - 1) & ": " & formula
				End If
			Next
		Next
	End If
End Function

Function getUsedRangeIncludingShapes(sht)
	Dim shp, rng
	Dim col_max, row_max
	col_max = 0
	row_max = 0
	For Each shp In sht.Shapes
		Set rng = shp.BottomRightCell
		If row_max < rng.Row + rng.Rows.Count - 1 Then row_max = rng.Row + rng.Rows.Count - 1
		If col_max < rng.Column + rng.Columns.Count - 1 Then col_max = rng.Column + rng.Columns.Count - 1
	Next
	Set rng = sht.UsedRange
	If row_max < rng.Row + rng.Rows.Count - 1 Then row_max = rng.Row + rng.Rows.Count - 1
	If col_max < rng.Column + rng.Columns.Count - 1 Then col_max = rng.Column + rng.Columns.Count - 1
	Set getUsedRangeIncludingShapes = sht.Range("A1", sht.Cells(row_max, col_max))
End Function

Sub ungroupShapes(sht)
    On Error Resume Next
    Dim cnt, shp
    Do
        cnt = sht.Shapes.Count
        For Each shp In sht.Shapes
            If shp.Type = pbGroup Then shp.ungroup
        Next
    Loop While cnt <> sht.Shapes.Count
End Sub

Function writeTextsInShapes(fo, sht)
	Dim shp
	On Error Resume Next
	For Each shp In sht.Shapes
		fo.WriteLine shp.Name & ": " & shp.TextFrame.Characters.Text
	Next
	On Error GoTo 0
End Function

Function writeHeadersAndFooters(fo, sht)
	On Error Resume Next
	fo.WriteLine "LeftHeader: " & sht.PageSetup.LeftHeader
	fo.WriteLine "CenterHeader: " & sht.PageSetup.CenterHeader
	fo.WriteLine "RightHeader: " & sht.PageSetup.RightHeader
	fo.WriteLine "LeftFooter: " & sht.PageSetup.LeftFooter
	fo.WriteLine "CenterFooter: " & sht.PageSetup.CenterFooter
	fo.WriteLine "RightFooter: " & sht.PageSetup.RightFooter
	On Error GoTo 0
End Function

Function getModuleExtension(cmp)
	Select Case cmp.Type
	Case 2
		getModuleExtension = ".cls"
	Case 3
		getModuleExtension = ".frm"
	Case Else
		getModuleExtension = ".bas"
	End Select
End Function

Sub Sleep(sec)
	if sec = 0 Then Exit Sub
	wsh.Run "ping.exe localhost -n " & sec, 0, True
End Sub

Function saveRangeAsImage(sht, rng, filename)
	Dim obj
	Dim shtNew
	Dim wbkNew
	Dim oldSheetsInNewWorkbook
	Dim i

	saveRangeAsImage = True

	On Error Resume Next
	Err.Clear

	sht.Activate
	With sht.Parent.Windows(1)
		.DisplayGridlines = False
		.View = 1
	End With

	oldSheetsInNewWorkbook = sht.Application.SheetsInNewWorkbook
	sht.Application.SheetsInNewWorkbook = 1
	set wbkNew = sht.Application.Workbooks.Add
	sht.Application.SheetsInNewWorkbook = oldSheetsInNewWorkbook
	Set shtNew = wbkNew.Sheets(1)
	Set obj = wbkNew.Charts.Add
	Set obj = obj.Location(2, shtNew.Name) ' xlLocationAsObject=2

	If sht.Application.Version <= 11 Then
		obj.Parent.Width = rng.Width + 8
		obj.Parent.Height = rng.Height + 8
	Else
		obj.Parent.Width = rng.Width
		obj.Parent.Height = rng.Height
	End If

	For i = 0 to 1
		If sht.Application.Version < 14 Then
			rng.CopyPicture 1, 2 ' xlScreen=1, xlBitmap=2
			If Err.Number = 0 Then
				Sleep i
				obj.Paste
				obj.Export filename, "PNG"
			ElseIf i = 0 Then
				Sleep 1
			End If
		Else
			rng.Copy
			If Err.Number = 0 Then
				Sleep i
				shtNew.Pictures.Paste
				obj.Export filename, "PNG"
			ElseIf i = 0 Then
				Sleep 1
			End If
		End If

		If Err.Number = 0 Then Exit For
		If i = 0 Then Err.Clear
	Next

	wbkNew.Close False

	saveRangeAsImage = (Err.Number = 0)

End Function

Function getTimeStamp()
    Dim dt, tm, ms
    tm = Timer
    ms = Fix((tm - Fix(tm)) * 1000)
    tm = Fix(tm)
    getTimeStamp = (tm \ (60 * 60)) & ":" & ((tm \ 60) Mod 60) & ":" & (tm Mod 60) & "." & ms
End Function

Function findRowByPosition(sht, ByVal rowBegin, ByVal rowEnd, ByVal pos)
    Dim height, rowPrev, row, rowBeginOrg
    row = rowEnd
    rowBeginOrg = rowBegin
    rowPrev = row
    Do
        height = sht.Range("A" & rowBeginOrg & ":A" & row).height
        If height < pos Then
            rowBegin = row
        Else
            rowEnd = row
        End If
        row = (rowEnd - rowBegin) \ 2 + rowBegin
        If row = rowPrev Then
            findRowByPosition = row
            Exit Function
        End If
        rowPrev = row
    Loop
End Function

Function findColumnByPosition(sht, ByVal columnBegin, ByVal columnEnd, ByVal pos)
    Dim width, columnPrev, column, columnBeginOrg
    column = columnEnd
    columnBeginOrg = columnBegin
    columnPrev = column
    Do
        width = sht.Range(sht.Cells(1, columnBeginOrg), sht.Cells(1, column)).width
        If width < pos Then
            columnBegin = column
        Else
            columnEnd = column
        End If
        column = (columnEnd - columnBegin) \ 2 + columnBegin
        If column = columnPrev Then
            findColumnByPosition = column
            Exit Function
        End If
        columnPrev = column
    Loop
End Function

Function saveSheetAsImage(sht, basefilename)
	Dim rngUsed, rngImage, row, rowEnd, column, columnEnd, filename, numX, numY, imageWidth, imageHeight
	imageWidth = regRead(RegKeyPath & "ImageWidth", 1000)
	imageHeight = regRead(RegKeyPath & "ImageHeight", 3000)
	Set rngUsed = getUsedRangeIncludingShapes(sht)
	numX = 1
	column = rngUsed.Column
	Do 
		columnEnd = findColumnByPosition(sht, column, rngUsed.Column + rngUsed.Columns.Count - 1, imageWidth)
		numY = 1
		row = rngUsed.Row
		Do 
			rowEnd = findRowByPosition(sht, row, rngUsed.Row + rngUsed.Rows.Count - 1, imageHeight)
			Set rngImage = sht.Range(sht.Cells(row, column), sht.Cells(rowEnd, columnEnd))
			filename = basefilename & "(" & numX & "-" & numY & ").png"
			If Not saveRangeAsImage(sht, rngImage, filename) Then
				Dim shtNew
				Set shtNew = sht.Parent.Sheets.Add
				shtNew.Range("A1") = getTimeStamp() & ": Error" & Err.Number & ": " & Err.Description
				shtNew.Columns.AutoFit
				saveRangeAsImage shtNew, shtNew.Range("A1"), filename
				shtNew.Delete
			End If
			row = rowEnd + 1
			numY = numY + 1
		Loop While row < rngUsed.row + rngUsed.Rows.Count - 1 
		column = columnEnd + 1
		numX = numX + 1
	Loop While column < rngUsed.column + rngUsed.Columns.Count - 1 
End Function

Function saveSheetAsHTML(sht, filename)
    Dim pobj
    Set pobj = sht.Parent.PublishObjects.Add(1, filename, sht.Name, "", 0, "CompareMSExcelFilesPlugin", "") ' 1 = xlSourceSheet, 0 = xlHtmlStatic
    pobj.Publish True
    pobj.AutoRepublish = False
End Function

Function escape(sheetName)
    escape = Replace(sheetName, "%", "%25")
    escape = Replace(escape, "<", "%3C")
    escape = Replace(escape, ">", "%3E")
    escape = Replace(escape, "|", "%7C")
    Select Case Left(UCase(escape), 3)
    Case "CON", "AUX", "NUL"
        If Len(escape) = 3 Then
            escape = "%" & escape
        End If
    Case "COM", "LPT"
        If Len(escape) = 4 And IsNumeric(Mid(escape, 4, 1)) Then
            escape = "%" & escape
        End If
    End Select
End Function

Function get_PluginEvent()
	get_PluginEvent = "FILE_FOLDER_PACK_UNPACK"
End Function

Function get_PluginDescription()
	get_PluginDescription = "Display the text content of MS Excel files"
End Function

Function get_PluginFileFilters()
	get_PluginFileFilters = "\.xls(\..*)?$;\.xlsx(\..*)?$;\.xlsm(\..*)?$;\.xlsb(\..*)?;\.xla(\..*)?$;\.xlax(\..*)?$;\.xltx(\..*)?$;\.xltm(\..*)?$"
End Function

Function get_PluginIsAutomatic()
	get_PluginIsAutomatic = True
End Function

Function get_PluginUnpackedFileExtension()
	get_PluginUnpackedFileExtension = ".tsv"
End Function

Function get_PluginExtendedProperties()
	get_PluginExtendedProperties = "ProcessType=Content Extraction;FileType=MS-Excel;MenuCaption=MS-Excel"
End Function

Sub PluginOnEvent(eventType, obj)
	Set mergeApp = obj
End Sub

Function UnpackFile(fileSrc, fileDst, pbChanged, pSubcode)
	Dim fo
	Dim xl
	Dim wbk
	Dim sht
	Dim cmp
	Dim fileSrc2

	Set fo = fso.CreateTextFile(fileDst, True, True)

	Set xl = CreateObject("Excel.Application")
	xl.EnableEvents = False
	xl.DisplayAlerts = False

	fileSrc2 = fileSrc
	If fso.GetExtensionName(fileSrc2) = "lnk" Then
		fileSrc2 = wsh.CreateShortcut(fileSrc2).TargetPath
		If Not fso.FileExists(fileSrc2) Then
			Err.Raise 30001, "CompareMSExcelFiles.sct", fileSrc & ": Target file '" & fileSrc2 & "' not found"
		End If 
	End If
	Set wbk = xl.Workbooks.Open(fileSrc2, regRead(RegKeyPath & "UpdateLinks", 0),,,,,,,,,,,,True)

	On Error Resume Next

	If regRead(RegKeyPath & "CompareDocumentProperties", False) Then
		fo.WriteLine "[Document Properties]"
		writeObjectProperties fo, wbk.BuiltinDocumentProperties
		fo.WriteLine ""
	End If

	If regRead(RegKeyPath & "CompareNames", True) Then
		fo.WriteLine "[Names]"
		writeObjectProperties fo, wbk.Names
		fo.WriteLine ""
	End If

	For Each sht In wbk.Worksheets
		If regRead(RegKeyPath & "CompareCellValues", True) Then
			fo.WriteLine "[" & sht.Name & "]"
			writeCellValues fo, sht
			fo.WriteLine ""
		End If
		If regRead(RegKeyPath & "CompareFormulas", False) Then
			fo.WriteLine "[" & sht.Name & ".Formulas]"
			writeFormulas fo, sht
			fo.WriteLine ""
		End If
		If regRead(RegKeyPath & "CompareTextsInShapes", True) Then
			fo.WriteLine "[" & sht.Name & ".Shapes]"
			ungroupShapes sht
			writeTextsInShapes fo, sht
			fo.WriteLine ""
		End If
		If regRead(RegKeyPath & "CompareHeadersAndFooters", True) Then
			fo.WriteLine "[" & sht.Name & ".HeadersAndFooters]"
			writeHeadersAndFooters fo, sht
			fo.WriteLine ""
		End If
	Next

	If regRead(RegKeyPath & "CompareVBAMacros", True) Then
		If Not isAccessibleVBAProject(wbk) Then
			fo.WriteLine Translate(MsgCannotGetMacros)
		End If
		For Each cmp In wbk.VBProject.VBComponents
			fo.WriteLine "[CodeModule." & cmp.Name & "]"
			If cmp.CodeModule.CountOfLines > 0 Then
				fo.WriteLine cmp.CodeModule.Lines(1, cmp.CodeModule.CountOfLines)
			End If
			fo.WriteLine ""
		Next
	End If

	Set sht = Nothing
	wbk.Close
	Set wbk = Nothing
	xl.Quit
	Set xl = Nothing
	fo.Close
	Set fo = Nothing

	pbChanged = True
	pSubcode = 0
	UnpackFile = True

End Function

Function PackFile(fileSrc, fileDst, pbChanged, pSubcode)
	PackFile = False
End Function

Function IsFolder(file)
	IsFolder = regRead(RegKeyPath & "UnpackToFolder", False)
End Function

Function UnpackFolder(fileSrc, folderDst, pbChanged, pSubcode)
	Dim fo
	Dim xl
	Dim wbk
	Dim sht
	Dim cmp
	Dim digit
	Dim zf
	Dim No
	Dim fileSrc2

	If Not fso.FolderExists(folderDst) Then fso.CreateFolder folderDst

	Set xl = CreateObject("Excel.Application")
	xl.EnableEvents = False
	xl.DisplayAlerts = False

	Dim backgroundChecking
	backgroundChecking = xl.ErrorCheckingOptions.BackgroundChecking
	xl.ErrorCheckingOptions.BackgroundChecking = False

	fileSrc2 = fileSrc
	If fso.GetExtensionName(fileSrc2) = "lnk" Then
		fileSrc2 = wsh.CreateShortcut(fileSrc2).TargetPath
		If Not fso.FileExists(fileSrc2) Then
			Err.Raise 30001, "CompareMSExcelFiles.sct", fileSrc & ": Target file '" & fileSrc2 & "' not found"
		End If 
	End If
	Set wbk = xl.Workbooks.Open(fileSrc2, regRead(RegKeyPath & "UpdateLinks", 0),,,,,,,,,,,,True)

	On Error Resume Next

	digit = Len(CStr(wbk.Worksheets.Count))
	If digit <= 0 Then digit = 1
	zf = String(digit, "0")

	If regRead(RegKeyPath & "CompareDocumentProperties", False) Then
		Set fo = fso.CreateTextFile(fso.BuildPath(folderDst, "(" & zf & ")DocumentProperties.txt"), True, True)
		writeObjectProperties fo, wbk.BuiltinDocumentProperties
		fo.Close
	End If

	If regRead(RegKeyPath & "CompareNames", True) Then
		Set fo = fso.CreateTextFile(fso.BuildPath(folderDst, "(" & zf & ")Names.txt"), True, True)
		writeObjectProperties fo, wbk.Names
		fo.Close
	End If

	No = 1
	For Each sht In wbk.Worksheets
		No = Right(zf & CInt(No), digit)
		If regRead(RegKeyPath & "CompareCellValues", True) Then
			Set fo = fso.CreateTextFile(fso.BuildPath(folderDst, "(" & No & ")" & escape(sht.Name) & ".tsv"), True, True)
			writeCellValues fo, sht
			fo.Close
		End If

		If regRead(RegKeyPath & "CompareFormulas", False) Then
			Set fo = fso.CreateTextFile(fso.BuildPath(folderDst, "(" & No & ")" & escape(sht.Name) & "_Formulas.txt"), True, True)
			writeFormulas fo, sht
			fo.Close
		End If

		If regRead(RegKeyPath & "CompareTextsInShapes", True) Then
			Set fo = fso.CreateTextFile(fso.BuildPath(folderDst, "(" & No & ")" & escape(sht.Name) & "_Shapes.txt"), True, True)
			ungroupShapes sht
			writeTextsInShapes fo, sht
			fo.Close
		End If

		If regRead(RegKeyPath & "CompareHeadersAndFooters", True) Then
			Set fo = fso.CreateTextFile(fso.BuildPath(folderDst, "(" & No & ")" & escape(sht.Name) & "_HeadersAndFooters.txt"), True, True)
			writeHeadersAndFooters fo, sht
			fo.Close
		End If

		If regRead(RegKeyPath & "CompareWorksheetsAsImage", True) Then
			saveSheetAsImage sht, fso.BuildPath(folderDst, "(" & No & ")" & escape(sht.Name))
		End If

		If regRead(RegKeyPath & "CompareWorksheetsAsHTML", False) Then
			saveSheetAsHTML sht, fso.BuildPath(folderDst, "(" & No & ")" & escape(sht.Name) & ".html")
		End If
		No = CInt(No) + 1
	Next
	If regRead(RegKeyPath & "CompareVBAMacros", True) Then
		If Not isAccessibleVBAProject(wbk) Then
			Set fo = fso.CreateTextFile(fso.BuildPath(folderDst, "CannotGetMacros.bas"), True, True)
			fo.WriteLine Translate(MsgCannotGetMacros)
			fo.Close
		End If

		For Each cmp In wbk.VBProject.VBComponents
			cmp.Export fso.BuildPath(folderDst, cmp.Name & getModuleExtension(cmp))
		Next
	End If

	Set sht = Nothing
	wbk.Close
	Set wbk = Nothing
	xl.ErrorCheckingOptions.BackgroundChecking = backgroundChecking
	xl.Quit
	Set xl = Nothing
	Set fo = Nothing

	pbChanged = True
	pSubcode = 0
	UnpackFolder = True
End Function

Function PackFolder(fileSrc, folderDst, pbChanged, pSubcode)
	PackFolder = False
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\\CompareMSExcelFiles.sct/";

function exportSettingsToJSONFile(filepath)
{
	var key_defvalues = {
		"UnpackToFolder" : false,
		"UpdateLinks" : false,
		"CompareDocumentProperties" : false,
		"CompareNames" : true,
		"CompareCellValues" : true,
		"CompareWorksheetsAsImage" : true,
		"CompareWorksheetsAsHTML" : false,
		"ImageWidth" : 1000,
		"ImageHeight" : 3000,
		"CompareFormulas" : false,
		"CompareTextsInShapes" : true,
		"CompareHeadersAndFooters" : true,
		"CompareVBAMacros" : true
	};
	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>${CompareMSExcelFiles.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 { margin-top: 1.5em; text-align: right; }
    input[type="button"] { border: none; padding: 0.6em 2em; height: 2.5em; text-align: center; }
    .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; }
    </style>
    <script type="text/javascript">
      var REGKEY_PATH = "Plugins\\CompareMSExcelFiles.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 onload() {
        jsonFilePath = objHTA.commandLine.split('"')[3];
        settings = loadSettingsFromJSONFile(jsonFilePath);

        var dpi = window.screen.deviceXDPI;
        var w = 600 * dpi / 96, h = 500 * dpi / 96;
        window.resizeTo(w, h);
        window.moveTo((screen.width - w) / 2, (screen.height - h) / 2);

        chkUnpackToFolder.checked = regRead(REGKEY_PATH + "UnpackToFolder", false);
        chkUpdateLinks.checked = (regRead(REGKEY_PATH + "UpdateLinks", 0) == 3);
        chkCompareDocumentProperties.checked = regRead(REGKEY_PATH + "CompareDocumentProperties", false);
        chkCompareNames.checked = regRead(REGKEY_PATH + "CompareNames", true);
        chkCompareCellValues.checked = regRead(REGKEY_PATH + "CompareCellValues", true);
        chkCompareWorksheetsAsImage.checked = regRead(REGKEY_PATH + "CompareWorksheetsAsImage", true);
        chkCompareWorksheetsAsHTML.checked = regRead(REGKEY_PATH + "CompareWorksheetsAsHTML", false);
        txtImageWidth.value = regRead(REGKEY_PATH + "ImageWidth", 1000);
        txtImageHeight.value = regRead(REGKEY_PATH + "ImageHeight", 3000);
        chkCompareFormulas.checked = regRead(REGKEY_PATH + "CompareFormulas", false);
        chkCompareTextsInShapes.checked = regRead(REGKEY_PATH + "CompareTextsInShapes", true);
        chkCompareHeadersAndFooters.checked = regRead(REGKEY_PATH + "CompareHeadersAndFooters", true);
        chkCompareVBAMacros.checked = regRead(REGKEY_PATH + "CompareVBAMacros", true);
        chkUnpackToFolder_onclick();
        chkCompareWorksheetsAsImage_onclick();
        chkCompareWorksheetsAsHTML_onclick();
      }

      function chkUnpackToFolder_onclick() {
        if (!chkUnpackToFolder.checked) {
          chkCompareWorksheetsAsImage.checked = false;
          chkCompareWorksheetsAsHTML.checked = false;
        }
      }

      function chkCompareWorksheetsAsImage_onclick() {
        if (chkCompareWorksheetsAsImage.checked)
          chkUnpackToFolder.checked = true;
      }

      function chkCompareWorksheetsAsHTML_onclick() {
        if (chkCompareWorksheetsAsHTML.checked)
          chkUnpackToFolder.checked = true;
      }

      function btnOk_onclick() {
        regWrite(REGKEY_PATH + "UnpackToFolder", chkUnpackToFolder.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "UpdateLinks", chkUpdateLinks.checked ? 3 : 0, "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareDocumentProperties", chkCompareDocumentProperties.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareNames", chkCompareNames.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareCellValues", chkCompareCellValues.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareWorksheetsAsImage", chkCompareWorksheetsAsImage.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareWorksheetsAsHTML", chkCompareWorksheetsAsHTML.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "ImageWidth", Number(txtImageWidth.value), "REG_DWORD");
        regWrite(REGKEY_PATH + "ImageHeight", Number(txtImageHeight.value), "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareFormulas", chkCompareFormulas.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareTextsInShapes", chkCompareTextsInShapes.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareHeadersAndFooters", chkCompareHeadersAndFooters.checked, "REG_DWORD");
        regWrite(REGKEY_PATH + "CompareVBAMacros", chkCompareVBAMacros.checked, "REG_DWORD");

        saveSettingsToJSONFile(jsonFilePath, settings);

        window.close();
      }

      function btnCancel_onclick() {
        saveSettingsToJSONFile(jsonFilePath, "{}");

        window.close();
      }

      function onlyNumeric() {
        var k = event.keyCode;

        if (event.shiftKey) {
          if (k == 37 || k == 39) {
            return true;
          }
        } else if (event.altKey) {
          return true;
        } else if (event.ctrlKey) {
          return true;
        } else if (k == 8 || k == 9 || k == 37 || k == 39 || k == 46 /* || k == 144 */
            || (48 <= k && k <= 57) || (96 <= k && k <= 105)) {
          return true;
        }

        event.returnValue = false;
        return false;
      }

      function onPaste() {
        var paste = (event.clipboardData || window.clipboardData).getData("text");
        if (!paste.match(/^[0-9]{0,4}$/)) {
          paste = "";
          if (event.preventDefault) {
              event.preventDefault();
          }
          event.returnValue = false;
          return false;
        } else {
          return true;
        }
      }
    </script>
  </head>
  <body onload="onload();">
		<div class="container">
			<ul>
				<li>
					<input id="chkUnpackToFolder" type="checkbox" onclick="chkUnpackToFolder_onclick();"/>
					<label>${Extract workbook data to multiple files}</label>
				</li>
				<li>
					<input id="chkUpdateLinks" type="checkbox" />
					<label>${Update external references(links)}</label>
				</li>
				<li>
					<input id="chkCompareDocumentProperties" type="checkbox" />
					<label>${Compare document properties}</label>
				</li>
				<li>
					<input id="chkCompareNames" type="checkbox" />
					<label>${Compare names}</label>
				</li>
				<li>
					<input id="chkCompareCellValues" type="checkbox" />
					<label>${Compare cell values}</label>
				</li>
				<li>
					<input id="chkCompareWorksheetsAsImage" type="checkbox" onclick="chkCompareWorksheetsAsImage_onclick();"/>
					<label>${Compare worksheets as image (very slow)}</label>
					<ul>
						<li>
							<label>${ - Image split size: }</label>
							<input id="txtImageWidth"  type="text" size="5" maxlength="4" onkeyDown="return onlyNumeric();" onpaste="return onPaste();" />
							<span> x </span>
							<input id="txtImageHeight" type="text" size="5" maxlength="4" onkeyDown="return onlyNumeric();" onpaste="return onPaste();" />
						</li>
					</ul>
				</li>
				<li>
					<input id="chkCompareWorksheetsAsHTML" type="checkbox" onclick="chkCompareWorksheetsAsHTML_onclick();"/>
					<label>${Compare worksheets as HTML}</label>
				</li>
				<li>
					<input id="chkCompareFormulas" type="checkbox" />
					<label>${Compare formulas}</label>
				</li>
				<li>
					<input id="chkCompareTextsInShapes" type="checkbox" />
					<label>${Compare texts in shapes}</label>
				</li>
				<li>
					<input id="chkCompareHeadersAndFooters" type="checkbox" />
					<label>${Compare headers and footers}</label>
				</li>
				<li>
					<input id="chkCompareVBAMacros" type="checkbox" />
					<label>${Compare VBA macros}</label>
				</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>
