@echo OFF
setlocal enabledelayedexpansion

reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set OS=x86 || set OS=x64

if not %1 == s (
	cls
	echo ---------------------------------------
	echo --- unipatch v0.8 by epithetic --------
	echo ---------------------------------------
	echo.
	echo.
)
if %1.==. goto MissingParam
if %2.==. goto MissingParam

set "source=%2"
set "dest=%3"
set "work=%~dp0%"
rem Default destination to working directory
if %3.==. set "dest=%~dp0%"

if %1 == extract (set mode=extract) else if %1 == install (set mode=install) else if %1 == ^? (set mode=read) else if %1 == s (set mode=read) else (goto MissingParam)

if not exist !source!\ goto MissingDir
if not exist !dest!\ goto MissingDir

set warncount=0
set errcount=0

if not %1 == s (
	echo.

	echo Preparing to !mode! from !source!...
	echo.

	echo ---------------------------------------- >> unipatch-log.txt
	echo %time% %date% ^| Preparing to !mode! from !source! >> unipatch-log.txt
	echo ---------------------------------------- >> unipatch-log.txt
	echo. >> unipatch-log.txt
)

rem Remove spaces from paths so it's easier to wrangle relative paths
set work_=!work: =█!
set dest_=!dest: =█!
set work_=!work_:"=!
set dest_=!dest_:"=!
set source_=!source: =█!
set source_=!source_:"=!

rem Extract actual unipname from path (regardless of absolute/relative)
for /F "tokens=*" %%g IN ('where !source!:*.info') do (set infopath=%%g)
for %%F in ("!infopath!") do set unipname=%%~nxF
set unipname=!unipname:.info=!
set unipname_=!unipname: =█!
set unipname=!unipname:-unip=!

if not exist !infopath! goto InvalidUnip

rem Read unip info file
set counter=0
for /F "usebackq tokens=*" %%A in ("!infopath!") do (
	if !counter! == 0 (set unipver=%%A)
	if !counter! == 1 (set uniptitle=%%A)
	if !counter! == 2 (set unipdesc=%%A)
	if !counter! == 3 (set unipreq_=%%A)
	set /a counter+=1
)

rem Check for version string
set "testver=!unipver:UNIP=!"
if  !testver! == !unipver! (
	goto InvalidUnip
)

if not %1 == s (
	echo !unipver!installer found^^!
)

echo.
echo !uniptitle!
echo ---------------------------------------
echo !unipdesc!

echo.


rem Check for dependencies
if "!unipreq_!" == "" (
	rem no dependencies
	if !mode! == read (
		if not %1 == s (
			echo OK.
		)
		goto End
	)
) else (
	if exist unipatch-installed.txt (
		set /p installedreq_=<unipatch-installed.txt
		set "installedreq=!installedreq_:█= !"
		set "unipreq=!unipreq_:█= !"
		
		echo requires : !unipreq!
		echo installed: !installedreq!
		echo.
		if !mode! == read (
			echo OK.
			goto End
		)
		rem get dependencies length
		echo !unipreq_!> unip-tmp.tmp
		for %%? in (unip-tmp.tmp) do ( set /A length=%%~z? - 2 )
		set length=-!length!
		del unip-tmp.tmp
		rem get last -length- characters of installed patches to see if they match
		call set teststring=%%installedreq_:~!length!%%
		if !teststring! == !unipreq_! (
			echo Last installed patches match prerequisites. Continuing.
			echo.
			goto InstallThis
		)
		set teststring=!installedreq_:%unipreq_%=!
		if not !teststring! == !installedreq_! (
			echo Stated dependencies are installed, but following patches may result in incompatibilities.
			set /P c=Do you want to try to run the installer anyway [Y/N]?
			if /I "!c!" EQU "Y" goto InstallThis
			if /I "!c!" EQU "N" goto End
			goto End
		)
		echo Cannot verify that stated dependencies are installed, or in compatible order.
		set /P c=Do you want to try to run the installer anyway [Y/N]?
		if /I "!c!" EQU "Y" goto InstallThis
		if /I "!c!" EQU "N" goto End
		goto End
	) else (
		set "unipreq=!unipreq_:█= !"
		echo requires : !unipreq!
		echo.
		if !mode! == read (
			echo OK.
			goto End
		)
		echo Stated dependencies don't appear to be installed.
		set /P c=Do you want to try to run the installer anyway [Y/N]?
		if /I "!c!" EQU "Y" goto InstallThis
		if /I "!c!" EQU "N" goto End
		goto End
	)
	echo.
)

:InstallThis

rem Main loop, iterate through files in destination directory
for /R %source%\ %%i in (*) do (
	set "fullpath=%%i"
	set "pathonly=%%~fi"
	set "filename=%%~nxi"
	set "extension=%%~xi"
	rem Replace spaces to make these easier to work with.
	set fullpath_=!fullpath: =█!
	set pathonly_=!pathonly: =█!
	set filename_=!filename: =█!
	rem Get relative sourcepath
	call:ReplaceText !pathonly_! !work_! "" relsourcepath_
	call:ReplaceText !relsourcepath_! !source_!\ "" relsourcepath_
	rem Make destination path
	set destpath_=!dest_!!relsourcepath_!
	
	rem echo !fullpath! turns into !relsourcepath_! leading to !destpath_!
	
	rem regenerate actual paths
	set "destpath=!destpath_:█= !"
	set "destpath=!destpath:.hdiff=!"
	set "relsourcepath=!relsourcepath_:█= !"
	
	rem Process only hdiff files.
	if !extension! == .hdiff (
		set fileok=0
		set skipbackup=0
		
		rem Create backup folder if it doesn't exist
		if not exist unip-backup\ ( mkdir unip-backup )
		
		rem Setup relative dest path
		set reldestpath=!relsourcepath:.hdiff=!
		rem Prepare extract path for later
		set "extractpath=!unipname!\!reldestpath!"
		set "extractpath_=!extractpath: =█!"
		
		rem Check if we're remapping
		set "filenamex_=!filename_:@=!"
		if not !filenamex_! == !filename_! (
			
			rem Skip backup for remaps, otherwise we might run into trouble later
			set skipbackup=1
			
			rem Read remap file
			for /F "tokens=*" %%g IN ('where !source!:*.remap') do (set remappath=%%g)
			if not exist !remappath! goto InvalidUnip
			for /F "usebackq tokens=*" %%A in ("!remappath!") do (
				rem Does this line have the current filename?
				echo.%%A| find /I "!relsourcepath_!">Nul && ( 
				  rem echo Found it^^! !relsourcepath_! is in %%A
				  rem Strip everything else from it.
				  set destpath_=%%A
				  set remove=!unipname_!\!relsourcepath_!
				  call:ReplaceText "!destpath_!" "!remove!" "" destpath_
				  rem clean up destpath_
				  set "destpath_=!destpath_: =!"
				  set "destpath=!destpath_:█= !"
				  rem get extractpath
				  set extractpath_=%%A
				  call:ReplaceText "!extractpath_!" "!destpath_!" "" extractpath_
				  set "extractpath_=!extractpath_: =!"
				  set "extractpath_=!extractpath_:-unip=!"
				  rem remap paths are relative, so use this one, sans extension.
				  set reldestpath=!destpath!
				  set destpath=!dest!!destpath!
				) 
			)
			
		) 
		
		rem Now check if source file exists
		if exist !destpath! (
			set fileok=1
		) else (
			rem Ignore missing files.
			echo Warning: !relsourcepath! not found in original files. Ignoring.
			echo WARNING: !relsourcepath! not found in original files. Ignoring. >> unipatch-log.txt
			set /a warncount+=1
		)
		
		rem Process file if ok
		if !fileok! == 1 (
			echo !mode!ing file !relsourcepath!...
			if !skipbackup! == 0 (
				if !mode! == install (
					rem Create backup path
					call:ReplaceText "!relsourcepath_!" "!filename_!" "" makepath_
					set "makepath=unip-backup\!makepath_:█= !"
					if not exist !makepath! ( mkdir "!makepath!" )
					rem Copy original file to safety, do not touch if it already exists
					if not exist unip-backup\!reldestpath! (
						echo backing up file !reldestpath!
						echo f | xcopy /f "!destpath!" "unip-backup\!reldestpath!" >> unipatch-log.txt
					)
				)
			)
			rem extract unip first regardless
			
			rem get actual path in the most horrible way
			call:DerivePath !extractpath_! extractpath_
			set "extractpath=!extractpath_:█= !"
			
			rem Get eventual destination path for check
			call:ReplaceText "!extractpath!" "!unipname!\" "" checkpath
			
			if !mode! == install ( set "extractpath=tmp-!extractpath_:█= !" )
			if not exist !extractpath! ( mkdir "!extractpath!" )
			rem actually diff the source files
			set "outputfile=!filenamex_:█= !"
			set "outputfile=!outputfile:.hdiff=!"
			bin\!OS!\hpatchz.exe -f "!destpath!" "!fullpath!" "!extractpath!!outputfile!" >> unipatch.tmp
			type unipatch.tmp >> unipatch-log.txt
			rem Did hdiffz succeed?
			>nul find "patch ok" unipatch.tmp && (
			  echo processed !reldestpath! successfully.
			) || (
			  echo ERROR in processing !reldestpath!, check unipatch-log.txt
			  echo ERROR in processing !reldestpath!. File probably does not match correct version. >> unipatch-log.txt
			  set /a errcount+=1
			)
			del unipatch.tmp
			
			if !mode! == install (
				rem if destination file doesn't exist, add it to delete queue for backup
				set checkfile=!checkpath!!outputfile!
				set checkfile_=!checkfile: =█!
				if not exist !checkfile! (
					echo !checkfile_! >> unip-backup\delete.log
				)
			)
		)
		
		
	) else if !extension! == .info (
		rem This is a unip file we ignore here
	) else if !extension! == .remap (
		rem This is a unip file we ignore here
	) else (
		rem Ignore files that aren't hdiff
		echo "Warning: !relsourcepath! is not a patch file. Ignoring.
		echo WARNING: !relsourcepath! is not a patch file. Ignoring. >> unipatch-log.txt
		set /a warncount+=1
	)
	

)

if !mode! == install (
	echo.
	echo copying files...
	rem Overwrite files if installing, then delete temp folder
	xcopy /s /f /y "tmp-!unipname!" "!dest!" >> unipatch-log.txt
	@rd /s /q "tmp-!unipname!"
	rem Add ID to installed log
	set unipname_=!unipname_:-unip=!
	set /p "=!unipname_! " < nul >> unipatch-installed.txt
)

echo.
echo Finished processing installer !unipname!-unip with !warncount! warnings and !errcount! errors.

goto End

:MissingParam
echo Missing parameters: run-unip.bat extract^|install unippath [destination] 
echo When unspecified, destination defaults to current directory.
goto End

:MissingDir
echo One or both of the specified directories do not exist.
goto End

:InvalidUnip
echo Input does not seem to be a valid unip folder.
goto End

:End
goto :eof

:ReplaceText
::Replace Text In String
:: call:ReplaceText "!OriginalText!" OldWordToReplace NewWordToUse  Result
set "OriginalText=%~1"
set "OldWord=%~2"
set "NewWord=%~3"
call set OriginalText=%%OriginalText:!OldWord!=!NewWord!%%
set %4=!OriginalText!
goto End

:DerivePath
::Strip characters from end of string until \
:: call:DerivePath "!String!" Result
set string=%~1
:OneAtATime
set checklast=%string:~-1%
if !checklast! == \ goto DoneHere
set string=!string:~0,-1!
goto OneAtATime
:DoneHere
set %2=!string!
goto End