
# require be provided bytewise
set(REG_FILE_TYPE_none	"hex(0)")
set(REG_FILE_TYPE_expand_sz "hex(2)")
set(REG_FILE_TYPE_expandable_string "${REG_FILE_TYPE_expand_sz}")
set(REG_FILE_TYPE_dword_big_endian "hex(5)")
set(REG_FILE_TYPE_dword_be "${REG_FILE_TYPE_dword_big_endian}")
set(REG_FILE_TYPE_link "hex(6)")
set(REG_FILE_TYPE_multi_sz "hex(7)")
set(REG_FILE_TYPE_multistring "${REG_FILE_TYPE_multi_sz}")
set(REG_FILE_TYPE_resource_list "hex(8)")
set(REG_FILE_TYPE_full_resource_descriptor "hex(9)")
set(REG_FILE_TYPE_qword "hex(b)")
set(REG_FILE_TYPE_qword_little_endian "${qword}")
set(REG_FILE_TYPE_resource_requirements_list "hex(a)")

# special
set(REG_FILE_TYPE_binary "hex")
set(REG_FILE_TYPE_hex "${REG_FILE_TYPE_binary}")
set(REG_FILE_TYPE_dword "dword")
set(REG_FILE_TYPE_dword_little_endian "dword")
set(REG_FILE_TYPE_sz "")
set(REG_FILE_TYPE_string "${REG_FILE_TYPE_sz}")

set(REG_FILE_HIVE_ABBR_HKLM "HKEY_LOCAL_MACHINE")
set(REG_FILE_HIVE_ABBR_HKCU "HKEY_CURRENT_USER")
set(REG_FILE_HIVE_ABBR_HKCR "HKEY_CLASSES_ROOT")
set(REG_FILE_HIVE_ABBR_HKU "HKEY_USERS")
set(REG_FILE_HIVE_ABBR_HKCC "HKEY_CURRENT_CONFIG")
set(REG_FILE_HIVE_ABBR_HKDD "HKEY_DYN_DATA")
set(REG_FILE_HIVE_ABBR_HKPD "HKEY_PERFORMANCE_DATA")
set(REG_FILE_HIVE_ABBR_SHCTX "SHELL_CONTEXT")


function(addRegistryKeyNSIS rootKey subKey keyName type value)
	message(STATUS "Adding registry key into NSIS script ${rootKey} ${subKey} ${keyName} ${type} ${value}")
	string(REPLACE "\\" "\\\\" subKey "${subKey}")

	set(type_tag "${REG_FILE_TYPE_${type}}")
	if("${type_tag}" STREQUAL "${REG_FILE_TYPE_dword}")
		set(commandName "WriteRegDWORD")
	elif("${type_tag}" STREQUAL "${REG_FILE_TYPE_sz}")
		set(commandName "WriteRegStr")
	elif("${type_tag}" STREQUAL "${REG_FILE_TYPE_binary}")
		set(commandName "WriteRegBin")
	elif("${type_tag}" STREQUAL "${REG_FILE_TYPE_none}")
		set(commandName "WriteRegNone")
	elif("${type_tag}" STREQUAL "${REG_FILE_TYPE_expandable_string}")
		set(commandName "WriteRegExpandStr")
	elif("${type_tag}" STREQUAL "${REG_FILE_TYPE_multistring}")
		set(commandName "WriteRegMultiStr")
	endif()

	SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}
		${commandName} ${rootKey} '${subKey}' '${keyName}' '${value}'
	")

	SET(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}
		DeleteRegValue HKLM '${subKey}' '${keyName}'
	")
	SET(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}
		DeleteRegKey /ifempty ${rootKey} '${subKey}' 
	")
endfunction()

function(getWixPatchProlog guid outVar)
	set(${outVar} "${${outVar}}<CPackWiXPatch>;<CPackWiXFragment Id=\"TARGETDIR\">;<Component Id=\"RegistryEntries\" Guid=\"${guid}\">" PARENT_SCOPE)
endfunction()
set(WixPatchEpilog "</Component>;</CPackWiXFragment>;</CPackWiXPatch>")

function(getWixRegKeyProlog rootKey subKeyComponent outVar)
	set("${outVar}" "${${outVar}}<RegistryKey ")
	if(rootKey)
		set(${outVar} "${${outVar}}Root=\"${rootKey}\" ")
	endif()
	set(${outVar} "${${outVar}}Key=\"${subKeyComponent}\" ")
	set(${outVar} "${${outVar}}Action=\"createAndRemoveOnUninstall\">")
	set(${outVar} "${${outVar}}" PARENT_SCOPE)
endfunction()
set("WixRegKeyEpilog" "</RegistryKey>")

function(getWixRegValue type key value outVar)
	set(${outVar} "<RegistryKey Type=\"${type}\" ")
	if(key)
		set(${outVar} "${${outVar}}Name=\"${key}\" ")
	endif()
	set(${outVar} "${${outVar}}Value=\"${value}\"/>")
	set(${outVar} "${${outVar}}" PARENT_SCOPE)
endfunction()

function(CPackRegistryInitCache)
	unset(CPackRegistry_installRegFile CACHE)
	unset(CPackRegistry_uninstallRegFile CACHE)
	unset(CPackRegistry_WIX_AMENDMENT CACHE)
endfunction()
CPackRegistryInitCache()


function(addRegistryKeyWIX rootKey subKey keyName type value)
	message(STATUS "Adding registry key into WIX patch file ${rootKey} ${subKey} ${keyName} ${type} ${value}")
	string(REPLACE "\\" ";" subKey "${subKey}")
	getWixPatchProlog("guidShit" currentPatch)

	list(GET "${subKey}" 0 firstPathComp)
	getWixRegKeyProlog("${rootKey}" "${firstPathComp}" currentPatch)
	list(SUBLIST "${subKey}" 1 -1 subKey)
	foreach(subKeyComponent ${subKey})
		getWixRegKeyProlog("" "${subKeyComponent}" currentPatch)
	endforeach()

	getWixRegValue("${type}" "${keyName}" "${value}" currentPatch)

	foreach(subKeyComponent ${subKey})
		set("currentPatch" "${currentPatch}${WixRegKeyEpilog}")
	endforeach()
	set(currentPatch "${currentPatch};${WixRegKeyEpilog}")

	set(currentPatch "${currentPatch};${WixPatchEpilog}")
	set(CPackRegistry_WIX_AMENDMENT "${currentPatch}" CACHE INTERNAL "WIX patch file.")
endfunction()

function(integer2bytes int size isBE outVar)
	math(EXPR hexed "${int}" OUTPUT_FORMAT HEXADECIMAL)
	string(LENGTH "${hexed}" l)
	math(EXPR bytes "${l}/2")
	
	set(res "")
	for(i in range 0 ${bytes})
		math(EXPR pos1 "${i}*2")
		math(EXPR pos2 "${pos1}+2")
		string(SUBSTRING "${hexed}" "${pos1}" "${pos2}" byte)
		list(APPEND res ${byte})
	endfor()
	if(isBE)
		list(REVERSE res)
	endif()
	string(REPLACE ";" "," res "${res}")
	set(outVar "${res}" PARENT_SCOPE)
endfunction()

function(expandRootKey rootKey outVar)
	string(LENGTH "${rootKey}" rootKeyLen)
	if("${rootKeyLen}" LESS_EQUAL 5)
		string(TOUPPER "${rootKey}" rootKey)
		set(rootKey "${REG_FILE_HIVE_ABBR_${rootKey}}")
	endif()
	set("${outVar}" "${rootKey}" PARENT_SCOPE)
endfunction()

function(addRegistryKeyRegFile rootKey subKey keyName type value uninstallType)
	expandRootKey("${rootKey}" rootKey)
	message(STATUS "Adding registry key into reg file ${rootKey} ${subKey} ${keyName} ${type} ${value}")

	set(type_tag "${REG_FILE_TYPE_${type}}")
	if("${type_tag}" STREQUAL "${REG_FILE_TYPE_expand_sz}" OR "${type_tag}" STREQUAL "${REG_FILE_TYPE_multi_sz}" OR "${type_tag}" STREQUAL "${REG_FILE_TYPE_link}")
		string(HEX "${value}" "${value}")
	elif("${type_tag}" STREQUAL "${REG_FILE_TYPE_qword}")
		integer2bytes("${value}" 8 OFF value)
	elif("${type_tag}" STREQUAL "${REG_FILE_TYPE_dword_big_endian}")
		integer2bytes("${value}" 4 ON value)
	endif()

	if("${type_tag}" STREQUAL "${REG_FILE_TYPE_sz}")
		set(typeValue "\"${value}\"")
	else()
		set(typeValue "${type}:${value}")
	endif()

	if(NOT DEFINED CACHE{CPackRegistry_installRegFile})
		list(APPEND CPackRegistry_installRegFile "Windows Registry Editor Version 5.00")
		list(APPEND CPackRegistry_installRegFile "") # 2 empty lines
		list(APPEND CPackRegistry_installRegFile "")
		set(CPackRegistry_uninstallRegFile "${CPackRegistry_installRegFile}")
	else()
		set(CPackRegistry_installRegFile "$CACHE{CPackRegistry_installRegFile}")
		set(CPackRegistry_uninstallRegFile "$CACHE{CPackRegistry_uninstallRegFile}")
	endif()
	
	list(APPEND CPackRegistry_installRegFile "[${rootKey}\\${subKey}]")
	list(APPEND CPackRegistry_installRegFile "\"${keyName}\"=${typeValue}")

	if("${uninstallType}" STREQUAL "deleteSubkey")
		list(APPEND CPackRegistry_uninstallRegFile "[-${rootKey}\\${subKey}]")
	elseif("${uninstallType}" STREQUAL "deleteValue")
		list(APPEND CPackRegistry_uninstallRegFile "[${rootKey}\\${subKey}]")
		list(APPEND CPackRegistry_uninstallRegFile "\"${keyName}\"=-")
	endif()

	set(CPackRegistry_installRegFile "${CPackRegistry_installRegFile}" CACHE INTERNAL "List of lines of a .reg file to create the needed registry keys.")
	set(CPackRegistry_uninstallRegFile "${CPackRegistry_uninstallRegFile}" CACHE INTERNAL "List of lines of a .reg file to remove the registry keys created by CPackRegistry_installRegFile.")
endfunction()


function(addRegistryKeyIWF rootKey subKey keyName type value)
	message(STATUS "Adding registry key IFW ${rootKey} ${subKey} ${keyName} ${type} ${value}")
	#CPACK_IFW_PACKAGE_CONTROL_SCRIPT
endfunction()

function(addRegistryKeyActivateNSISifNeeded outVar)
	set(res OFF)
	list(FIND CPACK_GENERATOR "NSIS" FOUND)
	if(NOT "${FOUND}" STREQUAL "-1")
		set(res ON)
	endif()
	message(STATUS "FIND CPACK_GENERATOR NSIS FOUND ${FOUND} ${res}")
	list(FIND CPACK_GENERATOR "NSIS64" FOUND)
	if(NOT "${FOUND}" STREQUAL "-1")
		set(res ON)
	endif()
	set("${outVar}" "${res}" PARENT_SCOPE)
endfunction()

function(CPackRegistryFinalize destinationDir registerFileName deRegisterFileName)
	if(DEFINED CACHE{CPackRegistry_installRegFile})
		message(STATUS "Writing reg files: ${destinationDir}/${registerFileName} and ${destinationDir}/${deRegisterFileName}")
		string(REPLACE ";" "\n" CPackRegistry_installRegFile "$CACHE{CPackRegistry_installRegFile}")
		string(REPLACE ";" "\n" CPackRegistry_uninstallRegFile "$CACHE{CPackRegistry_uninstallRegFile}")
		file(WRITE "${destinationDir}/${registerFileName}" "${CPackRegistry_installRegFile}")
		file(WRITE "${destinationDir}/${deRegisterFileName}" "${CPackRegistry_uninstallRegFile}")
	endif()
	if(DEFINED CACHE{CPackRegistry_WIX_AMENDMENT})
		message(STATUS "Writing WIX patchfile: ${destinationDir}/WixRegistryAmendment.xml")
		string(REPLACE ";" "\n" CPackRegistry_WIX_AMENDMENT "$CACHE{CPackRegistry_WIX_AMENDMENT}")
		file(WRITE "${destinationDir}/WixRegistryAmendment.xml" "${CPackRegistry_WIX_AMENDMENT}")
	endif()
	CPackRegistryInitCache()
endfunction()

function(addRegistry_key rootKey subKey keyName type value uninstallType)
	addRegistryKeyRegFile("${rootKey}" "${subKey}" "${keyName}" "${type}" "${value}" "${uninstallType}")

	addRegistryKeyActivateNSISifNeeded(nsisUsed)
	if("${nsisUsed}")
		addRegistryKeyNSIS("${rootKey}" "${subKey}" "${keyName}" "${type}" "${value}")
	endif()
	list(FIND CPACK_GENERATOR "WIX" FOUND)
	if(NOT "${FOUND}" STREQUAL "-1")
		addRegistryKeyWIX("${rootKey}" "${subKey}" "${keyName}" "${type}" "${value}")
	endif()

	list(FIND CPACK_GENERATOR "IFW" FOUND)
	set(IFWUsed OFF)
	if(NOT "${FOUND}" STREQUAL "-1")
		set(IFWUsed ON)
	endif()

	if("${IFWUsed}")
		addRegistryKeyIWF("${rootKey}" "${subKey}" "${keyName}" "${type}" "${value}")
	endif()
endfunction()
