#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 MyAppErrorMsgIsWin32 "You already have a 32 bit installation of pgAdmin 4. Please uninstall this before installing the 64 bit version."
#define MyAppErrorMsgIsWin64 "You already have a 64 bit installation of pgAdmin 4. Please uninstall this before installing the 32 bit version."
#define MinimumWindowsVer "6.2.9200"

[Setup]
AppId={#MyAppName}{#MyAppVersion}
AppName={#MyAppName}
AppVersion={#MyAppFullVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}\{#MyAppVersion}
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} {#MyAppVersion}; 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}\{#MyAppVersion}"; Flags: uninsdeletekeyifempty
Root: HKA; Subkey: "Software\{#MyAppName}\{#MyAppVersion}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\{#MyAppName}\{#MyAppVersion}"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"
Root: HKA; Subkey: "Software\{#MyAppName}\{#MyAppVersion}"; 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;

function IsPathValid(Path: string): Boolean;
var
  I: Integer;
  Ret: Boolean;
begin
  Ret := True;
  Path := Uppercase(Path);
  Result :=
    (Length(Path) >= 3) and
    (Path[1] >= 'A') and (Path[1] <= 'Z') and
    (Path[2] = ':') and
    (Path[3] = '\');

  if Result then
  begin
    for I := 3 to Length(Path) do
      begin
        case Path[I] of
          '0'..'9', 'A'..'Z', '\', ' ', '.', '-', '_', '(', ')':
          else
          begin
            Ret := False;
            break;
          end;
      end;
    end;
  end;
  Result := Ret;
end;

function CheckPgAdminAlreadyInstalled: Boolean;
var
  Version: String;
  InstallationFound: Boolean;
begin
  InstallationFound := False;
  // Check the installation mode 64 or 32 bit of installer
  if Is64BitInstallMode then
  begin

    // Check if pgAdmin 32 bit is already installed
    RegQueryStringValue(HKLM32,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version);

    // If version is found then shouldn't install 64bit - abort
    if Length(Version) > 0 then
    begin
      MsgBox(ExpandConstant('{#MyAppErrorMsgIsWin32}'), mbCriticalError, MB_OK);
	  Result := False;
	  InstallationFound := True;
    end;
  end
  else
  begin
    // Suppose system is running a 32-bit version of Windows then no need to check HKLM64 in RegQueryStringValue
    // So IsWin64 - will make sure its should only execute on 64-bit veersion of windows.
    if IsWin64 then
	begin
        // Check if pgAdmin 64 bit is already installed
        RegQueryStringValue(HKLM64,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version);

        // If version is found the shouldn't install 32bit - abort
        if Length(Version) > 0 then
        begin
          MsgBox(ExpandConstant('{#MyAppErrorMsgIsWin64}'), mbCriticalError, MB_OK);
	      Result := False;
	      InstallationFound := True;
	    end;
	end;
 end;

  if  not (InstallationFound) then
  begin
     if RegValueExists(HKEY_LOCAL_MACHINE,'Software\{#MyAppName}\{#MyAppVersion}', 'Version') then
     begin
       UpgradeMode := True;
       RegQueryStringValue(HKEY_LOCAL_MACHINE,'Software\{#MyAppName}\{#MyAppVersion}', '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;
  end;

  if  ( not (InstallationFound) and 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
    wpSelectDir:
      begin
        // Validate InstallDir path
        if Not IsPathValid(ExpandConstant('{app}')) then
        begin
          MsgBox(ExpandConstant('{cm:InvalidPath}'), mbError, MB_OK);
          Ret := False;
        end;
      end;

    wpReady:
	begin
      if (IsUpgradeMode) then
      begin
        DelWebfolder(ExpandConstant('{app}\web'));
        DelFolder(ExpandConstant('{app}\python'));
      end;
	end;
  end;

  Result := Ret;
end;

// End of program
