; ============================================================================
; INNO SETUP PROJECT TEMPLATE
; ============================================================================
;
; This template provides a starting point for creating Inno Setup installers.
; It includes common patterns, examples, and best practices.
;
; HOW TO USE THIS TEMPLATE:
; 1. Copy this entire folder to a new location
; 2. Rename Template.iss to YourProjectName.iss
; 3. Search for "TODO:" comments and update as needed
; 4. Add your files to the project folder
; 5. Compile with Inno Setup Compiler
;
; REQUIREMENTS:
; - Inno Setup 6.x or later (https://jrsoftware.org/isinfo.php)
; - Optional: Add gea-logo.ico, banner.bmp, banner-sm.bmp for branding
;
; Author: WJDT / GE Aerospace
; Version: 1.0
; ============================================================================

; ============================================================================
; [Setup] - Basic installer configuration
; ============================================================================
[Setup]
; TODO: Generate a unique GUID for your app (Tools > Generate GUID in Inno Setup)
AppId={{YOUR-UNIQUE-GUID-HERE}}

; TODO: Update these with your application details
AppName=My Application Name
AppVersion=1.0
AppPublisher=WJDT
AppPublisherURL=https://www.geaerospace.com
AppSupportURL=https://www.geaerospace.com
AppUpdatesURL=https://www.geaerospace.com

; Installation directory (use {autopf} for Program Files, auto-selects 32/64-bit)
DefaultDirName={autopf}\My Application

; Start menu folder name
DefaultGroupName=My Application

; Output settings
OutputDir=Output
OutputBaseFilename=MyApplicationSetup_v1.0

; Compression
SolidCompression=yes
Compression=lzma2

; Visual style
WizardStyle=modern

; Branding (included in template - replace with your own)
SetupIconFile=gea-logo.ico
WizardImageFile=banner.bmp
WizardSmallImageFile=banner-sm.bmp

; Privileges: admin = requires elevation, lowest = current user only
; Use 'admin' for Program Files installs, 'lowest' for user-specific tools
PrivilegesRequired=admin

; Other common options
DisableWelcomePage=no
DisableDirPage=no
DisableProgramGroupPage=no
AllowNoIcons=yes

; Uninstall settings
Uninstallable=yes
CreateUninstallRegKey=yes

; ============================================================================
; [Languages] - Supported languages
; ============================================================================
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
; Uncomment for additional languages:
; Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"
; Name: "french"; MessagesFile: "compiler:Languages\French.isl"
; Name: "german"; MessagesFile: "compiler:Languages\German.isl"

; ============================================================================
; [Messages] - Custom message overrides
; ============================================================================
[Messages]
; TODO: Customize the welcome page text
WelcomeLabel2=This will install [name] version [ver] on your computer.%n%nIt is recommended that you close all other applications before continuing.%n%nClick Next to continue, or Cancel to exit Setup.

; ============================================================================
; [Tasks] - Optional installation tasks (checkboxes)
; ============================================================================
[Tasks]
Name: "desktopicon"; Description: "Create a &desktop shortcut"; GroupDescription: "Additional shortcuts:"; Flags: unchecked
Name: "quicklaunchicon"; Description: "Create a &Quick Launch shortcut"; GroupDescription: "Additional shortcuts:"; Flags: unchecked
; Example: Optional component
; Name: "installextra"; Description: "Install optional components"; GroupDescription: "Components:"

; ============================================================================
; [Files] - Files to install
; ============================================================================
[Files]
; TODO: Add your application files here
;
; Common flags:
;   ignoreversion    - Always overwrite regardless of version
;   recursesubdirs   - Include subdirectories
;   createallsubdirs - Create empty subdirectories too
;   deleteafterinstall - Delete after install (for temp files)
;
; Examples:
; Source: "MyApp.exe"; DestDir: "{app}"; Flags: ignoreversion
; Source: "MyApp.dll"; DestDir: "{app}"; Flags: ignoreversion
; Source: "Data\*"; DestDir: "{app}\Data"; Flags: ignoreversion recursesubdirs createallsubdirs
; Source: "README.txt"; DestDir: "{app}"; Flags: ignoreversion isreadme

; ============================================================================
; [Dirs] - Directories to create
; ============================================================================
[Dirs]
; Example: Create a data directory with specific permissions
; Name: "{app}\Data"; Permissions: users-modify
; Name: "{commonappdata}\MyApp"; Permissions: users-modify

; ============================================================================
; [Icons] - Shortcuts to create
; ============================================================================
[Icons]
; Start Menu shortcut
; Name: "{group}\My Application"; Filename: "{app}\MyApp.exe"; WorkingDir: "{app}"

; Desktop shortcut (only if task selected)
; Name: "{userdesktop}\My Application"; Filename: "{app}\MyApp.exe"; WorkingDir: "{app}"; Tasks: desktopicon

; Uninstall shortcut in Start Menu
; Name: "{group}\Uninstall My Application"; Filename: "{uninstallexe}"

; ============================================================================
; [Registry] - Registry entries
; ============================================================================
[Registry]
; Examples:
; Root: HKLM; Subkey: "Software\MyCompany\MyApp"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"; Flags: uninsdeletekey
; Root: HKCU; Subkey: "Software\MyCompany\MyApp"; ValueType: dword; ValueName: "SomeOption"; ValueData: "1"

; ============================================================================
; [INI] - INI file entries
; ============================================================================
[INI]
; Example: Create an INI file
; Filename: "{app}\MyApp.ini"; Section: "Settings"; Key: "Language"; String: "en"

; ============================================================================
; [Run] - Programs to run after installation
; ============================================================================
[Run]
; Example: Launch app after install (optional, user can uncheck)
; Filename: "{app}\MyApp.exe"; Description: "Launch My Application"; Flags: nowait postinstall skipifsilent

; Example: Run a configuration script
; Filename: "{cmd}"; Parameters: "/c ""{app}\configure.bat"""; Flags: runhidden waituntilterminated

; ============================================================================
; [UninstallRun] - Programs to run during uninstall
; ============================================================================
[UninstallRun]
; Example: Run cleanup script before uninstall
; Filename: "{app}\cleanup.bat"; Flags: runhidden waituntilterminated

; ============================================================================
; [UninstallDelete] - Additional files to delete during uninstall
; ============================================================================
[UninstallDelete]
; Example: Delete log files created by the app
; Type: files; Name: "{app}\*.log"
; Type: filesandordirs; Name: "{app}\Cache"

; ============================================================================
; [Code] - Pascal scripting section
; ============================================================================
[Code]

// ============================================================================
// CONSTANTS
// ============================================================================

const
  // TODO: Add your constants here
  APP_NAME = 'My Application';

// ============================================================================
// GLOBAL VARIABLES
// ============================================================================

var
  // Custom wizard pages (if needed)
  CustomPage: TWizardPage;

  // Progress page for long operations
  ProgressPage: TOutputProgressWizardPage;

// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================

// Execute a command and capture output
function ExecWithOutput(const Cmd, Params: String; var Output: String): Integer;
var
  TempFile: String;
  ResultCode: Integer;
  OutputAnsi: AnsiString;
begin
  TempFile := ExpandConstant('{tmp}\exec_output.txt');

  Exec('cmd.exe', '/c ' + Cmd + ' ' + Params + ' > "' + TempFile + '" 2>&1',
       '', SW_HIDE, ewWaitUntilTerminated, ResultCode);

  if FileExists(TempFile) then
  begin
    LoadStringFromFile(TempFile, OutputAnsi);
    Output := String(OutputAnsi);
    DeleteFile(TempFile);
  end
  else
    Output := '';

  Result := ResultCode;
end;

// Execute a PowerShell script and capture output
function ExecPowerShell(const Script: String; var Output: String): Integer;
var
  TempScript, TempOutput: String;
  ResultCode: Integer;
  OutputAnsi: AnsiString;
begin
  TempScript := ExpandConstant('{tmp}\ps_script.ps1');
  TempOutput := ExpandConstant('{tmp}\ps_output.txt');

  SaveStringToFile(TempScript, Script, False);

  Exec('cmd.exe',
       '/c powershell.exe -NoProfile -ExecutionPolicy Bypass -File "' + TempScript + '" > "' + TempOutput + '" 2>&1',
       '', SW_HIDE, ewWaitUntilTerminated, ResultCode);

  if FileExists(TempOutput) then
  begin
    LoadStringFromFile(TempOutput, OutputAnsi);
    Output := String(OutputAnsi);
    DeleteFile(TempOutput);
  end
  else
    Output := '';

  DeleteFile(TempScript);
  Result := ResultCode;
end;

// Check if a program is installed (by checking registry)
function IsProgramInstalled(const DisplayName: String): Boolean;
var
  Subkey: String;
  Value: String;
begin
  Result := False;
  // Check 64-bit registry
  Subkey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + DisplayName;
  if RegQueryStringValue(HKLM, Subkey, 'DisplayName', Value) then
    Result := True
  else
  begin
    // Check 32-bit registry on 64-bit Windows
    Subkey := 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\' + DisplayName;
    if RegQueryStringValue(HKLM, Subkey, 'DisplayName', Value) then
      Result := True;
  end;
end;

// Check if .NET Framework 4.8 is installed
function IsDotNet48Installed: Boolean;
var
  Release: Cardinal;
begin
  Result := False;
  if RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', Release) then
    Result := (Release >= 528040); // 4.8 or later
end;

// Check if VC++ Redistributable is installed (2015-2022)
function IsVCRedistInstalled: Boolean;
var
  Installed: Cardinal;
begin
  Result := False;
  if RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Installed', Installed) then
    Result := (Installed = 1);
end;

// Show a modal message dialog with scrollable text
procedure ShowResultsDialog(const Title, Content: String);
var
  ResultForm: TSetupForm;
  Memo: TNewMemo;
  OKButton: TNewButton;
begin
  ResultForm := CreateCustomForm;
  ResultForm.Caption := Title;
  ResultForm.ClientWidth := 500;
  ResultForm.ClientHeight := 400;
  ResultForm.Position := poScreenCenter;

  Memo := TNewMemo.Create(ResultForm);
  Memo.Parent := ResultForm;
  Memo.Left := 10;
  Memo.Top := 10;
  Memo.Width := ResultForm.ClientWidth - 20;
  Memo.Height := ResultForm.ClientHeight - 60;
  Memo.ScrollBars := ssVertical;
  Memo.ReadOnly := True;
  Memo.Text := Content;
  Memo.Font.Name := 'Consolas';
  Memo.Font.Size := 9;

  OKButton := TNewButton.Create(ResultForm);
  OKButton.Parent := ResultForm;
  OKButton.Caption := 'OK';
  OKButton.Width := 80;
  OKButton.Height := 30;
  OKButton.Left := (ResultForm.ClientWidth - OKButton.Width) div 2;
  OKButton.Top := ResultForm.ClientHeight - 45;
  OKButton.ModalResult := mrOK;
  OKButton.Default := True;

  ResultForm.ShowModal;
  ResultForm.Free;
end;

// ============================================================================
// WIZARD PAGE CREATION
// ============================================================================

procedure InitializeWizard;
begin
  // Create a progress page for long operations
  ProgressPage := CreateOutputProgressPage('Please Wait',
    'Please wait while the operation completes...');

  // TODO: Create custom wizard pages here if needed
  // Example: Create a custom input page
  // CustomPage := CreateCustomPage(wpSelectDir, 'Custom Options', 'Configure additional options');

  // Example: Add controls to custom page
  // var MyLabel: TLabel;
  // MyLabel := TLabel.Create(CustomPage);
  // MyLabel.Parent := CustomPage.Surface;
  // MyLabel.Caption := 'Enter your setting:';
  // MyLabel.Left := 0;
  // MyLabel.Top := 0;
end;

// ============================================================================
// INSTALLATION EVENTS
// ============================================================================

// Called at the very start - return False to abort
function InitializeSetup: Boolean;
begin
  Result := True;

  // Example: Check for admin rights
  if not IsAdmin then
  begin
    MsgBox('This installer requires administrator privileges.' + #13#10 +
           'Please right-click and select "Run as administrator".',
           mbError, MB_OK);
    Result := False;
    Exit;
  end;

  // Example: Check prerequisites
  // if not IsDotNet48Installed then
  // begin
  //   MsgBox('.NET Framework 4.8 is required but not installed.', mbError, MB_OK);
  //   Result := False;
  //   Exit;
  // end;
end;

// Called before each wizard page - return True to skip the page
function ShouldSkipPage(PageID: Integer): Boolean;
begin
  Result := False;
  // Example: Skip directory page for portable install
  // if PageID = wpSelectDir then
  //   Result := True;
end;

// Called when Next button is clicked - return False to stay on page
function NextButtonClick(CurPageID: Integer): Boolean;
begin
  Result := True;

  // Example: Validate custom page input
  // if CurPageID = CustomPage.ID then
  // begin
  //   if MyEdit.Text = '' then
  //   begin
  //     MsgBox('Please enter a value.', mbError, MB_OK);
  //     Result := False;
  //   end;
  // end;
end;

// Called at each installation step
procedure CurStepChanged(CurStep: TSetupStep);
var
  ResultCode: Integer;
begin
  // ssInstall: Before files are installed
  // ssPostInstall: After files are installed
  // ssDone: Installation complete

  if CurStep = ssPostInstall then
  begin
    // Example: Run post-install configuration
    // Exec(ExpandConstant('{app}\configure.exe'), '/silent', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
  end;
end;

// Called at each uninstallation step
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  // usAppMutexCheck: Check for running app
  // usUninstall: Before uninstall
  // usPostUninstall: After uninstall
  // usDone: Uninstall complete

  if CurUninstallStep = usUninstall then
  begin
    // Example: Backup user data before uninstall
  end;
end;

// ============================================================================
// SILENT INSTALL SUPPORT
// ============================================================================

// To run silently: MySetup.exe /VERYSILENT /SUPPRESSMSGBOXES
// To run silently with log: MySetup.exe /VERYSILENT /LOG="install.log"

// Check if running in silent mode
function IsSilentMode: Boolean;
begin
  Result := WizardSilent;
end;

// Show message only if not in silent mode
procedure ShowMessageIfNotSilent(const Msg: String; MsgType: TMsgBoxType);
begin
  if not WizardSilent then
    MsgBox(Msg, MsgType, MB_OK);
end;
