#define MyAppName "pgAdmin 4"
#define MyAppVersion MYAPP_VERSION
#define MyAppPublisher "The pgAdmin Development Team"
#define MyAppURL "www.pgadmin.org"
#define MyAppExeName "pgAdmin4.exe"
#define MyAppID "C14F64E7-DCB9-4DE1-8560-16F08FCFF64E"
#define MyAppFullVersion MYAPP_FULLVERSION
#define MyAppArchitecturesMode "x64"
#define MyAppVCDist MYAPP_VCDIST
#define MyAppInvalidPath "Please provide a valid path."
#define MinimumWindowsVer "6.2.9200"
#define CheckOldInstallerVersion "v8"

[Setup]
AppId={#MyAppName}{#MyAppVersion}
AppName={#MyAppName}
AppVersion={#MyAppFullVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableWelcomePage=no
DisableProgramGroupPage=auto
LicenseFile=Resources\license.rtf
OutputBaseFilename=pgadmin4-setup
SetupIconFile=Resources\pgAdmin4.ico
Compression=lzma
SolidCompression=yes
PrivilegesRequired=lowest
PrivilegesRequiredOverridesAllowed=dialog
ChangesEnvironment=yes
UninstallDisplayIcon={app}\runtime\{#MyAppExeName}
ArchitecturesInstallIn64BitMode={#MyAppArchitecturesMode}
AllowNoIcons=yes
WizardImageFile=sidebar.bmp
MinVersion={#MinimumWindowsVer}

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

;This section will override the standard error message by default which is called internally and  we don't have a control over this.
[Messages]
InvalidPath={#MyAppInvalidPath}

;This section would be used for customized error message display.
[CustomMessages]
english.NewerVersionExists=A newer version of {#MyAppName}
english.InvalidPath={#MyAppInvalidPath}

[Icons]
Name: {group}\{#MyAppName}; Filename: {app}\runtime\{#MyAppExeName}; IconFilename: {app}\pgAdmin4.ico; WorkingDir: {app}\runtime;

[Files]
Source: "..\..\win-build\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs;

[Run]
Filename: "{app}\installer\{#MyAppVCDist}"; StatusMsg: "VC runtime redistributable package"; Parameters: "/passive /verysilent /norestart"; Check: InstallVC;

[Registry]
Root: HKA; Subkey: "Software\{#MyAppName}"; Flags: uninsdeletekeyifempty
Root: HKA; Subkey: "Software\{#MyAppName}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\{#MyAppName}"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"
Root: HKA; Subkey: "Software\{#MyAppName}"; ValueType: string; ValueName: "Version"; ValueData: "{#MyAppFullVersion}"

[Code]
var
  UpgradeMode: Boolean;

// Procedure to split a string into an array of integers
procedure Explode(var Dest: TArrayOfInteger; Text: String; Separator: String);
var
  i, p: Integer;
begin
  i := 0;
  repeat
    SetArrayLength(Dest, i+1);
    p := Pos(Separator,Text);
    if p > 0 then begin
      Dest[i] := StrToInt(Copy(Text, 1, p-1));
      Text := Copy(Text, p + Length(Separator), Length(Text));
      i := i + 1;
    end else begin
      Dest[i] := StrToInt(Text);
      Text := '';
    end;
  until Length(Text)=0;
end;

// Function compares version strings numerically:
//     * when v1 = v2, result = 0
//     * when v1 < v2, result = -1
//     * when v1 > v2, result = 1
//
// Supports version numbers with trailing zeroes, for example 1.02.05.
// Supports comparison of two version number of different lengths,
// for example CompareVersions('1.2', '2.0.3')
// When any of the parameters is '' (empty string) it considers version
// number as 0
function CompareVersions(v1: String; v2: String): Integer;
var
  v1parts: TArrayOfInteger;
  v2parts: TArrayOfInteger;
  i: Integer;
begin
  if v1 = '' then
  begin
    v1 := '0';
  end;

  if v2 = '' then
  begin
    v2 := '0';
  end;

  Explode(v1parts, v1, '.');
  Explode(v2parts, v2, '.');

  if (GetArrayLength(v1parts) > GetArrayLength(v2parts)) then
  begin
    SetArrayLength(v2parts, GetArrayLength(v1parts))
  end else if (GetArrayLength(v2parts) > GetArrayLength(v1parts)) then
  begin
    SetArrayLength(v1parts, GetArrayLength(v2parts))
  end;

  for i := 0 to GetArrayLength(v1parts) - 1 do
  begin
    if v1parts[i] > v2parts[i] then
    begin
      { v1 is greater }
      Result := 1;
      exit;
    end else if v1parts[i] < v2parts[i] then
    begin
      { v2 is greater }
      Result := -1;
      exit;
    end;
  end;

  { Are Equal }
  Result := 0;
end;

// This function is invoked only when the V8 version is already installed.
// It retrieves the path of the uninstaller to remove the installed V8 version.
function GetUninstallerPath(): String;
var
  sUnInstRegKey: String;
  sUnInstPath: String;
begin
  sUnInstRegKey := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppName}{#CheckOldInstallerVersion}_is1';
  sUnInstPath := '';
  RegQueryStringValue(HKA, sUnInstRegKey, 'UninstallString', sUnInstPath);
  Result := sUnInstPath;
end;

// This function is invoked only when the V8 version is already installed.
// It is used to uninstall the installed V8 version.
// Return Values:
// 1 - Uninstaller path is empty.
// 2 - Error executing the Uninstaller.
// 3 - Successfully executed the Uninstaller
function UnInstallOldVersion(): Integer;
var
  sUnInstallerPath: String;
  iResultCode: Integer;
begin
  // default return value
  Result := 0;

  // get the uninstall path of the old app
  sUnInstallerPath := GetUninstallerPath();
  if sUnInstallerPath <> '' then begin
    sUnInstallerPath := RemoveQuotes(sUnInstallerPath);
    if Exec(sUnInstallerPath, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
      Result := 3
    else
      Result := 2;
  end else
    Result := 1;
end;

function CheckPgAdminAlreadyInstalled: Boolean;
var
  Version: String;
begin
  if RegKeyExists(HKA,'Software\{#MyAppName}\{#CheckOldInstallerVersion}') then
  begin
    if UnInstallOldVersion() < 3 then
    begin
      Result := False;
    end;
  end;

  if RegValueExists(HKA,'Software\{#MyAppName}', 'Version') then
  begin
    UpgradeMode := True;
    RegQueryStringValue(HKA,'Software\{#MyAppName}', 'Version', Version);
    if CompareVersions(Version, '{#MyAppFullVersion}') = 1 then
    begin
      MsgBox(ExpandConstant('{cm:NewerVersionExists}' + '(v' + Version + ') is already installed' ), mbInformation, MB_OK);
      Result := False;
    end
    else
    begin
      Result := True;
    end;
  end;

  if  ( not (UpgradeMode) ) then
  begin
    // This is required as it will be passed on to the InitializeSetup function
    Result := True;
  end;
end;

// Find current version before installation
function InitializeSetup: Boolean;
begin
    Result := CheckPgAdminAlreadyInstalled;
end;

function IsUpgradeMode(): Boolean;
begin
  Result := UpgradeMode;
end;

function InstallVC: Boolean;
begin
  Result := True;
end;

// This function would be called during upgrade mode
// In upgrade mode - delete web/* and exclude config_local.py
procedure DelWebfolder(Path: string);
var
  FindRec: TFindRec;
  FilePath: string;
begin
  if FindFirst(Path + '\*', FindRec) then
  begin
    try
      repeat
        if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
        begin
          FilePath := Path + '\' + FindRec.Name;
          if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
          begin
            if CompareText(FindRec.Name, 'config_local.py') <> 0 then
            begin
              DeleteFile(FilePath);
            end
          end
          else
            begin
              DelWebfolder(FilePath);
              RemoveDir(FilePath);
            end;
          end;
        until not FindNext(FindRec);
      finally
      FindClose(FindRec);
    end;
  end;
end;

// This function would be called during upgrade mode
// In upgrade mode - delete python/* for example
procedure DelFolder(Path: string);
var
  FindRec: TFindRec;
  FilePath: string;
begin
  if FindFirst(Path + '\*', FindRec) then
  begin
    try
      repeat
        if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
        begin
          FilePath := Path + '\' + FindRec.Name;
          if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
          begin
            DeleteFile(FilePath);
          end
          else
            begin
              DelFolder(FilePath);
              RemoveDir(FilePath);
            end;
          end;
        until not FindNext(FindRec);
      finally
      FindClose(FindRec);
    end;
  end;
end;

//procedure CurPageChanged(CurPageID: Integer);
function NextButtonClick(CurPageID: Integer): Boolean;
var
  Ret: Boolean;
begin
  Ret := True;
  case CurPageID of
    wpReady:
	begin
      if (IsUpgradeMode) then
      begin
        DelWebfolder(ExpandConstant('{app}\web'));
        DelFolder(ExpandConstant('{app}\python'));
      end;
	end;
  end;

  Result := Ret;
end;

// End of program