!include "LogicLib.nsh"

!define LEGACY_APP_GUID "3a51f54f-dd33-55a2-a302-8f716620a296"
!define LEGACY_INSTALL_KEY "Software\${LEGACY_APP_GUID}"
!define LEGACY_UNINSTALL_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${LEGACY_APP_GUID}"
!define LEGACY_UNINSTALL_KEY_WOW64 "Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\${LEGACY_APP_GUID}"

Var OldInstallDir
Var OldBundleDir
Var BundleBackupDir
Var UpgradePreparationDone

Function LegacyGetInQuotes
  Exch $R0
  Push $R1
  Push $R2
  Push $R3

   StrCpy $R2 -1
   IntOp $R2 $R2 + 1
    StrCpy $R3 $R0 1 $R2
    StrCmp $R3 "" 0 +3
     StrCpy $R0 ""
     Goto legacy_get_in_quotes_done
    StrCmp $R3 '"' 0 -5

   IntOp $R2 $R2 + 1
   StrCpy $R0 $R0 "" $R2

   StrCpy $R2 0
   IntOp $R2 $R2 + 1
    StrCpy $R3 $R0 1 $R2
    StrCmp $R3 "" 0 +3
     StrCpy $R0 ""
     Goto legacy_get_in_quotes_done
    StrCmp $R3 '"' 0 -5

   StrCpy $R0 $R0 $R2
   legacy_get_in_quotes_done:

  Pop $R3
  Pop $R2
  Pop $R1
  Exch $R0
FunctionEnd

Function LegacyGetFileParent
  Exch $R0
  Push $R1
  Push $R2
  Push $R3

  StrCpy $R1 0
  StrLen $R2 $R0

  legacy_get_parent_loop:
    IntOp $R1 $R1 + 1
    IntCmp $R1 $R2 legacy_get_parent_done 0 legacy_get_parent_done
    StrCpy $R3 $R0 1 -$R1
    StrCmp $R3 "\" legacy_get_parent_done
  Goto legacy_get_parent_loop

  legacy_get_parent_done:
    StrCpy $R0 $R0 -$R1

    Pop $R3
    Pop $R2
    Pop $R1
    Exch $R0
FunctionEnd

Function ResolveLegacyInstallDirFromUninstallString
  Exch $0
  Push $1
  Push $2

  StrCpy $1 ""
  ${If} $0 == ""
    Goto resolve_legacy_dir_done
  ${EndIf}

  StrCpy $2 $0 1
  ${If} $2 == '"'
    Push $0
    Call LegacyGetInQuotes
    Pop $1
  ${Else}
    StrCpy $1 $0
  ${EndIf}

  ${If} $1 != ""
    Push $1
    Call LegacyGetFileParent
    Pop $1
  ${EndIf}

  resolve_legacy_dir_done:
  Pop $2
  Exch $1
FunctionEnd

Function ApplyLegacyInstallDirCandidate
  Exch $0

  ${If} $0 != ""
  ${AndIf} ${FileExists} "$0\*.*"
    StrCpy $OldInstallDir "$0"
    StrCpy $OldBundleDir "$OldInstallDir\resources-bundles"
    StrCpy $INSTDIR "$OldInstallDir"
  ${EndIf}

  Exch $0
FunctionEnd

Function ResolveLegacyInstallDir
  ${If} $OldInstallDir != ""
  ${AndIf} ${FileExists} "$OldInstallDir\*.*"
    StrCpy $INSTDIR "$OldInstallDir"
    Return
  ${EndIf}

  StrCpy $OldInstallDir ""
  StrCpy $OldBundleDir ""

  ReadRegStr $0 HKCU "${LEGACY_INSTALL_KEY}" "InstallLocation"
  Push $0
  Call ApplyLegacyInstallDirCandidate
  Pop $0
  ${If} $OldInstallDir == ""
    ReadRegStr $0 HKLM "${LEGACY_INSTALL_KEY}" "InstallLocation"
    Push $0
    Call ApplyLegacyInstallDirCandidate
    Pop $0
  ${EndIf}

  ${If} $OldInstallDir == ""
    ReadRegStr $0 HKCU "${LEGACY_UNINSTALL_KEY}" "InstallLocation"
    Push $0
    Call ApplyLegacyInstallDirCandidate
    Pop $0
  ${EndIf}
  ${If} $OldInstallDir == ""
    ReadRegStr $0 HKLM "${LEGACY_UNINSTALL_KEY}" "InstallLocation"
    Push $0
    Call ApplyLegacyInstallDirCandidate
    Pop $0
  ${EndIf}
  ${If} $OldInstallDir == ""
    ReadRegStr $0 HKLM "${LEGACY_UNINSTALL_KEY_WOW64}" "InstallLocation"
    Push $0
    Call ApplyLegacyInstallDirCandidate
    Pop $0
  ${EndIf}

  ${If} $OldInstallDir == ""
    ReadRegStr $0 HKCU "${LEGACY_UNINSTALL_KEY}" "UninstallString"
    Push $0
    Call ResolveLegacyInstallDirFromUninstallString
    Pop $0
    Push $0
    Call ApplyLegacyInstallDirCandidate
    Pop $0
  ${EndIf}
  ${If} $OldInstallDir == ""
    ReadRegStr $0 HKLM "${LEGACY_UNINSTALL_KEY}" "UninstallString"
    Push $0
    Call ResolveLegacyInstallDirFromUninstallString
    Pop $0
    Push $0
    Call ApplyLegacyInstallDirCandidate
    Pop $0
  ${EndIf}
  ${If} $OldInstallDir == ""
    ReadRegStr $0 HKLM "${LEGACY_UNINSTALL_KEY_WOW64}" "UninstallString"
    Push $0
    Call ResolveLegacyInstallDirFromUninstallString
    Pop $0
    Push $0
    Call ApplyLegacyInstallDirCandidate
    Pop $0
  ${EndIf}

  ${If} $OldInstallDir != ""
    DetailPrint "Legacy install dir: $OldInstallDir"
  ${EndIf}
FunctionEnd

Function ClearLegacyRegistry
  DeleteRegKey HKCU "${LEGACY_UNINSTALL_KEY}"
  DeleteRegKey HKLM "${LEGACY_UNINSTALL_KEY}"
  DeleteRegKey HKLM "${LEGACY_UNINSTALL_KEY_WOW64}"
  DeleteRegKey HKCU "${LEGACY_INSTALL_KEY}"
  DeleteRegKey HKLM "${LEGACY_INSTALL_KEY}"
FunctionEnd

Function RemoveDirectoryDeep
  Exch $0

  ${If} $0 == ""
    Return
  ${EndIf}

  ClearErrors
  RMDir /r "$0"
  ClearErrors
  nsExec::ExecToLog '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "$$target = ''\\?\'' + [System.IO.Path]::GetFullPath(''$0''); try { Remove-Item -LiteralPath $$target -Recurse -Force -ErrorAction Stop } catch {}"'
  Pop $1

  Exch $0
FunctionEnd

Function KillDirectAppProcesses
  nsExec::ExecToLog 'taskkill /F /IM "${PRODUCT_FILENAME}.exe" /T'
  Pop $0
  nsExec::ExecToLog 'taskkill /F /IM "SC-IP-Agent.exe" /T'
  Pop $0
  nsExec::ExecToLog 'taskkill /F /IM "尚创IP智能体V8.exe" /T'
  Pop $0
FunctionEnd

Function KillProcessesUnderLegacyInstall
  Call KillDirectAppProcesses

  ${If} $OldInstallDir == ""
    Return
  ${EndIf}

  DetailPrint "Closing processes under $OldInstallDir"
  nsExec::ExecToLog '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "$$root = [System.IO.Path]::GetFullPath(''$OldInstallDir''); Get-Process -ErrorAction SilentlyContinue | Where-Object { try { $$path = $$_.Path; if (-not $$path) { return $$false }; [System.IO.Path]::GetFullPath($$path).StartsWith($$root, [System.StringComparison]::OrdinalIgnoreCase) } catch { $$false } } | ForEach-Object { try { Stop-Process -Id $$_.Id -Force -ErrorAction Stop } catch {} }"'
  Pop $0
  Sleep 1200

  Call KillDirectAppProcesses
  Sleep 800
FunctionEnd

Function BackupLegacyResourceBundles
  ${If} $OldBundleDir == ""
    Return
  ${EndIf}

  StrCpy $BundleBackupDir "$OldInstallDir.__resources-bundles-backup"
  ${If} ${FileExists} "$BundleBackupDir\*.*"
    ${IfNot} ${FileExists} "$OldBundleDir\*.*"
      DetailPrint "Reusing preserved resource bundles from $BundleBackupDir"
      Return
    ${EndIf}
  ${EndIf}

  ${IfNot} ${FileExists} "$OldBundleDir\*.*"
    Return
  ${EndIf}

  Push "$BundleBackupDir"
  Call RemoveDirectoryDeep

  DetailPrint "Preserving resource bundles to $BundleBackupDir"
  Rename "$OldBundleDir" "$BundleBackupDir"
  ${If} ${Errors}
    ClearErrors
    nsExec::ExecToLog 'robocopy "$OldBundleDir" "$BundleBackupDir" /E /R:1 /W:1 /NFL /NDL /NJH /NJS /NP'
    Pop $0
  ${EndIf}
FunctionEnd

Function RestorePreservedResourceBundles
  ${If} $BundleBackupDir == ""
    Return
  ${EndIf}

  ${IfNot} ${FileExists} "$BundleBackupDir\*.*"
    Return
  ${EndIf}

  DetailPrint "Merging preserved resource bundles"
  CreateDirectory "$INSTDIR\resources-bundles"
  nsExec::ExecToLog 'robocopy "$BundleBackupDir" "$INSTDIR\resources-bundles" /E /XC /XN /XO /R:1 /W:1 /NFL /NDL /NJH /NJS /NP'
  Pop $0
  Push "$BundleBackupDir"
  Call RemoveDirectoryDeep
FunctionEnd

Function RunUpgradePreparation
  ${If} $UpgradePreparationDone == "true"
    Return
  ${EndIf}

  Call ResolveLegacyInstallDir
  ${If} $OldInstallDir == ""
    StrCpy $UpgradePreparationDone "true"
    Return
  ${EndIf}

  Call KillProcessesUnderLegacyInstall
  Call BackupLegacyResourceBundles
  Call ClearLegacyRegistry
  StrCpy $UpgradePreparationDone "true"
FunctionEnd

!macro customCheckAppRunning
  !ifdef BUILD_UNINSTALLER
    DetailPrint "Closing running application..."
    nsExec::ExecToLog 'taskkill /F /IM "${PRODUCT_FILENAME}.exe" /T'
    Pop $0
    nsExec::ExecToLog 'taskkill /F /IM "SC-IP-Agent.exe" /T'
    Pop $0
    nsExec::ExecToLog 'taskkill /F /IM "尚创IP智能体V8.exe" /T'
    Pop $0
  !else
    DetailPrint "Preparing in-place upgrade..."
    Call RunUpgradePreparation
    DetailPrint "Upgrade preparation complete"
  !endif
!macroend

!macro customInit
  Call ResolveLegacyInstallDir

  IfSilent skip_vcredist 0
  ReadRegStr $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
  StrCmp $0 "1" skip_vcredist
  MessageBox MB_YESNO "检测到系统缺少 Visual C++ 运行库，是否安装？" IDYES install_vcredist IDNO skip_vcredist
  install_vcredist:
    SetOutPath "$TEMP"
    File "${BUILD_RESOURCES_DIR}\vc_redist.x64.exe"
    ExecWait '"$TEMP\vc_redist.x64.exe" /install /quiet /norestart' $1
    Delete "$TEMP\vc_redist.x64.exe"
  skip_vcredist:

  Call RunUpgradePreparation
!macroend

!macro customInstall
  DetailPrint "Running final upgrade checks..."
  Call KillProcessesUnderLegacyInstall
  Call RestorePreservedResourceBundles
!macroend

!macro customUnInit
  DetailPrint "Closing running application..."
  nsExec::ExecToLog 'taskkill /F /IM "${PRODUCT_FILENAME}.exe" /T'
  Pop $0
  nsExec::ExecToLog 'taskkill /F /IM "SC-IP-Agent.exe" /T'
  Pop $0
  nsExec::ExecToLog 'taskkill /F /IM "尚创IP智能体V8.exe" /T'
  Pop $0
!macroend
