; === Languages ===
LoadLanguageFile "${NSISDIR}\Contrib\Language files\English.nlf"

; === Program Details ===
Caption "${APPNAME} Portable"
VIProductVersion "${APPVER}"
VIAddVersionKey /LANG=${LANG_ENGLISH} BuildDate "${BUILDDATE} ${__TIME__}"
VIAddVersionKey /LANG=${LANG_ENGLISH} ProductName "${APPNAME} Portable"
VIAddVersionKey /LANG=${LANG_ENGLISH} Comments "Allows ${APPNAME} to be run from a removable drive."
VIAddVersionKey /LANG=${LANG_ENGLISH} CompanyName "${COPYRIGHT}"
VIAddVersionKey /LANG=${LANG_ENGLISH} LegalCopyright "${COPYRIGHT}"
VIAddVersionKey /LANG=${LANG_ENGLISH} FileDescription "${APPNAME} Portable"
VIAddVersionKey /LANG=${LANG_ENGLISH} FileVersion "${APPVER}"
VIAddVersionKey /LANG=${LANG_ENGLISH} ProductVersion "${VER}"
VIAddVersionKey /LANG=${LANG_ENGLISH} InternalName "${APPNAME}"
VIAddVersionKey /LANG=${LANG_ENGLISH} LegalTrademarks ""
VIAddVersionKey /LANG=${LANG_ENGLISH} OriginalFilename "${APP}Portable.exe"

; === Runtime Switches ===
XPStyle on
CRCCheck on
WindowIcon off
SilentInstall silent
AutoCloseWindow true
!ifndef RUNASADMIN
	RequestExecutionLevel user
!else
	RequestExecutionLevel admin
!endif

; === Include ===
!include TextFunc.nsh
!insertmacro GetParameters
!include FileFunc.nsh
!insertmacro GetRoot
!include LogicLib.nsh
!include Include\SystemMessageBox.nsh

; === Default Variables ===
Var PROGRAMDIR
!ifdef APPDIR64
	Var PROGRAMDIR64
!endif
Var PROGRAMEXE
!ifdef APPEXE64
	Var PROGRAMEXE64
!endif
Var DEFAULTDATA
Var SETTINGSDIR
Var PARAMETERS
Var PARENTDIR
Var ROOTDIR
Var LASTDRIVE
Var LASTDIR
Var LANGID
Var TEMPDIR
Var ARCHITECTURE
Var COMPUTERID
Var PROGRAMSWITCH

Function DefaultVar
	; === Set Program Directory ===
	StrCpy $PROGRAMDIR "$EXEDIR\App\${APPDIR}"

	; === Set Program Directory (x64) ===
	!ifdef APPDIR64
		StrCpy $PROGRAMDIR64 "$EXEDIR\App\${APPDIR64}"
	!endif

	; === Set Program Executable ===
	StrCpy $PROGRAMEXE "${APPEXE}"

	; === Set Program Executable (x64) ===
	!ifdef APPEXE64
		StrCpy $PROGRAMEXE64 "${APPEXE64}"
	!endif

	; === Set Default Data ===
	StrCpy $DEFAULTDATA "$EXEDIR\App\DefaultData\${APPDIR}"

	; === Set Settings Directory ===
	StrCpy $SETTINGSDIR "$EXEDIR\Data\${APPDIR}"

	; === Get any passed parameters and set Parameters ===
	${GetParameters} $PARAMETERS

	; === Get and set Parent Directory ===
	${GetParent} "$EXEDIR" $PARENTDIR

	; === Get root directory and set Root Directory and Last Drive ===
	${GetRoot} "$EXEDIR" $ROOTDIR
	ReadINIStr $LASTDRIVE "$EXEDIR\Data\${APP}Portable.ini" "${APP}Portable" "LastDrive"

	; === Set Last Directory ===
	ReadINIStr $LASTDIR "$EXEDIR\Data\${APP}Portable.ini" "${APP}Portable" "LastDirectory"

	; === Set User Default Lang ===
	System::Call `kernel32::GetUserDefaultLangID() i .r0`
	StrCpy $LANGID $0

	; === Set Portable App Temp ===
	StrCpy $TEMPDIR "$TEMP\${APP}PortableTemp"

	; === Set Architecture ===
	System::Call `kernel32::GetCurrentProcess()i.s`
	System::Call `kernel32::IsWow64Process(is,*i.s)`
	Pop $0
	StrCmp $0 "0" "" +2
		StrCpy $ARCHITECTURE "x86"
	StrCmp $0 "1" "" +2
		StrCpy $ARCHITECTURE "x64"

	; === Set Computer ID ===
	${GetRoot} "$WINDIR" $0
	System::Call `kernel32::GetVolumeInformation(t,t,i,*i,*i,*i,t,i) i("$0\",,${NSIS_MAX_STRLEN},.r1,,,,${NSIS_MAX_STRLEN})` ; get computer id
	StrCpy $COMPUTERID $1

	; === Set Program Switch ===
	!ifdef APPSWITCH
		StrCpy $PROGRAMSWITCH `${APPSWITCH}`
	!else
		StrCpy $PROGRAMSWITCH ""
	!endif
FunctionEnd

Function CheckStart
	; === Check program executable ===
	!ifndef CUSTOMCHECKPROGRAMEXE
		IfFileExists "$PROGRAMDIR\$PROGRAMEXE" FoundProgramEXE NoProgramEXE
		NoProgramEXE:
			${System::MessageBox} "${MB_OK}|${MB_ICONSTOP}" "Program executable not found" "Could not find $PROGRAMEXE in $PROGRAMDIR." $0
			Abort
		FoundProgramEXE:
	!else
		Call CheckProgramEXE
	!endif

	; === Check if launcher or app is still running ===
	!ifndef CUSTOMCHECKRUNEXE
		ReadINIStr $0 "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "AllowMultipleInstances"
		StrCmp $0 "" "" +2
			WriteINIStr "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "AllowMultipleInstances" "false"
		!ifdef NSIS_UNICODE
			System::Call `kernel32::CreateMutexW(i 0, i 0, t "$(^Name)") i .r1 ?e` ; check if launcher is already running
		!else
			System::Call `kernel32::CreateMutexA(i 0, i 0, t "$(^Name)") i .r1 ?e` ; check if launcher is already running
		!endif
		Pop $1
		StrCmp $1 "0" LauncherNotRunning LauncherAlreadyRunning
		LauncherAlreadyRunning:
			StrCmp $0 "true" RunAppAgain ShowMessageLauncherAlreadyRunning
			ShowMessageLauncherAlreadyRunning:
				FindWindow $0 "" "App is running"
				System::Call `user32::GetWindowText(i r0, t .r1, i r0) i.`
				StrCmp $1 "App is running" AppAlreadyRunning
					${System::MessageBox} "${MB_OK}|${MB_ICONINFORMATION}" "Launcher already running" "${APPNAME} Portable is already running." $0
					Abort
			RunAppAgain:
				FindWindow $0 "" "App is running"
				System::Call `user32::GetWindowText(i r0, t .r1, i r0) i.`
				StrCmp $1 "App is running" AppAlreadyRunning
					FindProcDLL::FindProc "$PROGRAMEXE"
					StrCmp $R0 "1" "" CheckRunEXEEnd
						SetOutPath "$PROGRAMDIR"
						ClearErrors
						ReadINIStr $0 "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "ExecAsAdmin"
						IfErrors +5
						StrCmp $0 "" +4
						StrCmp $0 "true" +3
							StdUtils::ExecShellAsUser /NOUNLOAD `$PROGRAMSWITCH $PARAMETERS` "" "$PROGRAMDIR\$PROGRAMEXE"
							Goto +2
						Exec `"$PROGRAMDIR\$PROGRAMEXE"$PROGRAMSWITCH $PARAMETERS`
						Abort
		LauncherNotRunning:
			FindProcDLL::FindProc "$PROGRAMEXE"
			StrCmp $R0 "1" AppAlreadyRunning CheckRunEXEEnd
			AppAlreadyRunning:
				${System::MessageBox} "${MB_OK}|${MB_ICONINFORMATION}" "App is running" "Another instances of ${APPNAME} is already running.$\nPlease close other instances of ${APPNAME} before running ${APPNAME} Portable." $0
				Abort
		CheckRunEXEEnd:
	!else
		Call CheckRunEXE
	!endif

	; === Check good or bad exit ===
	ReadINIStr $0 "$EXEDIR\Data\${APP}PortableRuntimeData.ini" "${APP}Portable" "Status"
	StrCmp $0 "running" "" CheckGoodOrBadExitEnd
		${System::MessageBox} "${MB_OKCANCEL}|${MB_ICONEXCLAMATION}" "Bad exit" "Last exit of ${APPNAME} Portable did not restore settings.$\nWould you try to restore local and backup portable settings now?" $0
		StrCmp $0 "1" "" CheckGoodOrBadExitEnd ; if user click OK
			ReadINIStr $0 "$EXEDIR\Data\${APP}PortableRuntimeData.ini" "${APP}Portable" "PluginsDir"
				RMDir "/r" "$0"
			Call Close
	CheckGoodOrBadExitEnd:
FunctionEnd

Var RUNTIMEDATA
Function RuntimeData
	CreateDirectory "$EXEDIR\Data"
		WriteINIStr "$EXEDIR\Data\${APP}Portable.ini" "${APP}Portable" "LastDrive" "$ROOTDIR" ; store current drive letter
		WriteINIStr "$EXEDIR\Data\${APP}Portable.ini" "${APP}Portable" "LastDirectory" "$EXEDIR" ; store current directory
	SetFileAttributes "$EXEDIR\Data\${APP}Portable.ini" HIDDEN
		WriteINIStr "$EXEDIR\Data\${APP}PortableRuntimeData.ini" "${APP}Portable" "PluginsDir" "$PLUGINSDIR" ; store plugins dir
		WriteINIStr "$EXEDIR\Data\${APP}PortableRuntimeData.ini" "${APP}Portable" "Status" "running" ; store status
	FileOpen $RUNTIMEDATA "$EXEDIR\Data\${APP}PortableRuntimeData.ini" r ; lock file!
FunctionEnd

; Function SplashScreen
	; ReadINIStr $0 "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "DisableSplashScreen"
	; StrCmp $0 "" "" +2
		; WriteINIStr "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "DisableSplashScreen" "false"
	; ClearErrors
	; ReadINIStr $1 "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "SplashScreenName"
	; IfErrors "" +2
		; WriteINIStr "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "SplashScreenName" ""
	; StrCmp $0 "true" SplashScreenEnd ; skip splash screen
	; StrCmp $1 "" ShowDefaultSplashScreen CustomSplashScreen
	; ShowDefaultSplashScreen:
		; InitPluginsDir
		; File "/oname=$PLUGINSDIR\PortableApp" "Include\splash.bmp"
		; newadvsplash::show /NOUNLOAD 1000 300 200 0xFF00FF /L "$PLUGINSDIR\PortableApp"
		; Delete "$PLUGINSDIR\PortableApp"
		; Goto SplashScreenEnd
	; CustomSplashScreen:
		; IfFileExists "$EXEDIR\Data\$1.bmp" ShowCustomSplashScreen ShowDefaultSplashScreen
		; ShowCustomSplashScreen:
			; newadvsplash::show /NOUNLOAD 1000 300 200 0xFF00FF /L "$EXEDIR\Data\$1.bmp"
	; SplashScreenEnd:
; FunctionEnd
