0.1.0

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "tellurium"
;#define MyAppVersion "0.0.0"  read from file, see below
#define MyAppPublisher "University of Washington, Seattle, WA, USA"
#define MyAppURL "http://tellurium.analogmachine.org/"
#define MyAppSetupIconFile "tellurium_icon_64x64.ico"
#define ThisInstallerPostfix "win32-superpack-setup"

#define LibRoadRunnerInstaller "libroadrunner-1.0.1-win32-minimal-setup.exe"
#define AntimonyInstaller "AntimonyPythonBindings-2.5.1-win32.exe"
#define TelPluginsInstaller "telplugins-1.0.5-Python-2.7-win32-minimal-setup.exe"
#define PyInstaller "python-2.7.6.msi"
#define NumpyInstaller "numpy-1.8.0-win32-superpack-python2.7.exe"
#define MatplotlibInstaller "matplotlib-1.3.1.win32-py2.7.exe"
;#define DateutilInstaller "python-dateutil-2.2.win32-py2.7.exe"
;#define PyparsingInstaller "pyparsing-2.0.1.win32-py2.7.exe"
;#define SixInstaller "six-1.5.2.win32-py2.7.exe"

#define PyQtInstaller "PyQt4"
#define SipInstaller "sip.pyd"
#define PipInstaller "get-pip.py"
#define SpyderInstaller "spyder-2.2.5-tellurium-0.1.0.win32.exe"

;add spyder source
;then do ":python setup.py install" to install

;downloads turned off, installers packaged
;#define LibRoadRunnerInstallerURL "http://sourceforge.net/projects/libroadrunner/files/roadrunner-1.0.1-rc1-win32-minimal-setup.exe"
;#define AntimonyInstallerURL "http://sourceforge.net/projects/antimony/files/Windows%20binaries/2.5/AntimonyPythonBindings-2.5.0-win32.exe"
;#define PyInstallerURL "http://python.org/ftp/python/2.7.6/python-2.7.6.msi"
;#define NumpyInstallerURL "http://downloads.sourceforge.net/project/numpy/NumPy/1.8.0/numpy-1.8.0-win32-superpack-python2.7.exe?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fnumpy%2Ffiles%2FNumPy%2F&ts=1390956336&use_mirror=softlayer-ams"
;#define MatplotlibInstallerURL "https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-1.3.1/matplotlib-1.3.1.win32-py2.7.exe"
;#define DateutilInstallerURL "http://www.lfd.uci.edu/~gohlke/pythonlibs/#python-dateutil" ;there does not appear to be a direct URL to the file
;#define PyparsingInstallerURL "http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyparsing" The one from "http://downloads.sourceforge.net/project/pyparsing/pyparsing/pyparsing-2.0.1/pyparsing-2.0.1.win32-py2.7.exe" did not work.
;#define SixInstallerURL "http://www.lfd.uci.edu/~gohlke/pythonlibs/#six"
;#define PyQtInstallerURL "http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.10.3/PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x32.exe/download"
;#define SipInstallerURL "http://www.riverbankcomputing.com/software/sip/download" #using file from bin install
;#define PipInstallerURL "https://raw.github.com/pypa/pip/master/contrib/get-pip.py"
;#define SpyderInstaller "https://bitbucket.org/spyder-ide/spyderlib/downloads/spyder-2.2.5.win32.exe"

#define Py "Python"
#define PyVer "2.7"
#define Numpy "numpy"
;#define NumpyVer "1.0"
#define Matplotlib "matplotlib"
;#define MatplotlibVer "1.0"
#define AppDir "tellurium"
#define Pip "pip.exe"

#define VerFile FileOpen("../../VERSION.txt")
#define MyAppVersion FileRead(VerFile)
#expr FileClose(VerFile)
#undef VerFile

;Used for downloader
;#include ReadReg(HKEY_LOCAL_MACHINE,'Software\Sherlock Software\InnoTools\Downloader','ScriptPath','');

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{2EA1F666-39FE-4A26-BCC9-4D534219C9AE}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DisableWelcomePage=yes
DefaultDirName={code:SetAppDirPath}
;DefaultDirName=C:\Python27\Lib\site-packages\{#AppDir}

;enable the next line for debug only
;DisableDirPage=yes

;DefaultGroupName=libRoadRunner
DisableProgramGroupPage=yes
;LicenseFile=..\..\LICENSE
;InfoBeforeFile=..\..\NOTICE.txt
;InfoAfterFile=README.md
DisableReadyPage=yes
;DisableFinishedPage=yes   ;finished page is good feedback
OutputDir=.
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-{#Py}-{#PyVer}-{#ThisInstallerPostfix}
SetupIconFile={#MyAppSetupIconFile}
Compression=lzma
SolidCompression=yes

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

[Files]
Source: "../../startTellurium.py"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../__init__.py"; DestDir: "{app}"; Flags: ignoreversion
;copy example to app dir, for temp file, this will open by default at first run
Source: "../../examples/tellurium-files/*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
;copy example to tellurium-files as example file
Source: "../../examples/tellurium-files/*"; DestDir: "{userdocs}\tellurium-files"; Flags: ignoreversion recursesubdirs

Source: "../../NEWS.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../VERSION.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../README.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../NOTICE.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "super_installer_dependencies\{#LibRoadRunnerInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion
Source: "super_installer_dependencies\{#AntimonyInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion
Source: "super_installer_dependencies\{#TelPluginsInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion
Source: "libRoadrunner-installer-dependencies\{#MatplotlibInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
;-Source: "libRoadrunner-installer-dependencies\{#DateutilInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
;-Source: "libRoadrunner-installer-dependencies\{#PyparsingInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
;-Source: "libRoadrunner-installer-dependencies\{#SixInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
Source: "libRoadrunner-installer-dependencies\{#NumpyInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
Source: "libRoadrunner-installer-dependencies\{#PyInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
Source: "libRoadrunner-installer-dependencies\{#PipInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist

Source: "spyder_dependencies\{#PyQtInstaller}\*"; DestDir: "{code:SetPythonSitePackagesPath}\{#PyQtInstaller}"; Flags: ignoreversion onlyifdoesntexist recursesubdirs createallsubdirs
Source: "spyder_dependencies\{#SipInstaller}"; DestDir: "{code:SetPythonSitePackagesPath}"; Flags: ignoreversion onlyifdoesntexist
Source: "spyder_dependencies\{#SpyderInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
;Spyder installer is a custom distro with the following mod at the end of scientific_startup.py
;from tellurium import *

; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Run]
Filename: "{code:SetPythonPath}\python.exe"; Parameters: "{tmp}\{#PipInstaller}"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install python-dateutil"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install pyparsing"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install six"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized

Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install ipython[all]"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install sphinx"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install pyflakes"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install pylint"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install pep8"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install psutil"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{#LibRoadRunnerInstaller}"; Parameters: "/SILENT"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{#AntimonyInstaller}"; Parameters: "/SILENT"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{#TelPluginsInstaller}"; Parameters: "/SILENT"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{#SpyderInstaller}"; Parameters: "/SILENT"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{app}\README.TXT"; Description: "View the README file"; Flags: postinstall shellexec skipifsilent unchecked
Filename: "{code:SetPythonPath}\pythonw.exe"; Parameters:"{code:SetPythonPath}\scripts\spyder -w {userdocs}\tellurium-files"; Description: "Run TeSpyder"; Flags: postinstall shellexec skipifsilent waituntilterminated

;SCIPY pip install has an error, may need a fortran compiler! mingw, but do we need Scipy?
;Filename: "{#Pip}"; Parameters: "install scipy"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized

;MATPLOTLIB, on pip install, cannot find vcvarsall.bat, a symptom of missing the 2008 VS++ <-seriously you need to install a compiler
;Filename: "{#Pip}"; Parameters: "install matplotlib"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized

;NUMPY, on pip install, cannot find vcvarsall.bat, a symptom of missing the 2008 VS++ <-seriously you need to install a compiler
;Filename: "{#Pip}"; Parameters: "install numpy"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized

[Code]
//////////////////////////////////////////////////////////////////////////////
const
  appDir = '{#AppDir}';
  pyReg = 'SOFTWARE\{#Py}\PythonCore\{#PyVer}\InstallPath';
  pyRegWow6443Node = 'SOFTWARE\Wow6432Node\{#Py}\PythonCore\{#PyVer}\InstallPath';

var
  installPython, installMatplot, installNumpy: Boolean;
  AppDirPath: String;
  PythonPath: String;
  PythonSitePackagesPath: String;

//////////////////////////////////////////////////////////////////////////////
procedure ExitProcess(exitCode:integer);
  external 'ExitProcess@kernel32.dll stdcall';

//////////////////////////////////////////////////////////////////////////////
function GetPathForPython(): string;
var
  InstallPath: string;
begin

  if RegQueryStringValue(HKEY_LOCAL_MACHINE, pyReg, '', InstallPath) then
    begin
    Log('HKLM pyReg: '+ InstallPath);
    Result := InstallPath;
    end
  else
  if RegQueryStringValue(HKEY_CURRENT_USER, pyReg, '', InstallPath) then
    begin
    Log('HKCU pyReg: '+ InstallPath);
    Result := InstallPath;
    end
  else
  if RegQueryStringValue(HKEY_LOCAL_MACHINE, pyRegWow6443Node, '', InstallPath) then
    begin
    Log('HKLM pyRegWow6443Node: '+ InstallPath);
    Result := InstallPath;
    end
  else
    begin
    MsgBox('Our installer did not find your Python installation. You need '
    + 'Python to run {#MyAppName}. In the next step use [Your Python installation'
    + ' location]\Lib\site-packages\{#AppDir} directory.',mbError,MB_OK);
    //ExitProcess(1);
    end
end;

//////////////////////////////////////////////////////////////////////////////
function GetPathForPythonSitePackages(PythonPath: String): string;
begin
  Result := PythonPath + 'Lib\site-packages\';
end;

//////////////////////////////////////////////////////////////////////////////
function IsPythonInstalled(): Boolean;
var
  InstallPath: string; //not really used here
begin

  if RegQueryStringValue(HKEY_LOCAL_MACHINE, pyReg, '', InstallPath) then
    begin
    Result := True;
    end
  else
  if RegQueryStringValue(HKEY_CURRENT_USER, pyReg, '', InstallPath) then
    begin
    Result := True;
    end
  else
  if RegQueryStringValue(HKEY_LOCAL_MACHINE, pyRegWow6443Node, '', InstallPath) then
    begin
    Result := True;
    end
  else
    begin
    Result := False;
    end
end;

//////////////////////////////////////////////////////////////////////////////
procedure GetPythonPaths();
begin
  PythonPath := GetPathForPython();
  PythonSitePackagesPath := GetPathForPythonSitePackages(PythonPath);
  AppDirPath := PythonSitePackagesPath + AppDir;
end;

//////////////////////////////////////////////////////////////////////////////
function SetPythonPath(Param: String): String;
begin
  Result := PythonPath;
end;

//////////////////////////////////////////////////////////////////////////////
function SetPythonSitePackagesPath(Param: String): String;
begin
  Result := PythonSitePackagesPath;
end;

//////////////////////////////////////////////////////////////////////////////
function SetAppDirPath(Param: String): String;
begin
  Result := AppDirPath;
end;

//////////////////////////////////////////////////////////////////////////////
function IsInstalled(name: String): Boolean;
//function IsInstalled(name: string; version: string): boolean;  //ver not neeeded
var
  InstallPath: string;
  reg : string;
begin
  //reg := 'Software\' + name + '\' + version
  // + '\InstallPath'
  // Log('reg Python: ' + reg)

  //if Numpy/ matplotlib installed - direct check for file
  InstallPath := PythonSitePackagesPath + name + '/__init__.py'
  Log('install dir: ' + InstallPath)
  if FileExists(InstallPath) then
  //if RegQueryStringValue(HKEY_CURRENT_USER, reg, 'InstallPath', InstallPath) then
   //numpy doesnt have a reg entry! (also gets its install path, not used here)
    begin
    Result := True;
    end
  else
    begin
    Result := False;
    end;
end;

//////////////////////////////////////////////////////////////////////////////
procedure RunMsiInstaller(execName: string);
var
  ResultCode: Integer;
  ExecPath: String;
  ExecCommand: String;
begin
  ExecPath := ExpandConstant('{tmp}\') + execName;
  ExecCommand := '/i ' + ExecPath + ''; //+ ' /qb'; //qb does it silently

  //Check that the msi installer file is present
  if FileExists(ExecPath) then
    begin
    Log('ExecPath exists : ' + ExecPath);
    end
  else
    begin
    Log('ExecPath doe not exist : ' + ExecPath);
    MsgBox('Could not find ' + execName + ' installer',mbError,MB_OK);
    ExitProcess(1);
    //something went wrong: hell or high water python installer must be there
    end;

  //execute msi installer, otherwie error and exit
  if not ShellExec('', 'msiexec.exe', ExecCommand, '', SW_SHOWNORMAL,
                   ewWaitUntilTerminated, ResultCode) then
      //msi exec not working
      MsgBox('Msi installer failed to run!' + #13#10 + ExecCommand + ' ' +
             SysErrorMessage(ResultCode), mbError, MB_OK);
end;

//////////////////////////////////////////////////////////////////////////////
function InitializeSetup(): Boolean;
var
tmpPy: String;
begin
  //if python installed get path for python site-packages
  //if isInstalled('{#Py}\PythonCore','{#PyVer}') then
  if IsPythonInstalled() then
  begin
    Log('Python: ' + 'True');
    installPython := False;
    //Python must be installed, get its path
    GetPythonPaths();
    Log('SetDefaultAppDirName: ' + AppDirPath);
  end
  else //Add Python to tmp folder [ // or download list.. ]
  begin
    Log('Python: ' + 'False');
    installPython := True;
    tmpPy := ExpandConstant('{tmp}\{#PyInstaller}');
    //FileCopy(ExpandConstant('{#PyInstaller}'), tmpPy, false);
    ExtractTemporaryFile('{#PyInstaller}')
    Log('tmpPy: '+ tmpPy);

    AppDirPath := 'C:\Python27\Lib\site-packages\{#AppDir}' //pretend default path
                                                            //will be used when python is installed
                                                            //not seeing another way to prepopulate
                                                            //the Dir Destination page.
                                                            //installing Pyton earlier not an option
                                                            //as {tmp} was not created yet, so cant
                                                            //extract python installer yet
    //itd_addfile('{#PyInstallerURL}',ExpandConstant('{tmp}\{#PyInstaller}'));
    //itd_addfile('http://sbol.bhi.washington.edu/ppp/setup-dummyPython.exe',ExpandConstant('{tmp}\setup-dummyPython.exe'));
    PythonPath := 'C:\Python27';
    PythonSitePackagesPath := 'C:\Python27\Lib\site-packages\';
  end;

  Result := True; //Required for fwd progress, false would exist
end;

//////////////////////////////////////////////////////////////////////////////
procedure InitializeWizard();
begin
 //itd_init;  //turned off when packaging installers

  //Install Python now if needed, we want it in place before anything else is done
  if (installPython) then
     RunMsiInstaller('{#PyInstaller}');

  //Python must be installed, get its path
  GetPythonPaths();
  Log('SetDefaultAppDirName: ' + AppDirPath);

  //Check if Numpy is installed
  if IsInstalled('{#Numpy}') then
  //if IsInstalled('{#Numpy}','{#NumpyVer}') then  //ver not needed
    begin
    Log('Numpy: ' + 'True');
    installNumpy := False;
    end
  else
    //Add Numpy to d/l list
    begin
    Log('Numpy: ' + 'False');
    installNumpy := True;

    //filecopy(ExpandConstant('{#NumpyInstaller}'),ExpandConstant('{tmp}\{#NumpyInstaller}'),false);
    ExtractTemporaryFile('{#NumpyInstaller}');

    //The following were used to test downloader srategy
    //itd_addfile('http://sbol.bhi.washington.edu/ppp/setup-dummyNump.exe',
    //            ExpandConstant('{tmp}\setup-dummyNump.exe'));
    end;

  //Check if Matplotlib is installed
  if IsInstalled('{#Matplotlib}') then
  //if IsInstalled('{#Matplotlib}','{#MatplotlibVer}') then   //ver not needed
    begin
    Log('Matplotlib: ' + 'True');
    installMatplot := False;
    end
  else
    //Add Matplotlib to d/l list
    begin
    Log('Matplotlib: ' + 'False');
    installMatplot := True;

    //filecopy(ExpandConstant('{#MatplotlibInstaller}'),ExpandConstant('{tmp}\{#MatplotlibInstaller}'),false);
    ExtractTemporaryFile('{#MatplotlibInstaller}');
    //ExtractTemporaryFile('{#DateutilInstaller}');
    //ExtractTemporaryFile('{#PyparsingInstaller}');
    //ExtractTemporaryFile('{#SixInstaller}');

    //The following were used to test downloader srategy
    //td_addfile('http://sbol.bhi.washington.edu/ppp/setup-dummyMatplot.exe',
    //            ExpandConstant('{tmp}\setup-dummyMatplot.exe'));
    end;

  //Downloads turned off, packaging installers.
  //Start the download after the "Ready to install" screen is shown
  //itd_downloadafter(wpReady);
end;

//////////////////////////////////////////////////////////////////////////////
procedure RunOtherInstaller(execName: string);
var
  ResultCode: Integer;
begin
  if not Exec(ExpandConstant('{tmp}\' + execName), '', '', SW_SHOWNORMAL,
    ewWaitUntilTerminated, ResultCode)
  then
    MsgBox('Other installer failed to run!' + #13#10 + execName +
      SysErrorMessage(ResultCode), mbError, MB_OK);
end;

//////////////////////////////////////////////////////////////////////////////
// Install Numpy and Matplotlib if mising
procedure CurStepChanged(CurStep: TSetupStep);
var
   ResultCode: Integer;
begin
  if CurStep=ssInstall then //If on the installation step
  //Lets install those files that were downloaded for us
    begin
    if ForceDirectories(ExpandConstant('{app}')) then
      begin
      Log('app: ' + ExpandConstant('{app}'));
      if (installNumpy) then
        RunOtherInstaller('{#NumpyInstaller}');
      if (installMatplot) then
        begin
        RunOtherInstaller('{#MatplotlibInstaller}');
        //RunOtherInstaller('{#DateutilInstaller}');
        //RunOtherInstaller('{#PyparsingInstaller}');
        //RunOtherInstaller('{#SixInstaller}');
        end;
      end;
    end;
end;

//////////////////////////////////////////////////////////////////////////////
// Install tellurium mod in spyder
//procedure MakeTelSpyder(FileName: String);
//begin
    //tmpPy := ExpandConstant('{tmp}\{#PyInstaller}');
//    FileCopy(ExpandConstant('{tmp}\scientific_startup.py'), FileName, false);
//    Log(ExpandConstant('{tmp}\scientific_startup.py') + ' :to: ' + FileName)
//end;

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "tellurium"
;#define MyAppVersion "0.0.0"  read from file, see below
#define MyAppPublisher "University of Washington, Seattle, WA, USA"
#define MyAppURL "http://tellurium.analogmachine.org/"
#define MyAppSetupIconFile "tellurium_icon_64x64.ico"
#define ThisInstallerPostfix "win32-superpack-setup"

#define LibRoadRunnerInstaller "libroadrunner-1.0.1-win32-minimal-setup.exe"
#define AntimonyInstaller "AntimonyPythonBindings-2.5.1-win32.exe"
#define TelPluginsInstaller "telplugins-1.0.5-Python-2.7-win32-minimal-setup.exe"
#define PyInstaller "python-2.7.6.msi"
#define NumpyInstaller "numpy-1.8.0-win32-superpack-python2.7.exe"
#define MatplotlibInstaller "matplotlib-1.3.1.win32-py2.7.exe"
;#define DateutilInstaller "python-dateutil-2.2.win32-py2.7.exe"
;#define PyparsingInstaller "pyparsing-2.0.1.win32-py2.7.exe"
;#define SixInstaller "six-1.5.2.win32-py2.7.exe"

#define PyQtInstaller "PyQt4"
#define SipInstaller "sip.pyd"
#define PipInstaller "get-pip.py"
#define SpyderInstaller "spyder-2.2.5-tellurium-0.0.9.win32.exe"

;add spyder source
;then do ":python setup.py install" to install

;downloads turned off, installers packaged
;#define LibRoadRunnerInstallerURL "http://sourceforge.net/projects/libroadrunner/files/roadrunner-1.0.1-rc1-win32-minimal-setup.exe"
;#define AntimonyInstallerURL "http://sourceforge.net/projects/antimony/files/Windows%20binaries/2.5/AntimonyPythonBindings-2.5.0-win32.exe"
;#define PyInstallerURL "http://python.org/ftp/python/2.7.6/python-2.7.6.msi"
;#define NumpyInstallerURL "http://downloads.sourceforge.net/project/numpy/NumPy/1.8.0/numpy-1.8.0-win32-superpack-python2.7.exe?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fnumpy%2Ffiles%2FNumPy%2F&ts=1390956336&use_mirror=softlayer-ams"
;#define MatplotlibInstallerURL "https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-1.3.1/matplotlib-1.3.1.win32-py2.7.exe"
;#define DateutilInstallerURL "http://www.lfd.uci.edu/~gohlke/pythonlibs/#python-dateutil" ;there does not appear to be a direct URL to the file
;#define PyparsingInstallerURL "http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyparsing" The one from "http://downloads.sourceforge.net/project/pyparsing/pyparsing/pyparsing-2.0.1/pyparsing-2.0.1.win32-py2.7.exe" did not work.
;#define SixInstallerURL "http://www.lfd.uci.edu/~gohlke/pythonlibs/#six"
;#define PyQtInstallerURL "http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.10.3/PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x32.exe/download"
;#define SipInstallerURL "http://www.riverbankcomputing.com/software/sip/download" #using file from bin install
;#define PipInstallerURL "https://raw.github.com/pypa/pip/master/contrib/get-pip.py"
;#define SpyderInstaller "https://bitbucket.org/spyder-ide/spyderlib/downloads/spyder-2.2.5.win32.exe"

#define Py "Python"
#define PyVer "2.7"
#define Numpy "numpy"
;#define NumpyVer "1.0"
#define Matplotlib "matplotlib"
;#define MatplotlibVer "1.0"
#define AppDir "tellurium"
#define Pip "pip.exe"

#define VerFile FileOpen("../../VERSION.txt")
#define MyAppVersion FileRead(VerFile)
#expr FileClose(VerFile)
#undef VerFile

;Used for downloader
;#include ReadReg(HKEY_LOCAL_MACHINE,'Software\Sherlock Software\InnoTools\Downloader','ScriptPath','');

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{2EA1F666-39FE-4A26-BCC9-4D534219C9AE}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DisableWelcomePage=yes
DefaultDirName={code:SetAppDirPath}
;DefaultDirName=C:\Python27\Lib\site-packages\{#AppDir}

;enable the next line for debug only
;DisableDirPage=yes

;DefaultGroupName=libRoadRunner
DisableProgramGroupPage=yes
;LicenseFile=..\..\LICENSE
;InfoBeforeFile=..\..\NOTICE.txt
;InfoAfterFile=README.md
DisableReadyPage=yes
;DisableFinishedPage=yes   ;finished page is good feedback
OutputDir=.
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-{#Py}-{#PyVer}-{#ThisInstallerPostfix}
SetupIconFile={#MyAppSetupIconFile}
Compression=lzma
SolidCompression=yes

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

[Files]
Source: "../../startTellurium.py"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../__init__.py"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../examples/tellurium-files/*"; DestDir: "{userdocs}\tellurium-files"; Flags: ignoreversion recursesubdirs

Source: "../../NEWS.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../VERSION.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../README.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../NOTICE.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "super_installer_dependencies\{#LibRoadRunnerInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion
Source: "super_installer_dependencies\{#AntimonyInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion
Source: "super_installer_dependencies\{#TelPluginsInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion
Source: "libRoadrunner-installer-dependencies\{#MatplotlibInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
;-Source: "libRoadrunner-installer-dependencies\{#DateutilInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
;-Source: "libRoadrunner-installer-dependencies\{#PyparsingInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
;-Source: "libRoadrunner-installer-dependencies\{#SixInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
Source: "libRoadrunner-installer-dependencies\{#NumpyInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
Source: "libRoadrunner-installer-dependencies\{#PyInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
Source: "libRoadrunner-installer-dependencies\{#PipInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist

Source: "spyder_dependencies\{#PyQtInstaller}\*"; DestDir: "{code:SetPythonSitePackagesPath}\{#PyQtInstaller}"; Flags: ignoreversion onlyifdoesntexist recursesubdirs createallsubdirs
Source: "spyder_dependencies\{#SipInstaller}"; DestDir: "{code:SetPythonSitePackagesPath}"; Flags: ignoreversion onlyifdoesntexist
Source: "spyder_dependencies\{#SpyderInstaller}"; DestDir: "{tmp}"; Flags: ignoreversion onlyifdoesntexist
;Spyder installer is a custom distro with the following mod at the end of scientific_startup.py
;from tellurium import *

; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Run]
Filename: "{code:SetPythonPath}\python.exe"; Parameters: "{tmp}\{#PipInstaller}"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install python-dateutil"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install pyparsing"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install six"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized

Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install ipython[all]"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install sphinx"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install pyflakes"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install pylint"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install pep8"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{code:SetPythonPath}\scripts\{#Pip}"; Parameters: "install psutil"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{#LibRoadRunnerInstaller}"; Parameters: "/SILENT"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{#AntimonyInstaller}"; Parameters: "/SILENT"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{#TelPluginsInstaller}"; Parameters: "/SILENT"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{#SpyderInstaller}"; Parameters: "/SILENT"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized
Filename: "{app}\README.TXT"; Description: "View the README file"; Flags: postinstall shellexec skipifsilent unchecked
Filename: "{code:SetPythonPath}\pythonw.exe"; Parameters:"{code:SetPythonPath}\scripts\spyder -w {userdocs}\tellurium-files"; Description: "Run TeSpyder"; Flags: postinstall shellexec skipifsilent waituntilterminated

;SCIPY pip install has an error, may need a fortran compiler! mingw, but do we need Scipy?
;Filename: "{#Pip}"; Parameters: "install scipy"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized

;MATPLOTLIB, on pip install, cannot find vcvarsall.bat, a symptom of missing the 2008 VS++ <-seriously you need to install a compiler
;Filename: "{#Pip}"; Parameters: "install matplotlib"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized

;NUMPY, on pip install, cannot find vcvarsall.bat, a symptom of missing the 2008 VS++ <-seriously you need to install a compiler
;Filename: "{#Pip}"; Parameters: "install numpy"; WorkingDir: "{tmp}"; Flags: shellexec waituntilterminated runmaximized

[Code]
//////////////////////////////////////////////////////////////////////////////
const
  appDir = '{#AppDir}';
  pyReg = 'SOFTWARE\{#Py}\PythonCore\{#PyVer}\InstallPath';
  pyRegWow6443Node = 'SOFTWARE\Wow6432Node\{#Py}\PythonCore\{#PyVer}\InstallPath';

var
  installPython, installMatplot, installNumpy: Boolean;
  AppDirPath: String;
  PythonPath: String;
  PythonSitePackagesPath: String;

//////////////////////////////////////////////////////////////////////////////
procedure ExitProcess(exitCode:integer);
  external 'ExitProcess@kernel32.dll stdcall';

//////////////////////////////////////////////////////////////////////////////
function GetPathForPython(): string;
var
  InstallPath: string;
begin

  if RegQueryStringValue(HKEY_LOCAL_MACHINE, pyReg, '', InstallPath) then
    begin
    Log('HKLM pyReg: '+ InstallPath);
    Result := InstallPath;
    end
  else
  if RegQueryStringValue(HKEY_CURRENT_USER, pyReg, '', InstallPath) then
    begin
    Log('HKCU pyReg: '+ InstallPath);
    Result := InstallPath;
    end
  else
  if RegQueryStringValue(HKEY_LOCAL_MACHINE, pyRegWow6443Node, '', InstallPath) then
    begin
    Log('HKLM pyRegWow6443Node: '+ InstallPath);
    Result := InstallPath;
    end
  else
    begin
    MsgBox('Our installer did not find your Python installation. You need '
    + 'Python to run {#MyAppName}. In the next step use [Your Python installation'
    + ' location]\Lib\site-packages\{#AppDir} directory.',mbError,MB_OK);
    //ExitProcess(1);
    end
end;

//////////////////////////////////////////////////////////////////////////////
function GetPathForPythonSitePackages(PythonPath: String): string;
begin
  Result := PythonPath + 'Lib\site-packages\';
end;

//////////////////////////////////////////////////////////////////////////////
function IsPythonInstalled(): Boolean;
var
  InstallPath: string; //not really used here
begin

  if RegQueryStringValue(HKEY_LOCAL_MACHINE, pyReg, '', InstallPath) then
    begin
    Result := True;
    end
  else
  if RegQueryStringValue(HKEY_CURRENT_USER, pyReg, '', InstallPath) then
    begin
    Result := True;
    end
  else
  if RegQueryStringValue(HKEY_LOCAL_MACHINE, pyRegWow6443Node, '', InstallPath) then
    begin
    Result := True;
    end
  else
    begin
    Result := False;
    end
end;

//////////////////////////////////////////////////////////////////////////////
procedure GetPythonPaths();
begin
  PythonPath := GetPathForPython();
  PythonSitePackagesPath := GetPathForPythonSitePackages(PythonPath);
  AppDirPath := PythonSitePackagesPath + AppDir;
end;

//////////////////////////////////////////////////////////////////////////////
function SetPythonPath(Param: String): String;
begin
  Result := PythonPath;
end;

//////////////////////////////////////////////////////////////////////////////
function SetPythonSitePackagesPath(Param: String): String;
begin
  Result := PythonSitePackagesPath;
end;

//////////////////////////////////////////////////////////////////////////////
function SetAppDirPath(Param: String): String;
begin
  Result := AppDirPath;
end;

//////////////////////////////////////////////////////////////////////////////
function IsInstalled(name: String): Boolean;
//function IsInstalled(name: string; version: string): boolean;  //ver not neeeded
var
  InstallPath: string;
  reg : string;
begin
  //reg := 'Software\' + name + '\' + version
  // + '\InstallPath'
  // Log('reg Python: ' + reg)

  //if Numpy/ matplotlib installed - direct check for file
  InstallPath := PythonSitePackagesPath + name + '/__init__.py'
  Log('install dir: ' + InstallPath)
  if FileExists(InstallPath) then
  //if RegQueryStringValue(HKEY_CURRENT_USER, reg, 'InstallPath', InstallPath) then
   //numpy doesnt have a reg entry! (also gets its install path, not used here)
    begin
    Result := True;
    end
  else
    begin
    Result := False;
    end;
end;

//////////////////////////////////////////////////////////////////////////////
procedure RunMsiInstaller(execName: string);
var
  ResultCode: Integer;
  ExecPath: String;
  ExecCommand: String;
begin
  ExecPath := ExpandConstant('{tmp}\') + execName;
  ExecCommand := '/i ' + ExecPath + ''; //+ ' /qb'; //qb does it silently

  //Check that the msi installer file is present
  if FileExists(ExecPath) then
    begin
    Log('ExecPath exists : ' + ExecPath);
    end
  else
    begin
    Log('ExecPath doe not exist : ' + ExecPath);
    MsgBox('Could not find ' + execName + ' installer',mbError,MB_OK);
    ExitProcess(1);
    //something went wrong: hell or high water python installer must be there
    end;

  //execute msi installer, otherwie error and exit
  if not ShellExec('', 'msiexec.exe', ExecCommand, '', SW_SHOWNORMAL,
                   ewWaitUntilTerminated, ResultCode) then
      //msi exec not working
      MsgBox('Msi installer failed to run!' + #13#10 + ExecCommand + ' ' +
             SysErrorMessage(ResultCode), mbError, MB_OK);
end;

//////////////////////////////////////////////////////////////////////////////
function InitializeSetup(): Boolean;
var
tmpPy: String;
begin
  //if python installed get path for python site-packages
  //if isInstalled('{#Py}\PythonCore','{#PyVer}') then
  if IsPythonInstalled() then
  begin
    Log('Python: ' + 'True');
    installPython := False;
    //Python must be installed, get its path
    GetPythonPaths();
    Log('SetDefaultAppDirName: ' + AppDirPath);
  end
  else //Add Python to tmp folder [ // or download list.. ]
  begin
    Log('Python: ' + 'False');
    installPython := True;
    tmpPy := ExpandConstant('{tmp}\{#PyInstaller}');
    //FileCopy(ExpandConstant('{#PyInstaller}'), tmpPy, false);
    ExtractTemporaryFile('{#PyInstaller}')
    Log('tmpPy: '+ tmpPy);

    AppDirPath := 'C:\Python27\Lib\site-packages\{#AppDir}' //pretend default path
                                                            //will be used when python is installed
                                                            //not seeing another way to prepopulate
                                                            //the Dir Destination page.
                                                            //installing Pyton earlier not an option
                                                            //as {tmp} was not created yet, so cant
                                                            //extract python installer yet
    //itd_addfile('{#PyInstallerURL}',ExpandConstant('{tmp}\{#PyInstaller}'));
    //itd_addfile('http://sbol.bhi.washington.edu/ppp/setup-dummyPython.exe',ExpandConstant('{tmp}\setup-dummyPython.exe'));
    PythonPath := 'C:\Python27';
    PythonSitePackagesPath := 'C:\Python27\Lib\site-packages\';
  end;

  Result := True; //Required for fwd progress, false would exist
end;

//////////////////////////////////////////////////////////////////////////////
procedure InitializeWizard();
begin
 //itd_init;  //turned off when packaging installers

  //Install Python now if needed, we want it in place before anything else is done
  if (installPython) then
     RunMsiInstaller('{#PyInstaller}');

  //Python must be installed, get its path
  GetPythonPaths();
  Log('SetDefaultAppDirName: ' + AppDirPath);

  //Check if Numpy is installed
  if IsInstalled('{#Numpy}') then
  //if IsInstalled('{#Numpy}','{#NumpyVer}') then  //ver not needed
    begin
    Log('Numpy: ' + 'True');
    installNumpy := False;
    end
  else
    //Add Numpy to d/l list
    begin
    Log('Numpy: ' + 'False');
    installNumpy := True;

    //filecopy(ExpandConstant('{#NumpyInstaller}'),ExpandConstant('{tmp}\{#NumpyInstaller}'),false);
    ExtractTemporaryFile('{#NumpyInstaller}');

    //The following were used to test downloader srategy
    //itd_addfile('http://sbol.bhi.washington.edu/ppp/setup-dummyNump.exe',
    //            ExpandConstant('{tmp}\setup-dummyNump.exe'));
    end;

  //Check if Matplotlib is installed
  if IsInstalled('{#Matplotlib}') then
  //if IsInstalled('{#Matplotlib}','{#MatplotlibVer}') then   //ver not needed
    begin
    Log('Matplotlib: ' + 'True');
    installMatplot := False;
    end
  else
    //Add Matplotlib to d/l list
    begin
    Log('Matplotlib: ' + 'False');
    installMatplot := True;

    //filecopy(ExpandConstant('{#MatplotlibInstaller}'),ExpandConstant('{tmp}\{#MatplotlibInstaller}'),false);
    ExtractTemporaryFile('{#MatplotlibInstaller}');
    //ExtractTemporaryFile('{#DateutilInstaller}');
    //ExtractTemporaryFile('{#PyparsingInstaller}');
    //ExtractTemporaryFile('{#SixInstaller}');

    //The following were used to test downloader srategy
    //td_addfile('http://sbol.bhi.washington.edu/ppp/setup-dummyMatplot.exe',
    //            ExpandConstant('{tmp}\setup-dummyMatplot.exe'));
    end;

  //Downloads turned off, packaging installers.
  //Start the download after the "Ready to install" screen is shown
  //itd_downloadafter(wpReady);
end;

//////////////////////////////////////////////////////////////////////////////
procedure RunOtherInstaller(execName: string);
var
  ResultCode: Integer;
begin
  if not Exec(ExpandConstant('{tmp}\' + execName), '', '', SW_SHOWNORMAL,
    ewWaitUntilTerminated, ResultCode)
  then
    MsgBox('Other installer failed to run!' + #13#10 + execName +
      SysErrorMessage(ResultCode), mbError, MB_OK);
end;

//////////////////////////////////////////////////////////////////////////////
// Install Numpy and Matplotlib if mising
procedure CurStepChanged(CurStep: TSetupStep);
var
   ResultCode: Integer;
begin
  if CurStep=ssInstall then //If on the installation step
  //Lets install those files that were downloaded for us
    begin
    if ForceDirectories(ExpandConstant('{app}')) then
      begin
      Log('app: ' + ExpandConstant('{app}'));
      if (installNumpy) then
        RunOtherInstaller('{#NumpyInstaller}');
      if (installMatplot) then
        begin
        RunOtherInstaller('{#MatplotlibInstaller}');
        //RunOtherInstaller('{#DateutilInstaller}');
        //RunOtherInstaller('{#PyparsingInstaller}');
        //RunOtherInstaller('{#SixInstaller}');
        end;
      end;
    end;
end;

//////////////////////////////////////////////////////////////////////////////
// Install tellurium mod in spyder
//procedure MakeTelSpyder(FileName: String);
//begin
    //tmpPy := ExpandConstant('{tmp}\{#PyInstaller}');
//    FileCopy(ExpandConstant('{tmp}\scientific_startup.py'), FileName, false);
//    Log(ExpandConstant('{tmp}\scientific_startup.py') + ' :to: ' + FileName)
//end;


Yikes, I missed a ; -- :'(

Yikes, I missed a ; -- :'(

; RailsInstaller - InnoSetup Script
; Adaptation from RubyInstaller installer script
;

; PRE-CHECK
; Verify that RubyPath is defined by ISCC using
; /d command line arguments.
;
; Usage:
;  iscc rubyinstaller.iss /dInstallerVersion=0.1.0
;                         /dStagePath=stage
;                         /dRubyPath=Ruby/1.8.7
;                         [/dInstVersion=26-OCT-2009]

; Full example:
; iscc resouces\railsinstaller\railsinstaller.iss \
;       /dInstallerVersion=0.1.0 \
;       /dStagePath=stage \
;       /dRubyPath=Ruby1.8.7 \
;       /opkg
;       /frailsinstaller-0.1.0.exe

#if Defined(InstallerVersion) == 0
  #error Please provide a InstallerVersion definition using a /d parameter.
#endif

#if Defined(StagePath) == 0
  #error Please provide a StagePath value to the Ruby files using a /d parameter.
#endif

#if Defined(RubyPath) == 0
  #error Please provide a RubyPath value to the Ruby files using a /d parameter.
#else
  #if FileExists(StagePath + '/' + RubyPath + '\bin\ruby.exe') == 0
    #error No Ruby installation (bin\ruby.exe) found inside defined RubyPath. Please verify.
  #endif
#endif

#if Defined(InstVersion) == 0
  #define InstVersion GetDateTimeString('dd-mmm-yy"T"hhnn', '', '')
#endif

; Build Installer details using above values
#define InstallerName "RailsInstaller"
#define InstallerNameWithVersion InstallerName + " " + InstallerVersion
#define InstallerPublisher "RailsInstaller Team"
#define InstallerHomepage "http://www.railsinstaller.org/"

#define CurrentYear GetDateTimeString('yyyy', '', '')

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications!
AppId={{613C3EA5-1248-4E35-B61A-6D0B31BBC0DB}
AppName={#InstallerName}
AppVerName={#InstallerNameWithVersion}
AppPublisher={#InstallerPublisher}
AppPublisherURL={#InstallerHomepage}
AppVersion={#InstallerVersion}
DefaultGroupName={#InstallerName}
DefaultDirName={sd}\RailsInstaller
DisableProgramGroupPage=true
LicenseFile=LICENSE.txt
Compression=lzma2/ultra64
SolidCompression=true
AlwaysShowComponentsList=false
DisableReadyPage=true
InternalCompressLevel=ultra64
VersionInfoCompany={#InstallerPublisher}
VersionInfoCopyright=(c) {#CurrentYear} {#InstallerPublisher}
VersionInfoDescription=Rails development environment installer for Windows
VersionInfoTextVersion={#InstallerVersion}
VersionInfoVersion={#InstallerVersion}
UninstallDisplayIcon={app}\bin\ruby.exe
WizardImageFile={#ResourcesPath}\images\RailsInstallerWizardImage.bmp
WizardSmallImageFile={#ResourcesPath}\images\RailsInstallerWizardImageSmall.bmp
PrivilegesRequired=lowest
ChangesAssociations=yes
ChangesEnvironment=yes

#if Defined(SignPackage) == 1
SignTool=risigntool sign /a /d $q{#InstallerNameWithVersion}$q /du $q{#InstallerHomepage}$q /t $qhttp://timestamp.comodoca.com/authenticode$q $f
#endif

[Languages]
Name: en; MessagesFile: compiler:Default.isl

[Messages]
en.InstallingLabel=Installing [name], this will take a few minutes...
en.WelcomeLabel1=Welcome to [name] Installer!
en.WelcomeLabel2=This will install [name/ver] on your computer which includes Ruby 1.8.7, Git, Sqlite3, DevKit, and Rails 3.  Please close any console applications before continuing.
en.WizardLicense={#InstallerName} License Agreement
en.LicenseLabel=
en.LicenseLabel3=Please read the following License Agreements and accept the terms before continuing the installation.
en.LicenseAccepted=I &accept all of the Licenses
en.LicenseNotAccepted=I &decline any of the Licenses
en.WizardSelectDir=Installation Destination and Optional Tasks
en.SelectDirDesc=This is the location that Ruby, DevKit, Git, Rails and Sqlite will be installed to.
en.SelectDirLabel3=[name] will be installed into the following folder. Click Install to continue or click Browse to use a different one.
en.SelectDirBrowseLabel=Please avoid any folder name that contains spaces (e.g. Program Files).
en.DiskSpaceMBLabel=Required free disk space: ~[mb] MB

[Files]
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
Source: {#StagePath}\{#RubyPath}\*; DestDir: {app}\{#RubyPath}; Excludes: "devkit.*, operating_system.*"; Flags: recursesubdirs createallsubdirs
Source: {#StagePath}\Git\*; DestDir: {app}\Git; Flags: recursesubdirs createallsubdirs
Source: {#StagePath}\DevKit\*; DestDir: {app}\DevKit; Excludes: "config.yml"; Flags: recursesubdirs createallsubdirs
Source: {#StagePath}\DevKit\config.yml; DestDir: {app}\DevKit; AfterInstall: UpdateDevKitConfig('{app}\{#RubyPath}', '{app}\DevKit\config.yml')
Source: {#StagePath}\Sites\*; DestDir: {sd}\Sites; Flags: recursesubdirs createallsubdirs
Source: setup_environment.bat; DestDir: {app}\{#RubyPath}

[Registry]
; FIXME: Proper registry keys for RailsInstaller (admin)
;Root: HKLM; Subkey: Software\RailsInstaller; ValueType: string; ValueName: ; ValueData: ; Flags: uninsdeletevalue uninsdeletekeyifempty; Check: IsAdmin

; FIXME: Proper registry key for RailsInstaller (user)
;Root: HKCU; Subkey: Software\RailsInstaller; ValueType: string; ValueName: ; ValueData: ; Flags: uninsdeletevalue uninsdeletekeyifempty; Check: IsNotAdmin

[Icons]
Name: {group}\Interactive Ruby; Filename: {app}\{#RubyPath}\bin\irb.bat; IconFilename: {app}\{#RubyPath}\bin\ruby.exe; Flags: createonlyiffileexists
Name: {group}\RubyGems Documentation Server; Filename: {app}\{#RubyPath}\bin\gem.bat; Parameters: server; IconFilename: {app}\{#RubyPath}\bin\ruby.exe; Flags: createonlyiffileexists runminimized
Name: {group}\Command Prompt with Ruby and Rails; Filename: {sys}\cmd.exe; Parameters: /E:ON /K {app}\{#RubyPath}\setup_environment.bat; WorkingDir: {sd}\Sites; IconFilename: {sys}\cmd.exe; Flags: createonlyiffileexists
; {%HOMEPATH%}
Name: {group}\{cm:UninstallProgram,{#InstallerName}}; Filename: {uninstallexe}

[Run]
Filename: "{app}\{#RubyPath}\bin\ruby.exe"; Parameters: "dk.rb install --force"; WorkingDir: "{app}\DevKit"; Flags: runhidden

[Code]
#include "util.iss"
#include "railsinstaller_gui.iss"

function GetInstallDate(Param: String): String;
begin
  Result := GetDateTimeString('yyyymmdd', #0 , #0);
end;

procedure CurStepChanged(const CurStep: TSetupStep);
begin

  // TODO move into ssPostInstall just after install completes?
  if CurStep = ssInstall then
  begin
    if UsingWinNT then
    begin
      Log(Format('Selected Tasks - Path: %d', [PathChkBox.State]));

      if IsModifyPath then
        ModifyPath([ExpandConstant('{app}') + '\{#RubyPath}\bin']);
        ModifyPath([ExpandConstant('{app}') + '\Git\cmd']);

    end else
      MsgBox('Looks like you''ve got on older, unsupported Windows version.' #13 +
             'Proceeding with a reduced feature set installation.',
             mbInformation, MB_OK);
  end;
end;

procedure RegisterPreviousData(PreviousDataKey: Integer);
begin
  {* store install choices so we can use during uninstall *}
  if IsModifyPath then
    SetPreviousData(PreviousDataKey, 'PathModified', 'yes');

  SetPreviousData(PreviousDataKey, 'RailsInstallerId', '{#InstallerVersion}');
end;

procedure CurUninstallStepChanged(const CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep = usUninstall then
  begin
    if UsingWinNT then
    begin
      if GetPreviousData('PathModified', 'no') = 'yes' then
        ModifyPath([ExpandConstant('{app}') + '\{#RubyPath}\bin']);
        ModifyPath([ExpandConstant('{app}') + '\Git\cmd']);
    end;
  end;
end;

procedure UpdateDevKitConfig(RubyPath: string; FileName: string);
var
  S: String;
begin
  // Make YAML happy :-)
  S := ExpandConstant(RubyPath);
  StringChangeEx(S, '\', '/', True);

  // Update DevKit config.yml with the installation path
  SaveStringToFile(ExpandConstant(FileName), '- ' + S, False);
end;

; RailsInstaller - InnoSetup Script
; Adaptation from RubyInstaller installer script
;

; PRE-CHECK
; Verify that RubyPath is defined by ISCC using
; /d command line arguments.
;
; Usage:
;  iscc rubyinstaller.iss /dInstallerVersion=0.1.0
;                         /dStagePath=stage
;                         /dRubyPath=Ruby/1.8.7
;                         [/dInstVersion=26-OCT-2009]

; Full example:
; iscc resouces\railsinstaller\railsinstaller.iss \
;       /dInstallerVersion=0.1.0 \
;       /dStagePath=stage \
;       /dRubyPath=Ruby1.8.7 \
;       /opkg
;       /frailsinstaller-0.1.0.exe

#if Defined(InstallerVersion) == 0
  #error Please provide a InstallerVersion definition using a /d parameter.
#endif

#if Defined(StagePath) == 0
  #error Please provide a StagePath value to the Ruby files using a /d parameter.
#endif

#if Defined(RubyPath) == 0
  #error Please provide a RubyPath value to the Ruby files using a /d parameter.
#else
  #if FileExists(StagePath + '/' + RubyPath + '\bin\ruby.exe') == 0
    #error No Ruby installation (bin\ruby.exe) found inside defined RubyPath. Please verify.
  #endif
#endif

#if Defined(InstVersion) == 0
  #define InstVersion GetDateTimeString('dd-mmm-yy"T"hhnn', '', '')
#endif

; Build Installer details using above values
#define InstallerName "RailsInstaller"
#define InstallerNameWithVersion InstallerName + " " + InstallerVersion
#define InstallerPublisher "RailsInstaller Team"
#define InstallerHomepage "http://www.railsinstaller.org/"

#define CurrentYear GetDateTimeString('yyyy', '', '')

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications!
AppId={{613C3EA5-1248-4E35-B61A-6D0B31BBC0DB}
AppName={#InstallerName}
AppVerName={#InstallerNameWithVersion}
AppPublisher={#InstallerPublisher}
AppPublisherURL={#InstallerHomepage}
AppVersion={#InstallerVersion}
DefaultGroupName={#InstallerName}
DefaultDirName={sd}\RailsInstaller
DisableProgramGroupPage=true
LicenseFile=LICENSE.txt
Compression=lzma2/ultra64
SolidCompression=true
AlwaysShowComponentsList=false
DisableReadyPage=true
InternalCompressLevel=ultra64
VersionInfoCompany={#InstallerPublisher}
VersionInfoCopyright=(c) {#CurrentYear} {#InstallerPublisher}
VersionInfoDescription=Rails development environment installer for Windows
VersionInfoTextVersion={#InstallerVersion}
VersionInfoVersion={#InstallerVersion}
UninstallDisplayIcon={app}\bin\ruby.exe
WizardImageFile={#ResourcesPath}\images\RailsInstallerWizardImage.bmp
WizardSmallImageFile={#ResourcesPath}\images\RailsInstallerWizardImageSmall.bmp
PrivilegesRequired=lowest
ChangesAssociations=yes
ChangesEnvironment=yes

#if Defined(SignPackage) == 1
SignTool=risigntool sign /a /d $q{#InstallerNameWithVersion}$q /du $q{#InstallerHomepage}$q /t $qhttp://timestamp.comodoca.com/authenticode$q $f
#endif

[Languages]
Name: en; MessagesFile: compiler:Default.isl

[Messages]
en.InstallingLabel=Installing [name], this will take a few minutes...
en.WelcomeLabel1=Welcome to [name] Installer!
en.WelcomeLabel2=This will install [name/ver] on your computer which includes Ruby 1.8.7, Git, Sqlite3, DevKit, and Rails 3.  Please close any console applications before continuing.
en.WizardLicense={#InstallerName} License Agreement
en.LicenseLabel=
en.LicenseLabel3=Please read the following License Agreements and accept the terms before continuing the installation.
en.LicenseAccepted=I &accept all of the Licenses
en.LicenseNotAccepted=I &decline any of the Licenses
en.WizardSelectDir=Installation Destination and Optional Tasks
en.SelectDirDesc=This is the location that Ruby, DevKit, Git, Rails and Sqlite will be installed to.
en.SelectDirLabel3=[name] will be installed into the following folder. Click Install to continue or click Browse to use a different one.
en.SelectDirBrowseLabel=Please avoid any folder name that contains spaces (e.g. Program Files).
en.DiskSpaceMBLabel=Required free disk space: ~[mb] MB

[Files]
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
Source: {#StagePath}\{#RubyPath}\*; DestDir: {app}\{#RubyPath}; Excludes: "devkit.*, operating_system.*"; Flags: recursesubdirs createallsubdirs
Source: {#StagePath}\Git\*; DestDir: {app}\Git; Flags: recursesubdirs createallsubdirs
Source: {#StagePath}\DevKit\*; DestDir: {app}\DevKit; Excludes: config.yml Flags: recursesubdirs createallsubdirs
Source: {#StagePath}\DevKit\config.yml; DestDir: {app}\DevKit; AfterInstall: UpdateDevKitConfig('{app}\{#RubyPath}', '{app}\DevKit\config.yml')
Source: {#StagePath}\Sites\*; DestDir: {sd}\Sites; Flags: recursesubdirs createallsubdirs
Source: setup_environment.bat; DestDir: {app}\{#RubyPath}

[Registry]
; FIXME: Proper registry keys for RailsInstaller (admin)
;Root: HKLM; Subkey: Software\RailsInstaller; ValueType: string; ValueName: ; ValueData: ; Flags: uninsdeletevalue uninsdeletekeyifempty; Check: IsAdmin

; FIXME: Proper registry key for RailsInstaller (user)
;Root: HKCU; Subkey: Software\RailsInstaller; ValueType: string; ValueName: ; ValueData: ; Flags: uninsdeletevalue uninsdeletekeyifempty; Check: IsNotAdmin

[Icons]
Name: {group}\Interactive Ruby; Filename: {app}\{#RubyPath}\bin\irb.bat; IconFilename: {app}\{#RubyPath}\bin\ruby.exe; Flags: createonlyiffileexists
Name: {group}\RubyGems Documentation Server; Filename: {app}\{#RubyPath}\bin\gem.bat; Parameters: server; IconFilename: {app}\{#RubyPath}\bin\ruby.exe; Flags: createonlyiffileexists runminimized
Name: {group}\Command Prompt with Ruby and Rails; Filename: {sys}\cmd.exe; Parameters: /E:ON /K {app}\{#RubyPath}\setup_environment.bat; WorkingDir: {sd}\Sites; IconFilename: {sys}\cmd.exe; Flags: createonlyiffileexists
; {%HOMEPATH%}
Name: {group}\{cm:UninstallProgram,{#InstallerName}}; Filename: {uninstallexe}

[Run]
Filename: "{app}\{#RubyPath}\bin\ruby.exe"; Parameters: "dk.rb install --force"; WorkingDir: "{app}\DevKit"; Flags: runhidden

[Code]
#include "util.iss"
#include "railsinstaller_gui.iss"

function GetInstallDate(Param: String): String;
begin
  Result := GetDateTimeString('yyyymmdd', #0 , #0);
end;

procedure CurStepChanged(const CurStep: TSetupStep);
begin

  // TODO move into ssPostInstall just after install completes?
  if CurStep = ssInstall then
  begin
    if UsingWinNT then
    begin
      Log(Format('Selected Tasks - Path: %d', [PathChkBox.State]));

      if IsModifyPath then
        ModifyPath([ExpandConstant('{app}') + '\{#RubyPath}\bin']);
        ModifyPath([ExpandConstant('{app}') + '\Git\cmd']);

    end else
      MsgBox('Looks like you''ve got on older, unsupported Windows version.' #13 +
             'Proceeding with a reduced feature set installation.',
             mbInformation, MB_OK);
  end;
end;

procedure RegisterPreviousData(PreviousDataKey: Integer);
begin
  {* store install choices so we can use during uninstall *}
  if IsModifyPath then
    SetPreviousData(PreviousDataKey, 'PathModified', 'yes');

  SetPreviousData(PreviousDataKey, 'RailsInstallerId', '{#InstallerVersion}');
end;

procedure CurUninstallStepChanged(const CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep = usUninstall then
  begin
    if UsingWinNT then
    begin
      if GetPreviousData('PathModified', 'no') = 'yes' then
        ModifyPath([ExpandConstant('{app}') + '\{#RubyPath}\bin']);
        ModifyPath([ExpandConstant('{app}') + '\Git\cmd']);
    end;
  end;
end;

procedure UpdateDevKitConfig(RubyPath: string; FileName: string);
var
  S: String;
begin
  // Make YAML happy :-)
  S := ExpandConstant(RubyPath);
  StringChangeEx(S, '\', '/', True);

  // Update DevKit config.yml with the installation path
  SaveStringToFile(ExpandConstant(FileName), '- ' + S, False);
end;


Create sched task as current user on XP during install

#define MyAppName "KA Lite"
#define MyAppPublisher "Foundation for Learning Equality"
#define MyAppURL "http://learningequality.org/"
#define MyAppExeName "KA Lite.exe"

#define getKALiteVersion() \
    Local[1] = Exec(SourcePath+"\getversion.bat") == 0 ? StringChange(FileRead(FileOpen(SourcePath+"\version.temp")), " ", "") : "null"

#define TargetVersion = getKALiteVersion();

#expr DeleteFile(SourcePath+"\version.temp")

[Setup]
AppId={#MyAppName}-{#MyAppPublisher}
AppName={#MyAppName}
AppVersion={#TargetVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
LicenseFile=..\ka-lite\LICENSE
OutputDir=..\
OutputBaseFilename=KALiteSetup-{#TargetVersion}
SetupIconFile=logo48.ico
Compression=lzma
SolidCompression=yes
PrivilegesRequired=admin
UsePreviousAppDir=yes
ChangesEnvironment=yes

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

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "..\ka-lite\dist\ka-lite-static-*.zip"; DestDir: "{app}\ka-lite"
Source: "..\khan_assessment.zip"; DestDir: "{app}"
Source: "..\scripts\*.bat"; DestDir: "{app}\ka-lite\scripts\"
Source: "..\gui-packed\KA Lite.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\gui-packed\guitools.vbs"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\gui-packed\images\logo48.ico"; DestDir: "{app}\images"; Flags: ignoreversion
Source: "..\python-setup\*"; DestDir: "{app}\python-setup"; Flags: ignoreversion

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\images\logo48.ico"
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon ; IconFilename: "{app}\images\logo48.ico"

[Dirs]
Name: "{app}\"; Permissions: everyone-readexec

[InstallDelete]
Type: Files; Name: "{app}\*"

[UninstallDelete]
Type: filesandordirs; Name: "{app}\ka-lite*"
Type: files; Name: "{userstartup}\KA Lite.lnk"
Type: files; Name: "{app}\CONFIG.dat"

[Code]
var
  installFlag : boolean;
  startupFlag : string;
  ServerInformationPage : TInputQueryWizardPage;
  StartupPage : TInputOptionWizardPage;
  isUpgrade : boolean;
  stopServerCode: integer;
  removeOldGuiTool: integer;
  uninstallError: integer;
  saveDatabaseTemp : integer;
  cleanOldKaliteFolder : integer;
  restoreDatabaseTemp : integer;
  forceCancel : boolean;
  prevVerStr : string;

procedure InitializeWizard;
begin
    isUpgrade := False;
    forceCancel := False;

    if WizardForm.PrevAppDir <> nil then
    begin
        ShellExec('open', 'taskkill.exe', '/F /T /im "KA Lite.exe"', '', SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        ShellExec('open', 'tskill.exe', '"KA Lite"', '', SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        Exec(ExpandConstant('{cmd}'),'/C ka-lite\bin\windows\kalite.bat stop', WizardForm.PrevAppDir, SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        Exec(ExpandConstant('{cmd}'),'/C del winshortcut.vbs', WizardForm.PrevAppDir, SW_HIDE, ewWaitUntilTerminated, removeOldGuiTool);
    end;

    // Server data
    ServerInformationPage := CreateInputQueryPage(wpSelectDir,
    'Server Information', 'General data',
    'Please specify the server name and a description, then click Next. (you can leave blank both fields if you want to use the default server name or if you do not want to insert a description)');
    ServerInformationPage.Add('Server name:', False);
    ServerInformationPage.Add('Server description:', False);

    // Run at windows startup.
    StartupPage := CreateInputOptionPage(ServerInformationPage.ID,
    'Server Configuration', 'Startup configuration',
    'The server can run automatically. You may choose one of the following options:', True, False);
    StartupPage.Add('Run the server at windows startup');
    StartupPage.Add('Run the server when this user logs in');
    StartupPage.Add('Do not run the server at startup.');
    StartupPage.SelectedValueIndex := 2;
end;

procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
  if forceCancel = True then
  begin
    Confirm := False;
  end;
end;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
    result := False;
    if isUpgrade = True then
    begin
        if PageID = ServerInformationPage.ID then
        begin
            result := True;
        end;
        if PageID = wpSelectDir then
        begin
            result := True;
        end;
    end;
end;

procedure RemoveOldInstallation(targetPath : String);
begin
    WizardForm.Hide;
    if Not Exec(ExpandConstant('{cmd}'),'/C ( dir /b "unins***.exe" | findstr /r "unins[0-9][0-9][0-9].exe" ) > tempu & ( for /f "delims=" %A in ( tempu ) do call %A /SILENT /SUPPRESSMSGBOXES ) & del tempu', targetPath, SW_HIDE, ewWaitUntilTerminated, uninstallError) then
    begin
        Exec(ExpandConstant('{cmd}'),'/C mkdir '+ExpandConstant('{tmp}')+'\ka-lite\kalite\database & xcopy /y /s ka-lite\kalite\database\data.sqlite '+ExpandConstant('{tmp}')+'\ka-lite\kalite\database', targetPath, SW_HIDE, ewWaitUntilTerminated, saveDatabaseTemp);
        Exec(ExpandConstant('{cmd}'),'/C cd .. & del /q "'+targetPath+'\*" & for /d %x in ( "'+targetPath+'\*" ) do @rd /s /q "%x"', targetPath, SW_HIDE, ewWaitUntilTerminated, cleanOldKaliteFolder);
        Exec(ExpandConstant('{cmd}'),'/C mkdir ka-lite\kalite\database & xcopy /y /s '+ExpandConstant('{tmp}')+'\ka-lite\kalite\database\data.sqlite ka-lite\kalite\database', targetPath, SW_HIDE, ewWaitUntilTerminated, restoreDatabaseTemp);
    end;
    WizardForm.Show;
end;

{ Get the previous version number by checking the uninstall key registry values. }
{ IS writes quite a bit of information to the registry by default: https://github.com/jrsoftware/issrc/blob/5203240a7de9b83c5432bee0b5b09d467869a02b/Projects/Install.pas#L434 }
procedure GetPreviousVersion;
var
    subkey : String;
begin
    subkey := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\KA Lite-Foundation for Learning Equality_is1';
    prevVerStr := ''
    { 32-bit programs have a virtualized registry on 64-bit windows. So check all possible root keys. }
    if Not RegQueryStringValue(HKLM, subkey, 'DisplayVersion', prevVerStr) then
    begin
        if Not RegQueryStringValue(HKCU, subkey, 'DisplayVersion', prevVerStr) then
        begin
            if IsWin64 then
            begin
                if Not RegQueryStringValue(HKLM64, subkey, 'DisplayVersion', prevVerStr) then
                begin
                    if Not RegQueryStringValue(HKCU64, subkey, 'DisplayVersion', prevVerStr) then
                    begin
                        { Couldn't determine the previous version, so prevVerStr is '' }
                    end;
                end;
            end;
        end;
    end;
end;

procedure ConfirmUpgradeDialog;
begin
    if MsgBox('We have detected an existing KA Lite installation; would you like to upgrade?', mbInformation,  MB_YESNO or MB_DEFBUTTON1) = IDYES then
    begin
        isUpgrade := True;
    end
    else if MsgBox('Installing fresh will delete all of your existing data; is this what you really want to do?', mbInformation,  MB_YESNO or MB_DEFBUTTON2) = IDYES then
    begin
        isUpgrade := False;
    end
    else
    begin
        isUpgrade := True;
    end;
end;

{ Copy files a la the gitmigrate management command, but use native windows executables instead. }
{ We assume the installing user is the main user of the app, so content goes into that user's .kalite dir}
procedure DoGitMigrate;
var
    retCodeContent, retCodeDB, retCode : integer;
begin
    MsgBox('Migrating old data to current user''s %USERPROFILE%\.kalite\ directory.', mbInformation, MB_OK);
    Exec(ExpandConstant('{cmd}'), '/S /C "mkdir "%USERPROFILE%\.kalite""', '', SW_SHOW, ewWaitUntilTerminated, retCode);
    Exec(ExpandConstant('{cmd}'), '/S /C "xcopy "' + WizardForm.PrevAppDir + '\ka-lite\content" "%USERPROFILE%\.kalite\content\" /Y"', '', SW_SHOW, ewWaitUntilTerminated, retCodeContent);
    Exec(ExpandConstant('{cmd}'), '/S /C "xcopy "' + WizardForm.PrevAppDir + '\ka-lite\kalite\database" "%USERPROFILE%\.kalite\database\" /Y"', '', SW_SHOW, ewWaitUntilTerminated, retCodeDB);
    if (retCodeContent <> 0) or (retCodeDB <> 0) then
    begin
        MsgBox('Something went wrong! Unable to backup your data. Continuing installation.', mbError, MB_OK);
    end;
end;

procedure HandleUpgrade(targetPath : String);
begin
    GetPreviousVersion;
    if FileExists(targetPath + '\ka-lite\kalite\database\data.sqlite') then
    begin
        ConfirmUpgradeDialog;
        if Not isUpgrade then
        begin
            if Not DeleteFile(targetPath + '\ka-lite\kalite\database\data.sqlite') then
            begin
                MsgBox('Error' #13#13 'Failed to delete the old database as requested; aborting the install.', mbError, MB_OK);
                forceCancel := True;
                WizardForm.Close;
            end;
        end
        else
        begin
            { This is where version-specific migration stuff should happen. }
            if CompareStr(prevVerStr, '0.13.99') < 0 then
            begin
                if CompareStr('{#TargetVersion}', '0.14.0') >= 0 then
                begin
                    DoGitMigrate;
                end;
            end;
        end;
    { forceCancel will be true if something went awry in DoGitMigrate... abort instead of trampling the user's data. }
    if Not forceCancel then
        RemoveOldInstallation(targetPath);
    end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
    result := True;

    if CurPageID = wpLicense then
    begin
        if WizardForm.PrevAppDir <> nil then
            HandleUpgrade(WizardForm.PrevAppDir);
    end;

    if CurPageID = wpSelectDir then
    begin
        { Unclear what the logic here is. This is only executed if HandleUpgrade was not previously run. }
        if Not isUpgrade then
            HandleUpgrade(ExpandConstant('{app}'));
    end;
end;

procedure HandlePythonSetup;
var
    installPythonErrorCode : Integer;
begin
    if(MsgBox('Python 2.7.9+ is required to install KA Lite on Windows; do you wish to first install Python 2.7.10, before continuing with the installation of KA Lite?', mbConfirmation, MB_YESNO) = idYes) then
    begin
        ExtractTemporaryFile('python-2.7.10.msi');
        ShellExec('open', ExpandConstant('{tmp}')+'\python-2.7.10.msi', '', '', SW_SHOWNORMAL, ewWaitUntilTerminated, installPythonErrorCode);
    end
    else begin
        MsgBox('Error' #13#13 'You must have Python 2.7.9+ installed to proceed! Installation will now exit.', mbError, MB_OK);
        forceCancel := True;
        WizardForm.Close;
    end;
end;

{ Used in GetPipPath below }
const
    DEFAULT_PATH = '\Python27\Scripts\pip.exe';

{ Returns the path of pip.exe on the system. }
{ Tries several different locations before prompting user. }
function GetPipPath: string;
var
    path : string;
    i : integer;
begin
    for i := Ord('C') to Ord('H') do
    begin
        path := Chr(i) + ':' + DEFAULT_PATH;
        if FileExists(path) then
        begin
            Result := path;
            exit;
        end;
    end;
    MsgBox('Could not find pip.exe. Please select the location of pip.exe to continue installation.', mbInformation, MB_OK);
    if GetOpenFileName('Please select pip.exe', path, '', 'All files (*.*)|*.*', 'exe') then
    begin
        Result := path;
    end
    else begin
        MsgBox('Fatal error'#13#13'Please install pip and try again.', mbError, MB_OK);
        forceCancel := True;
        Result := '';
    end;
end;

procedure HandlePipSetup;
var
    PipCommand: string;
    PipPath: string;
    ErrorCode: integer;

begin
    PipPath := GetPipPath;
    if PipPath = '' then
        exit;
    PipCommand := 'install "' + ExpandConstant('{app}') + '\ka-lite\ka-lite-static-'  + '{#TargetVersion}' + '.zip"';

    MsgBox('Setup will now install kalite source files to your Python site-packages.', mbInformation, MB_OK);
    if not ShellExec('open', PipPath, PipCommand, '', SW_SHOW, ewWaitUntilTerminated, ErrorCode) then
    begin
      MsgBox('Critical error.' #13#13 'Dependencies have failed to install. Error Number: ' + IntToStr(ErrorCode), mbInformation, MB_OK);
      forceCancel := True;
      WizardForm.Close;
    end;

    { Must set this environment variable so the systray executable knows where to find the installed kalite.bat script}
    { Should by in the same directory as pip.exe, e.g. 'C:\Python27\Scripts' }
    RegWriteStringValue(
        HKLM,
        'System\CurrentControlSet\Control\Session Manager\Environment',
        'KALITE_SCRIPT_DIR',
        ExtractFileDir(PipPath)
    );
end;

function InitializeSetup(): Boolean;
var
  PythonVersionCodeCheck: integer;
  killErrorCode: integer;
begin
    installFlag:=true;
    Result := true;
    startupFlag:='';

    ShellExec('open', 'taskkill.exe', '/F /T /im "KA Lite.exe"', '', SW_HIDE, ewWaitUntilTerminated, killErrorCode)
    ShellExec('open', 'tskill.exe', ' "KA Lite"', '', SW_HIDE, ewWaitUntilTerminated, killErrorCode);

    RegDeleteValue(HKCU, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', ExpandConstant('{#MyAppName}'));

    if ShellExec('open', 'python.exe','-c "import sys; (sys.version_info >= (2, 7, 9,) and sys.version_info < (3,) and sys.exit(0)) or sys.exit(1)"', '', SW_HIDE, ewWaitUntilTerminated, PythonVersionCodeCheck) then
    begin
        if PythonVersionCodeCheck = 1 then
        begin
            HandlePythonSetup();
        end;
    end
    else
    begin
        HandlePythonSetup();
    end;
end;

function InitializeUninstall(): Boolean;
var
ErrorCode: Integer;
begin
  ShellExec('open', 'taskkill.exe', '/F /T /im "KA Lite.exe"', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  ShellExec('open', 'tskill.exe', '"KA Lite"', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  ShellExec('open', ExpandConstant('{app}') + '\ka-lite\bin\windows\kalite.bat stop', '', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  result := True;
end;

procedure DoSetup;
var
    retCode: integer;
begin
    { Used to have more responsibility, but we delegated those to the app itself! }
    { Unpacks the assessment items. }
    Exec(ExpandConstant('{cmd}'), '/S /C "' + ExpandConstant('"{reg:HKLM\System\CurrentControlSet\Control\Session Manager\Environment,KALITE_SCRIPT_DIR}\kalite.bat"') + ' manage unpack_assessment_zip khan_assessment.zip"', ExpandConstant('{app}'), SW_SHOW, ewWaitUntilTerminated, retCode);
end;

procedure CurStepChanged(CurStep: TSetupStep);
var
  StartupCode: integer;
  moveKaliteFolderTemp: integer;
  moveContentFolderTemp: integer;
  cleanKaliteFolder: integer;
  restoreKaliteFolder: integer;
  restoreContentFolder: integer;
  informationBoxFlagged: boolean;
  kaliteSchtaskCmd: string;
  windowsVersion: TWindowsVersion;

begin
    if CurStep = ssInstall then
    begin
        informationBoxFlagged :=False;

        ShellExec('open', 'taskkill.exe', '/F /T /im "KA Lite.exe"', '', SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        ShellExec('open', 'tskill.exe', '"KA Lite"', '', SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        Exec(ExpandConstant('{cmd}'),'/C ka-lite\bin\windows\kalite.bat stop', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        Exec(ExpandConstant('{cmd}'),'/C del winshortcut.vbs', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, removeOldGuiTool);

        if DirExists(ExpandConstant('{app}') + '\kalite') then
        begin
            MsgBox('KA Lite old data structure' #13#13 'Setup detected that you have the old file structure. Setup will now move data to update the structure. Please be patient; this may take some time.', mbInformation, MB_OK);
            informationBoxFlagged :=True;
            Exec(ExpandConstant('{cmd}'),'/C mkdir '+ExpandConstant('{tmp}')+'\ka-lite\kalite & xcopy /y /s kalite\* '+ExpandConstant('{tmp}')+'\ka-lite\kalite', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, moveKaliteFolderTemp);
        end;

        if DirExists(ExpandConstant('{app}') + '\content') then
        begin
            if Not informationBoxFlagged then
            begin
                MsgBox('KA Lite old data structure' #13#13 'Setup detected that you have the old file structure. Setup will now move data to update the structure. Please be patient; this may take some time.', mbInformation, MB_OK);
                informationBoxFlagged :=True;
            end;
            Exec(ExpandConstant('{cmd}'),'/C mkdir '+ExpandConstant('{tmp}')+'\ka-lite\content & xcopy /y /s content\* '+ExpandConstant('{tmp}')+'\ka-lite\content', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, moveContentFolderTemp);
        end;

        if informationBoxFlagged then
        begin
            Exec(ExpandConstant('{cmd}'),'/C cd .. & del /q "'+ExpandConstant('{app}')+'\*" & for /d %x in ( "'+ExpandConstant('{app}')+'\*" ) do @rd /s /q "%x"', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, cleanKaliteFolder);

            if DirExists(ExpandConstant('{tmp}')+'\ka-lite\kalite') then
            begin
                Exec(ExpandConstant('{cmd}'),'/C mkdir ka-lite\kalite & xcopy /y /s '+ExpandConstant('{tmp}')+'\ka-lite\kalite\* ka-lite\kalite', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, restoreKaliteFolder);
            end;

            if DirExists(ExpandConstant('{tmp}')+'\ka-lite\content') then
            begin
                Exec(ExpandConstant('{cmd}'),'/C mkdir ka-lite\content & xcopy /y /s '+ExpandConstant('{tmp}')+'\ka-lite\content\* ka-lite\content', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, restoreContentFolder);
            end;
        end;

    end;

    if CurStep = ssPostInstall then
    begin
        if installFlag then
        begin
            HandlePipSetup();

            if Not forceCancel then
            begin
                DoSetup;
            end;

            if StartupPage.SelectedValueIndex = 0 then
            begin
                GetWindowsVersionEx(windowsVersion);

                { Windows 5.1 is XP, and 5.2 is Server 2003/64-bit XP. See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx }
                if (windowsVersion.Major = 5) and (windowsVersion.Minor <= 2) then
                begin
                    kaliteSchtaskCmd := ExpandConstant('/C "schtasks /create /tn "KALite" /tr "\"{reg:HKLM\System\CurrentControlSet\Control\Session Manager\Environment,KALITE_SCRIPT_DIR}\kalite.bat\" start" /sc onstart"');
                end
                else begin
                    kaliteSchtaskCmd := ExpandConstant('/C "schtasks /create /tn "KALite" /tr "\"{reg:HKLM\System\CurrentControlSet\Control\Session Manager\Environment,KALITE_SCRIPT_DIR}\kalite.bat\" start" /sc onstart /ru SYSTEM"');
                end;

                if Exec(ExpandConstant('{cmd}'), kaliteSchtaskCmd, '', SW_HIDE, ewWaitUntilTerminated, StartupCode) then
                begin
                    if Not SaveStringToFile(ExpandConstant('{app}')+'\CONFIG.dat', 'RUN_AT_STARTUP:TRUE;' + #13#10, False) then
                    begin
                        MsgBox('Configuration file error.' #13#13 'Setup has failed to add the entry in the configuration file to run KA Lite at Windows startup. The installation may proceed and you can set this option later while using KA Lite.', mbError, MB_OK);
                    end;
                end
                else begin
                    MsgBox('GUI tools error.' #13#13 'Setup has failed to register a task to run KA Lite at Windows startup. The installation may proceed and you can set this option later while using KA Lite.', mbError, MB_OK);
                end;
            end
            else if StartupPage.SelectedValueIndex = 1 then
            begin
                if ShellExec('open', 'guitools.vbs', '0', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, StartupCode) then
                begin
                    if Not SaveStringToFile(ExpandConstant('{app}')+'\CONFIG.dat', 'RUN_AT_USER_LOGIN:TRUE;' + #13#10, False) then
                    begin
                        MsgBox('Configuration file error.' #13#13 'Setup has failed to add the entry in the configuration file to run KA Lite on user login. The installation may proceed and you can set this option later while using KA Lite.', mbError, MB_OK);
                    end;
                end
                else begin
                    MsgBox('GUI tools error.' #13#13 'Setup has failed to add the shortcut at the startup folder to run KA Lite on user login. The installation may proceed and you can set this option later while using KA Lite.', mbError, MB_OK);
                end;
            end;
        end;
    end;
end;

{ Called just prior to uninstall finishing. }
{ Clean up things we did during uninstall: }
{ * Remove environment variable KALITE_SCRIPT_DIR, which is set starting in version 0.16.x }
{ * Previously (versions 0.13.x to 0.15.x) KALITE_ROOT_DATA_PATH was set -- it should be unset by the respective }
{   uninstallers of those versions }
procedure DeinitializeUninstall();
begin
    RegDeleteValue(
        HKLM,
        'System\CurrentControlSet\Control\Session Manager\Environment',
        'KALITE_SCRIPT_DIR'
    )
end;

#define MyAppName "KA Lite"
#define MyAppPublisher "Foundation for Learning Equality"
#define MyAppURL "http://learningequality.org/"
#define MyAppExeName "KA Lite.exe"

#define getKALiteVersion() \
    Local[1] = Exec(SourcePath+"\getversion.bat") == 0 ? StringChange(FileRead(FileOpen(SourcePath+"\version.temp")), " ", "") : "null"

#define TargetVersion = getKALiteVersion();

#expr DeleteFile(SourcePath+"\version.temp")

[Setup]
AppId={#MyAppName}-{#MyAppPublisher}
AppName={#MyAppName}
AppVersion={#TargetVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
LicenseFile=..\ka-lite\LICENSE
OutputDir=..\
OutputBaseFilename=KALiteSetup-{#TargetVersion}
SetupIconFile=logo48.ico
Compression=lzma
SolidCompression=yes
PrivilegesRequired=admin
UsePreviousAppDir=yes
ChangesEnvironment=yes

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

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "..\ka-lite\dist\ka-lite-static-*.zip"; DestDir: "{app}\ka-lite"
Source: "..\khan_assessment.zip"; DestDir: "{app}"
Source: "..\scripts\*.bat"; DestDir: "{app}\ka-lite\scripts\"
Source: "..\gui-packed\KA Lite.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\gui-packed\guitools.vbs"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\gui-packed\images\logo48.ico"; DestDir: "{app}\images"; Flags: ignoreversion
Source: "..\python-setup\*"; DestDir: "{app}\python-setup"; Flags: ignoreversion

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\images\logo48.ico"
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon ; IconFilename: "{app}\images\logo48.ico"

[Dirs]
Name: "{app}\"; Permissions: everyone-readexec

[InstallDelete]
Type: Files; Name: "{app}\*"

[UninstallDelete]
Type: filesandordirs; Name: "{app}\ka-lite*"
Type: files; Name: "{userstartup}\KA Lite.lnk"
Type: files; Name: "{app}\CONFIG.dat"

[Code]
var
  installFlag : boolean;
  startupFlag : string;
  ServerInformationPage : TInputQueryWizardPage;
  StartupPage : TInputOptionWizardPage;
  isUpgrade : boolean;
  stopServerCode: integer;
  removeOldGuiTool: integer;
  uninstallError: integer;
  saveDatabaseTemp : integer;
  cleanOldKaliteFolder : integer;
  restoreDatabaseTemp : integer;
  forceCancel : boolean;
  prevVerStr : string;

procedure InitializeWizard;
begin
    isUpgrade := False;
    forceCancel := False;

    if WizardForm.PrevAppDir <> nil then
    begin
        ShellExec('open', 'taskkill.exe', '/F /T /im "KA Lite.exe"', '', SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        ShellExec('open', 'tskill.exe', '"KA Lite"', '', SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        Exec(ExpandConstant('{cmd}'),'/C ka-lite\bin\windows\kalite.bat stop', WizardForm.PrevAppDir, SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        Exec(ExpandConstant('{cmd}'),'/C del winshortcut.vbs', WizardForm.PrevAppDir, SW_HIDE, ewWaitUntilTerminated, removeOldGuiTool);
    end;

    // Server data
    ServerInformationPage := CreateInputQueryPage(wpSelectDir,
    'Server Information', 'General data',
    'Please specify the server name and a description, then click Next. (you can leave blank both fields if you want to use the default server name or if you do not want to insert a description)');
    ServerInformationPage.Add('Server name:', False);
    ServerInformationPage.Add('Server description:', False);

    // Run at windows startup.
    StartupPage := CreateInputOptionPage(ServerInformationPage.ID,
    'Server Configuration', 'Startup configuration',
    'The server can run automatically. You may choose one of the following options:', True, False);
    StartupPage.Add('Run the server at windows startup');
    StartupPage.Add('Run the server when this user logs in');
    StartupPage.Add('Do not run the server at startup.');
    StartupPage.SelectedValueIndex := 2;
end;

procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
  if forceCancel = True then
  begin
    Confirm := False;
  end;
end;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
    result := False;
    if isUpgrade = True then
    begin
        if PageID = ServerInformationPage.ID then
        begin
            result := True;
        end;
        if PageID = wpSelectDir then
        begin
            result := True;
        end;
    end;
end;

procedure RemoveOldInstallation(targetPath : String);
begin
    WizardForm.Hide;
    if Not Exec(ExpandConstant('{cmd}'),'/C ( dir /b "unins***.exe" | findstr /r "unins[0-9][0-9][0-9].exe" ) > tempu & ( for /f "delims=" %A in ( tempu ) do call %A /SILENT /SUPPRESSMSGBOXES ) & del tempu', targetPath, SW_HIDE, ewWaitUntilTerminated, uninstallError) then
    begin
        Exec(ExpandConstant('{cmd}'),'/C mkdir '+ExpandConstant('{tmp}')+'\ka-lite\kalite\database & xcopy /y /s ka-lite\kalite\database\data.sqlite '+ExpandConstant('{tmp}')+'\ka-lite\kalite\database', targetPath, SW_HIDE, ewWaitUntilTerminated, saveDatabaseTemp);
        Exec(ExpandConstant('{cmd}'),'/C cd .. & del /q "'+targetPath+'\*" & for /d %x in ( "'+targetPath+'\*" ) do @rd /s /q "%x"', targetPath, SW_HIDE, ewWaitUntilTerminated, cleanOldKaliteFolder);
        Exec(ExpandConstant('{cmd}'),'/C mkdir ka-lite\kalite\database & xcopy /y /s '+ExpandConstant('{tmp}')+'\ka-lite\kalite\database\data.sqlite ka-lite\kalite\database', targetPath, SW_HIDE, ewWaitUntilTerminated, restoreDatabaseTemp);
    end;
    WizardForm.Show;
end;

{ Get the previous version number by checking the uninstall key registry values. }
{ IS writes quite a bit of information to the registry by default: https://github.com/jrsoftware/issrc/blob/5203240a7de9b83c5432bee0b5b09d467869a02b/Projects/Install.pas#L434 }
procedure GetPreviousVersion;
var
    subkey : String;
begin
    subkey := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\KA Lite-Foundation for Learning Equality_is1';
    prevVerStr := ''
    { 32-bit programs have a virtualized registry on 64-bit windows. So check all possible root keys. }
    if Not RegQueryStringValue(HKLM, subkey, 'DisplayVersion', prevVerStr) then
    begin
        if Not RegQueryStringValue(HKCU, subkey, 'DisplayVersion', prevVerStr) then
        begin
            if IsWin64 then
            begin
                if Not RegQueryStringValue(HKLM64, subkey, 'DisplayVersion', prevVerStr) then
                begin
                    if Not RegQueryStringValue(HKCU64, subkey, 'DisplayVersion', prevVerStr) then
                    begin
                        { Couldn't determine the previous version, so prevVerStr is '' }
                    end;
                end;
            end;
        end;
    end;
end;

procedure ConfirmUpgradeDialog;
begin
    if MsgBox('We have detected an existing KA Lite installation; would you like to upgrade?', mbInformation,  MB_YESNO or MB_DEFBUTTON1) = IDYES then
    begin
        isUpgrade := True;
    end
    else if MsgBox('Installing fresh will delete all of your existing data; is this what you really want to do?', mbInformation,  MB_YESNO or MB_DEFBUTTON2) = IDYES then
    begin
        isUpgrade := False;
    end
    else
    begin
        isUpgrade := True;
    end;
end;

{ Copy files a la the gitmigrate management command, but use native windows executables instead. }
{ We assume the installing user is the main user of the app, so content goes into that user's .kalite dir}
procedure DoGitMigrate;
var
    retCodeContent, retCodeDB, retCode : integer;
begin
    MsgBox('Migrating old data to current user''s %USERPROFILE%\.kalite\ directory.', mbInformation, MB_OK);
    Exec(ExpandConstant('{cmd}'), '/S /C "mkdir "%USERPROFILE%\.kalite""', '', SW_SHOW, ewWaitUntilTerminated, retCode);
    Exec(ExpandConstant('{cmd}'), '/S /C "xcopy "' + WizardForm.PrevAppDir + '\ka-lite\content" "%USERPROFILE%\.kalite\content\" /Y"', '', SW_SHOW, ewWaitUntilTerminated, retCodeContent);
    Exec(ExpandConstant('{cmd}'), '/S /C "xcopy "' + WizardForm.PrevAppDir + '\ka-lite\kalite\database" "%USERPROFILE%\.kalite\database\" /Y"', '', SW_SHOW, ewWaitUntilTerminated, retCodeDB);
    if (retCodeContent <> 0) or (retCodeDB <> 0) then
    begin
        MsgBox('Something went wrong! Unable to backup your data. Continuing installation.', mbError, MB_OK);
    end;
end;

procedure HandleUpgrade(targetPath : String);
begin
    GetPreviousVersion;
    if FileExists(targetPath + '\ka-lite\kalite\database\data.sqlite') then
    begin
        ConfirmUpgradeDialog;
        if Not isUpgrade then
        begin
            if Not DeleteFile(targetPath + '\ka-lite\kalite\database\data.sqlite') then
            begin
                MsgBox('Error' #13#13 'Failed to delete the old database as requested; aborting the install.', mbError, MB_OK);
                forceCancel := True;
                WizardForm.Close;
            end;
        end
        else
        begin
            { This is where version-specific migration stuff should happen. }
            if CompareStr(prevVerStr, '0.13.99') < 0 then
            begin
                if CompareStr('{#TargetVersion}', '0.14.0') >= 0 then
                begin
                    DoGitMigrate;
                end;
            end;
        end;
    { forceCancel will be true if something went awry in DoGitMigrate... abort instead of trampling the user's data. }
    if Not forceCancel then
        RemoveOldInstallation(targetPath);
    end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
    result := True;

    if CurPageID = wpLicense then
    begin
        if WizardForm.PrevAppDir <> nil then
            HandleUpgrade(WizardForm.PrevAppDir);
    end;

    if CurPageID = wpSelectDir then
    begin
        { Unclear what the logic here is. This is only executed if HandleUpgrade was not previously run. }
        if Not isUpgrade then
            HandleUpgrade(ExpandConstant('{app}'));
    end;
end;

procedure HandlePythonSetup;
var
    installPythonErrorCode : Integer;
begin
    if(MsgBox('Python 2.7.9+ is required to install KA Lite on Windows; do you wish to first install Python 2.7.10, before continuing with the installation of KA Lite?', mbConfirmation, MB_YESNO) = idYes) then
    begin
        ExtractTemporaryFile('python-2.7.10.msi');
        ShellExec('open', ExpandConstant('{tmp}')+'\python-2.7.10.msi', '', '', SW_SHOWNORMAL, ewWaitUntilTerminated, installPythonErrorCode);
    end
    else begin
        MsgBox('Error' #13#13 'You must have Python 2.7.9+ installed to proceed! Installation will now exit.', mbError, MB_OK);
        forceCancel := True;
        WizardForm.Close;
    end;
end;

{ Used in GetPipPath below }
const
    DEFAULT_PATH = '\Python27\Scripts\pip.exe';

{ Returns the path of pip.exe on the system. }
{ Tries several different locations before prompting user. }
function GetPipPath: string;
var
    path : string;
    i : integer;
begin
    for i := Ord('C') to Ord('H') do
    begin
        path := Chr(i) + ':' + DEFAULT_PATH;
        if FileExists(path) then
        begin
            Result := path;
            exit;
        end;
    end;
    MsgBox('Could not find pip.exe. Please select the location of pip.exe to continue installation.', mbInformation, MB_OK);
    if GetOpenFileName('Please select pip.exe', path, '', 'All files (*.*)|*.*', 'exe') then
    begin
        Result := path;
    end
    else begin
        MsgBox('Fatal error'#13#13'Please install pip and try again.', mbError, MB_OK);
        forceCancel := True;
        Result := '';
    end;
end;

procedure HandlePipSetup;
var
    PipCommand: string;
    PipPath: string;
    ErrorCode: integer;

begin
    PipPath := GetPipPath;
    if PipPath = '' then
        exit;
    PipCommand := 'install "' + ExpandConstant('{app}') + '\ka-lite\ka-lite-static-'  + '{#TargetVersion}' + '.zip"';

    MsgBox('Setup will now install kalite source files to your Python site-packages.', mbInformation, MB_OK);
    if not ShellExec('open', PipPath, PipCommand, '', SW_SHOW, ewWaitUntilTerminated, ErrorCode) then
    begin
      MsgBox('Critical error.' #13#13 'Dependencies have failed to install. Error Number: ' + IntToStr(ErrorCode), mbInformation, MB_OK);
      forceCancel := True;
      WizardForm.Close;
    end;

    { Must set this environment variable so the systray executable knows where to find the installed kalite.bat script}
    { Should by in the same directory as pip.exe, e.g. 'C:\Python27\Scripts' }
    RegWriteStringValue(
        HKLM,
        'System\CurrentControlSet\Control\Session Manager\Environment',
        'KALITE_SCRIPT_DIR',
        ExtractFileDir(PipPath)
    );
end;

function InitializeSetup(): Boolean;
var
  PythonVersionCodeCheck: integer;
  killErrorCode: integer;
begin
    installFlag:=true;
    Result := true;
    startupFlag:='';

    ShellExec('open', 'taskkill.exe', '/F /T /im "KA Lite.exe"', '', SW_HIDE, ewWaitUntilTerminated, killErrorCode)
    ShellExec('open', 'tskill.exe', ' "KA Lite"', '', SW_HIDE, ewWaitUntilTerminated, killErrorCode);

    RegDeleteValue(HKCU, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', ExpandConstant('{#MyAppName}'));

    if ShellExec('open', 'python.exe','-c "import sys; (sys.version_info >= (2, 7, 9,) and sys.version_info < (3,) and sys.exit(0)) or sys.exit(1)"', '', SW_HIDE, ewWaitUntilTerminated, PythonVersionCodeCheck) then
    begin
        if PythonVersionCodeCheck = 1 then
        begin
            HandlePythonSetup();
        end;
    end
    else
    begin
        HandlePythonSetup();
    end;
end;

function InitializeUninstall(): Boolean;
var
ErrorCode: Integer;
begin
  ShellExec('open', 'taskkill.exe', '/F /T /im "KA Lite.exe"', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  ShellExec('open', 'tskill.exe', '"KA Lite"', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  ShellExec('open', ExpandConstant('{app}') + '\ka-lite\bin\windows\kalite.bat stop', '', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  result := True;
end;

procedure DoSetup;
var
    retCode: integer;
begin
    { Used to have more responsibility, but we delegated those to the app itself! }
    { Unpacks the assessment items. }
    Exec(ExpandConstant('{cmd}'), '/S /C "' + ExpandConstant('"{reg:HKLM\System\CurrentControlSet\Control\Session Manager\Environment,KALITE_SCRIPT_DIR}\kalite.bat"') + ' manage unpack_assessment_zip khan_assessment.zip"', ExpandConstant('{app}'), SW_SHOW, ewWaitUntilTerminated, retCode);
end;

procedure CurStepChanged(CurStep: TSetupStep);
var
  StartupCode: integer;
  moveKaliteFolderTemp: integer;
  moveContentFolderTemp: integer;
  cleanKaliteFolder: integer;
  restoreKaliteFolder: integer;
  restoreContentFolder: integer;
  informationBoxFlagged: boolean;

begin
    if CurStep = ssInstall then
    begin
        informationBoxFlagged :=False;

        ShellExec('open', 'taskkill.exe', '/F /T /im "KA Lite.exe"', '', SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        ShellExec('open', 'tskill.exe', '"KA Lite"', '', SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        Exec(ExpandConstant('{cmd}'),'/C ka-lite\bin\windows\kalite.bat stop', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, stopServerCode);
        Exec(ExpandConstant('{cmd}'),'/C del winshortcut.vbs', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, removeOldGuiTool);

        if DirExists(ExpandConstant('{app}') + '\kalite') then
        begin
            MsgBox('KA Lite old data structure' #13#13 'Setup detected that you have the old file structure. Setup will now move data to update the structure. Please be patient; this may take some time.', mbInformation, MB_OK);
            informationBoxFlagged :=True;
            Exec(ExpandConstant('{cmd}'),'/C mkdir '+ExpandConstant('{tmp}')+'\ka-lite\kalite & xcopy /y /s kalite\* '+ExpandConstant('{tmp}')+'\ka-lite\kalite', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, moveKaliteFolderTemp);
        end;

        if DirExists(ExpandConstant('{app}') + '\content') then
        begin
            if Not informationBoxFlagged then
            begin
                MsgBox('KA Lite old data structure' #13#13 'Setup detected that you have the old file structure. Setup will now move data to update the structure. Please be patient; this may take some time.', mbInformation, MB_OK);
                informationBoxFlagged :=True;
            end;
            Exec(ExpandConstant('{cmd}'),'/C mkdir '+ExpandConstant('{tmp}')+'\ka-lite\content & xcopy /y /s content\* '+ExpandConstant('{tmp}')+'\ka-lite\content', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, moveContentFolderTemp);
        end;

        if informationBoxFlagged then
        begin
            Exec(ExpandConstant('{cmd}'),'/C cd .. & del /q "'+ExpandConstant('{app}')+'\*" & for /d %x in ( "'+ExpandConstant('{app}')+'\*" ) do @rd /s /q "%x"', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, cleanKaliteFolder);

            if DirExists(ExpandConstant('{tmp}')+'\ka-lite\kalite') then
            begin
                Exec(ExpandConstant('{cmd}'),'/C mkdir ka-lite\kalite & xcopy /y /s '+ExpandConstant('{tmp}')+'\ka-lite\kalite\* ka-lite\kalite', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, restoreKaliteFolder);
            end;

            if DirExists(ExpandConstant('{tmp}')+'\ka-lite\content') then
            begin
                Exec(ExpandConstant('{cmd}'),'/C mkdir ka-lite\content & xcopy /y /s '+ExpandConstant('{tmp}')+'\ka-lite\content\* ka-lite\content', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, restoreContentFolder);
            end;
        end;

    end;

    if CurStep = ssPostInstall then
    begin
        if installFlag then
        begin
            HandlePipSetup();

            if Not forceCancel then
            begin
                DoSetup;
            end;

            if StartupPage.SelectedValueIndex = 0 then
            begin
                if Exec(ExpandConstant('{cmd}'), ExpandConstant('/C "schtasks /create /tn "KALite" /tr "\"{reg:HKLM\System\CurrentControlSet\Control\Session Manager\Environment,KALITE_SCRIPT_DIR}\kalite.bat\" start" /sc onstart /ru SYSTEM"'), '', SW_HIDE, ewWaitUntilTerminated, StartupCode) then
                begin
                    if Not SaveStringToFile(ExpandConstant('{app}')+'\CONFIG.dat', 'RUN_AT_STARTUP:TRUE;' + #13#10, False) then
                    begin
                        MsgBox('Configuration file error.' #13#13 'Setup has failed to add the entry in the configuration file to run KA Lite at Windows startup. The installation may proceed and you can set this option later while using KA Lite.', mbError, MB_OK);
                    end;
                end
                else begin
                    MsgBox('GUI tools error.' #13#13 'Setup has failed to register a task to run KA Lite at Windows startup. The installation may proceed and you can set this option later while using KA Lite.', mbError, MB_OK);
                end;
            end
            else if StartupPage.SelectedValueIndex = 1 then
            begin
                if ShellExec('open', 'guitools.vbs', '0', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, StartupCode) then
                begin
                    if Not SaveStringToFile(ExpandConstant('{app}')+'\CONFIG.dat', 'RUN_AT_USER_LOGIN:TRUE;' + #13#10, False) then
                    begin
                        MsgBox('Configuration file error.' #13#13 'Setup has failed to add the entry in the configuration file to run KA Lite on user login. The installation may proceed and you can set this option later while using KA Lite.', mbError, MB_OK);
                    end;
                end
                else begin
                    MsgBox('GUI tools error.' #13#13 'Setup has failed to add the shortcut at the startup folder to run KA Lite on user login. The installation may proceed and you can set this option later while using KA Lite.', mbError, MB_OK);
                end;
            end;
        end;
    end;
end;

{ Called just prior to uninstall finishing. }
{ Clean up things we did during uninstall: }
{ * Remove environment variable KALITE_SCRIPT_DIR, which is set starting in version 0.16.x }
{ * Previously (versions 0.13.x to 0.15.x) KALITE_ROOT_DATA_PATH was set -- it should be unset by the respective }
{   uninstallers of those versions }
procedure DeinitializeUninstall();
begin
    RegDeleteValue(
        HKLM,
        'System\CurrentControlSet\Control\Session Manager\Environment',
        'KALITE_SCRIPT_DIR'
    )
end;