/*
 * PurkdellApps Universal Launcher
 * Developer: DoomStorm
 */

;=== Constants
!define PORTABLEAPPNAME     "YouTube By Click Portable"
!define VER                 "1.0.0.0"
!define APPEXE              "YouTubeByClick.exe"
!define APPDIR              "YouTubeByClick"
!define DEFAULTSWITCH       ``
!define LAUNCHERLANGUAGE    "English"
!define PROGRESSWINDOW

;=== Make sure, we compile this with PAUL
!ifndef COMPILED_BY_PAUL
    !error "${__FILE__} cannot be compiled manually. Use PurkdellAppsCompiler.exe instead."
!endif

;=== Require at least NSIS 3.0
!include "${PAUL}\RequireLatestNSIS.nsh"

;=== Load all segments
!include "${PAUL}\Segments.nsh"

;=== Includes
!include Includes\nsisXML.nsh

;=== Variables
;(Default)
Var BASENAME
Var PORTABLEAPPNAME
Var APPNAME
Var APPID
Var ARCHITECTURE
Var APPDIRECTORY
Var DATADIRECTORY
Var PROGRAMDIRECTORY
!ifdef APPDIR64
    !if "${APPDIR64}" != ""
        Var PROGRAMDIRECTORY64
    !endif
!endif
Var SETTINGSDIRECTORY
Var DEFAULTDATADIRECTORY
Var PORTABLEAPPSPATH
Var TEMPDIRECTORY
Var LIVEDIRECTORY
Var CURRENTDRIVE
Var REGFILE
Var ACCOUNTTYPE
Var LASTDRIVE
Var LASTDIRECTORY
Var ADDITIONALPARAMETERS
Var PROGRAMEXECUTABLE
Var RUNLOCALLY
Var MUTEXSTRING
Var SECONDARYLAUNCH
Var EXECSTRING

;(Constants)
Var ALLUSERSDESKTOP
Var ALLUSERSSTARTMENU
Var ALLUSERSSMPROGRAMS
Var ALLUSERSSMSTARTUP
Var ALLUSERSDOCUMENTS
Var ALLUSERSFAVORITES
Var ALLUSERSMUSIC
Var ALLUSERSPICTURES
Var ALLUSERSVIDEOS
Var ALLUSERSTEMPLATES
Var ALLUSERSAPPDATA
Var ALLUSERSADMINTOOLS

;(Custom)
Var DOWNLOAD

!macro Custom
    ${SegmentStart}
    ${SegmentInit}
        ${ProgressMessage} "Checking for .NET Framework 4.6.2..." 10
        ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Release
        ${If}   $0 == ""
        ${OrIf} $0 < 394802 ; 4.6.2
            ${MessageBox} ${MB_OK}|${MB_ICONEXCLAMATION} "Make sure you have .NET Framework v4.6.2 or higher installed, before running $APPNAME."
            Abort
        ${EndIf}

        ${IfNot} ${IsDir} $SETTINGSDIRECTORY
        ${AndIf} ${IsDir} $DEFAULTDATADIRECTORY
            Delete $SETTINGSDIRECTORY
            CreateDirectory $SETTINGSDIRECTORY
            ${If} ${IsDirEmpty} $SETTINGSDIRECTORY
                CopyFiles /SILENT $DEFAULTDATADIRECTORY\*.* $SETTINGSDIRECTORY
            ${EndIf}
        ${EndIf}

        ;=== Userconfig options
        ${ReadUserConfigWithDefault} $DOWNLOAD DefaultDownloadFolder true
    ${SegmentPrePortable}
        ${ProgressMessage} "Setting up custom settings..." 20
        ${If} $DOWNLOAD == true
            ${IfNot} ${IsDir} $DATADIRECTORY\Downloads
                Delete $DATADIRECTORY\Downloads
                CreateDirectory $DATADIRECTORY\Downloads
            ${EndIf}
            ${WriteXMLText} $SETTINGSDIRECTORY\AppData\Configuration.dat "/AllConfiguration/Configuration/ChoosenFolder" "$DATADIRECTORY\Downloads" $0
        ${EndIf}
    ${SegmentUnload}
        ${ProgressMessage} "Remove log file(s)..." 20
        Push $0
        Push $1
        StrCpy $0 ""
        StrCpy $1 ""
        ${Do}
            ${If} $0 == ""
                FindFirst $0 $1 "$LOCALAPPDATA\Microsoft\*"
            ${Else}
                FindNext $0 $1
            ${EndIf}
            ${IfThen} $1 == "" ${|} ${ExitDo} ${|}
            ${IfThen} $1 == . ${|} ${Continue} ${|}
            ${IfThen} $1 == .. ${|} ${Continue} ${|}
            ${If} ${IsFile} $LOCALAPPDATA\Microsoft\$1\UsageLogs\$BASENAME.exe.log
                Delete $LOCALAPPDATA\Microsoft\$1\UsageLogs\*.log
            ${ElseIf} ${IsDir} $LOCALAPPDATA\Microsoft\$1\UsageLogs
                RMDir $LOCALAPPDATA\Microsoft\$1\UsageLogs
            ${ElseIf} ${IsDir} $LOCALAPPDATA\Microsoft\$1
                RMDir $LOCALAPPDATA\Microsoft\$1
            ${EndIf}
        ${Loop}
        FindClose $0
        Pop $1
        Pop $0
    ${SegmentEnd}
!macroend

!macro Directory
    ${SegmentStart}
    ${SegmentPreLocal}
        ${ProgressMessage} "Backup local directory..." 10
        ${BackupDirectory} $APPDATA\YouTubeByClick
    ${SegmentPrePortable}
        ${ProgressMessage} "Restore portable directory..." 10
        ${MoveDirectoryBack} $SETTINGSDIRECTORY\AppData $APPDATA\YouTubeByClick
    ${SegmentPostPortable}
        ${ProgressMessage} "Backup portable directory..." 10
        ${PreserveDirectory} $SETTINGSDIRECTORY\AppData $APPDATA\YouTubeByClick
    ${SegmentPostLocal}
        ${ProgressMessage} "Restore local directory..." 10
        ${RestoreDirectory} $APPDATA\YouTubeByClick
    ${SegmentCleanUp}
        ${ProgressMessage} "Remove left-over directories..." 10
        RMDir $APPDATA\YouTubeByClick
    ${SegmentEnd}
!macroend

!macro Language
    ${SegmentStart}
    ${SegmentInit}
        Var /GLOBAL SYSTEMLANGUAGE
        ${ReadUserConfigWithDefault} $SYSTEMLANGUAGE UseSystemLanguage true
    ${SegmentPrePortable}
        ${If} ${PrimaryInstance}
            Var /GLOBAL APPLANGUAGE
            Var /GLOBAL DEFAULTAPPLANGUAGE

            StrCpy $0 ""

            ; Did we run from the PortableApps.com Platform?
            ${GetProcessParent} $EXEFILE $R0
            ${GetProcessPath} $R0 $R0
            ${If} $R0 == $PORTABLEAPPSPATH\PortableApps.com\PortableAppsPlatform.exe
            ${AndIf} ${IsFile} $R0
                ; If so, then get the language code from
                ; the PortableApps.com Platform
                ReadEnvStr $0 PortableApps.comLocaleID
            ${Else}
                ; We're not running from the PortableApps.com Platform,
                ; let's get the language code from the system
                ${If} $SYSTEMLANGUAGE == true
                    System::Call kernel32::GetUserDefaultLangID()i.s
                    Pop $0
                ${EndIf}
            ${EndIf}

            StrCpy $DEFAULTAPPLANGUAGE eng ; English (Default)

            ; Find correct language
            ${Select} $0
                ${Case} ""
                    Nop
                ${Case} 1025
                    StrCpy $APPLANGUAGE ara ; Arabic
                ${Case} 1050
                    StrCpy $APPLANGUAGE hrv ; Croatian
                ${Case} 1029
                    StrCpy $APPLANGUAGE ces ; Czech
                ${Case} 1124
                    StrCpy $APPLANGUAGE fil ; Filipino
                ${Case} 1036
                    StrCpy $APPLANGUAGE fra ; French
                ${Case} 1031
                    StrCpy $APPLANGUAGE deu ; German
                ${Case} 1043
                    StrCpy $APPLANGUAGE nld ; Dutch
                ${Case} 1038
                    StrCpy $APPLANGUAGE hun ; Hungarian
                ${Case} 1041
                    StrCpy $APPLANGUAGE jpn ; Japanese
                ${Case} 1040
                    StrCpy $APPLANGUAGE ita ; Italian
                ${Case} 1042
                    StrCpy $APPLANGUAGE kor ; Korean
                ${Case} 1044
                    StrCpy $APPLANGUAGE nor ; Norwegian
                ${Case} 1045
                    StrCpy $APPLANGUAGE pol ; Polish
                ${Case} 1046
                    StrCpy $APPLANGUAGE por ; Portugese
                ${Case} 1048
                    StrCpy $APPLANGUAGE ron ; Romanian
                ${Case} 1053
                    StrCpy $APPLANGUAGE swe ; Swedish
                ${Case} 1049
                    StrCpy $APPLANGUAGE rus ; Russian
                ${Case} 1055
                    StrCpy $APPLANGUAGE tur ; Turkish
                ${Case} 2052
                    StrCpy $APPLANGUAGE zho ; Chinese (Simplified, China)
                ${Case} 1028
                    StrCpy $APPLANGUAGE zh2 ; Chinese (Traditional, Taiwan)
                ${Case} 1054
                    StrCpy $APPLANGUAGE tha ; Thai
                ${Default}
                    StrCpy $APPLANGUAGE $DEFAULTAPPLANGUAGE
            ${EndSelect}

            ${If} $APPLANGUAGE != ""
                ; Compare app language
                ${ReadXMLText} $SETTINGSDIRECTORY\AppData\Configuration.dat "/AllConfiguration/Configuration/Lang" $R0
                ${If} $APPLANGUAGE != $R0 ; skip if the same
                    ; Set the language
                    ${WriteXMLText} $SETTINGSDIRECTORY\AppData\Configuration.dat "/AllConfiguration/Configuration/Lang" "$APPLANGUAGE" $0
                ${EndIf}
            ${EndIf}
        ${EndIf} ; ${PrimaryInstance}
    ${SegmentPreLaunch}
        ${If} ${PrimaryInstance}
            ;=== Enter some actions if necessary
        ${EndIf} ; ${PrimaryInstance}
    ${SegmentEnd}
!macroend

!macro RememberPaths
    ${WriteLauncherSettings} LastDrive $CURRENTDRIVE
    ${WriteLauncherSettings} LastDirectory $EXEDIR
!macroend

!macro ExecString
    ${SegmentStart}
    ${SegmentInit}
        ${ReadUserConfigWithDefault} $ADDITIONALPARAMETERS AdditionalParameters ""
    ${SegmentPreLaunch}
        ; Set the default value
        StrCpy $EXECSTRING `"$PROGRAMDIRECTORY\$PROGRAMEXECUTABLE"`

        ; Default command line switch
        !ifdef DEFAULTSWITCH
        StrCpy $EXECSTRING "$EXECSTRING ${DEFAULTSWITCH}"
        !endif

        ; Get any passed parameters
        ${GetParameters} $0
        ${If} $0 != ""
            StrCpy $EXECSTRING "$EXECSTRING $0"
        ${EndIf}

        ; Add some additional parameters from the user configuration file
        ${If} $ADDITIONALPARAMETERS != ""
            StrCpy $EXECSTRING "$EXECSTRING $ADDITIONALPARAMETERS"
        ${EndIf}
    ${SegmentEnd} ;}}}2
!macroend

!macro Temp
    ${SegmentStart}
    ${SegmentInit}
        ${RemoveDirectory} $TEMPDIRECTORY
        CreateDirectory $TEMPDIRECTORY
    ${SegmentPreLaunch}
        ${SetEnvironmentVariable} TEMP $TEMPDIRECTORY
        ${SetEnvironmentVariable} TMP $TEMPDIRECTORY
    ${SegmentCleanUp}
        ${RemoveDirectory} $TEMPDIRECTORY
    ${SegmentEnd}
!macroend

!macro WorkingDirectory
    ${SegmentStart}
    ${SegmentPreLaunch}
        SetOutPath $PROGRAMDIRECTORY
    ${SegmentCleanUp}
        ; Move-out current working directory
        SetOutPath $TEMP
    ${SegmentEnd}
!macroend

!macro Launch
    ${SegmentStart}
    ${SegmentInit}
        ${ReadUserConfigWithDefault} $PROGRAMEXECUTABLE ProgramExecutable "${APPEXE}"
        !ifdef RUNASADMIN & NONELEVATED
        Delete $APPDIRECTORY\Bin\appexecutor.ini ; be sure there's no another copy
        !endif
    ${SegmentLaunchPrimary}
        !insertmacro _Launch_Start
        ExecWait $EXECSTRING
        !insertmacro _Launch_End
    ${SegmentEnd}
!macroend

!macro _Launch_Start
!ifdef RUNASADMIN & NONELEVATED
    ${ReadUserConfigWithDefault} $R0 ExecAsAdmin false
    ${If} $R0 == true
!endif
!macroend

!macro _Launch_End
!ifdef RUNASADMIN & NONELEVATED
    ${Else}
        ; Get the parameter without program executable and its path
        ${WordReplace} $EXECSTRING `"$PROGRAMDIRECTORY\$PROGRAMEXECUTABLE" ` "" + $0 ; if input string can't be found: result == input
        ${If} $0 == $EXECSTRING ; replace again if no replacement been made
            ${WordReplace} $0 `"$PROGRAMDIRECTORY\$PROGRAMEXECUTABLE"` "" + $0 ; if replacement been made, this instruction will not be executed
        ${EndIf}

        ; Execute app as non-elevated
        ${WriteINIStr} $APPDIRECTORY\Bin\appexecutor.ini Executable Path $PROGRAMDIRECTORY\$PROGRAMEXECUTABLE
        ${WriteINIStr} $APPDIRECTORY\Bin\appexecutor.ini Executable Parameters $0
        Push $APPDIRECTORY\Bin\appexecutor.exe
        Push ""
        Push ""
        StdUtils::ExecShellAsUser /NOUNLOAD
        Pop $R0
    ${EndIf}
!endif
!macroend ;}}}2

!macro LaunchAndExit
    !insertmacro _Launch_Start
    Exec $EXECSTRING
    !insertmacro _Launch_End
!macroend

!macro CheckRunning
    !insertmacro _CheckRunning_Start

    !insertmacro _CheckRunning_WaitProcess ""
    !insertmacro _CheckRunning_WaitProcess $PROGRAMEXECUTABLE
;    !insertmacro _CheckRunning_WaitProcess Process.exe
;    !insertmacro _CheckRunning_WaitProcess "${APPEXEPARAMETERS}"

    !insertmacro _CheckRunning_FindProcess ""
    !insertmacro _CheckRunning_FindProcess $PROGRAMEXECUTABLE
;    !insertmacro _CheckRunning_FindProcess Process.exe
;    !insertmacro _CheckRunning_FindProcess "${APPEXEPARAMETERS}"
!macroend

!macro _CheckRunning_WaitProcess _process
!if `${_process}` == ""
    ${If} $PROGRAMEXECUTABLE != "${APPEXE}"
        FindProcDLL::WaitProcEnd "${APPEXE}" -1
    ${EndIf}
    !ifdef APPEXE64
    ${If} $PROGRAMEXECUTABLE != "${APPEXE64}"
        FindProcDLL::WaitProcEnd "${APPEXE64}" -1
    ${EndIf}
    !endif
!else
    FindProcDLL::WaitProcEnd `${_process}` -1
!endif
!macroend

!macro _CheckRunning_FindProcess _process
!if `${_process}` == ""
    StrCmp $PROGRAMEXECUTABLE "${APPEXE}" +3
        FindProcDLL::FindProc "${APPEXE}"
        StrCmp $R0 1 _CheckRunning_Label
    !ifdef APPEXE64
    StrCmp $PROGRAMEXECUTABLE "${APPEXE64}" +3
        FindProcDLL::FindProc "${APPEXE64}"
        StrCmp $R0 1 _CheckRunning_Label
    !endif
!else
    FindProcDLL::FindProc `${_process}`
    StrCmp $R0 1 _CheckRunning_Label
!endif
!macroend

!macro _CheckRunning_Start
    Var /GLOBAL _CheckRunning_Wait
    StrCpy $_CheckRunning_Wait false
    !ifdef RUNASADMIN & NONELEVATED
    Sleep 2000
    !endif
    _CheckRunning_Label:
        StrCmp $_CheckRunning_Wait true "" +2
        Sleep 2000
        StrCpy $_CheckRunning_Wait true
!macroend ;}}}2

!macro UnpinFromTaskbar
    ; Unpin from the taskbar if previously were pinned by user
    ${UnpinFromTaskbar} $PROGRAMDIRECTORY\$PROGRAMEXECUTABLE
!macroend

!macro InstanceManagement
    ;=== Create a mutex so we can determine if this specific launcher is already running
        ${WordReplace} $EXEDIR "\" "-" "+" $0
        StrCpy $MUTEXSTRING $0-$BASENAME
        Push "$MUTEXSTRING"
        System::Call kernel32::CreateMutex(i0,i0,ts)?e
        Pop $0
        ${If} $0 = 0
            ; Check for local copy
            ${If} ${ProcessExists} "${APPEXE}"
            !ifdef APPEXE64
            ${OrIf} ${ProcessExists} "${APPEXE64}"
            !endif
                ${MessageBox} ${MB_ICONINFORMATION} "Another instance of $APPNAME is already running. Please close other instances of $APPNAME before launching $PORTABLEAPPNAME."
                Goto TheEnd
            ${EndIf}
        ${Else}
            ; Launcher is already running, so we'll continue to just launch
            ; secondary instance without any initialization and just closing
            ; without waiting after it has been launched
            StrCpy $SECONDARYLAUNCH true
        ${EndIf}
!macroend

!macro OpenMutex
    ;=== Check if already starting
        Push "$MUTEXSTRING::Starting"
        System::Call kernel32::OpenMutex(i1048576,b0,ts)i.r0?e
        System::Call kernel32::CloseHandle(ir0)
        Pop $0
        ${If} $0 <> 2
            ${MessageBox} ${MB_ICONINFORMATION} "Another instance of $PORTABLEAPPNAME is starting. Please wait for it to start before launching it again."
            Goto TheEnd
        ${EndIf}

    ;=== Check if already stopping
        Push "$MUTEXSTRING::Stopping"
        System::Call kernel32::OpenMutex(i1048576,i0,ts)i.r0?e
        System::Call kernel32::CloseHandle(ir0)
        Pop $0
        ${If} $0 <> 2
            ${MessageBox} ${MB_ICONINFORMATION} "Another instance of $PORTABLEAPPNAME is currently closing. Please wait for it to finish before launching it again."
            Goto TheEnd
        ${EndIf}
!macroend

!macro CheckProgramExecutable
    ${IfNot} ${IsFile} $PROGRAMDIRECTORY\$PROGRAMEXECUTABLE
        ; Program executable not where expected
        ${MessageBox} ${MB_ICONEXCLAMATION} "Could not find $PROGRAMDIRECTORY\$PROGRAMEXECUTABLE. Re-extracting might fix this issue."
        Goto TheEnd
    ${EndIf}
!ifdef RUNASADMIN & NONELEVATED
    ; Be sure our helper is present
    ${IfNot} ${IsFile} $APPDIRECTORY\Bin\appexecutor.exe
        ${MessageBox} ${MB_ICONEXCLAMATION} "Could not find $APPDIRECTORY\Bin\appexecutor.exe. Re-extracting might fix this issue."
        Goto TheEnd
    ${EndIf}
!endif
!macroend

!macro OperatingSystem
    ; Check if we are running on the right operating system
    StrCpy $0 good-os
    ${If} ${IsNT}
        ${IfNot} ${AtLeastWinXP}
            StrCpy $0 bad-os
        ${EndIf}
    ${Else}
        StrCpy $0 bad-os
    ${EndIf}
    ${If} $0 == bad-os
        ${MessageBox} ${MB_ICONSTOP} "$APPNAME requires Windows XP or later to run. You are running on Windows that is older than required, so $APPNAME can not be started."
        Goto TheEnd
    ${EndIf}
!macroend

;=== Load core things {{{1
!include "${PAUL}\Core.nsh"
