// ----------------------------------------------------------------------------
//
// Inno Setup Ver:  5.4.2
// Script Version:  1.4.2
// Author:          Jared Breland <jbreland@legroom.net>
// Homepage:        http://www.legroom.net/software
// License:         GNU Lesser General Public License (LGPL), version 3
//                  http://www.gnu.org/licenses/lgpl.html
//
// Script Function:
//  Allow modification of environmental path directly from Inno Setup installers
//
// Instructions:
//  Copy modpath.iss to the same directory as your setup script
//
//  Add this statement to your [Setup] section
//      ChangesEnvironment=true
//
//  Add this statement to your [Tasks] section
//  You can change the Description or Flags
//  You can change the Name, but it must match the ModPathName setting below
//      Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked
//
//  Add the following to the end of your [Code] section
//  ModPathName defines the name of the task defined above
//  ModPathType defines whether the 'user' or 'system' path will be modified;
//      this will default to user if anything other than system is set
//  setArrayLength must specify the total number of dirs to be added
//  Result[0] contains first directory, Result[1] contains second, etc.
//      const
//          ModPathName = 'modifypath';
//          ModPathType = 'user';
//
//      function ModPathDir(): TArrayOfString;
//      begin
//          setArrayLength(Result, 1);
//          Result[0] := ExpandConstant('{app}');
//      end;
//      #include "modpath.iss"
// ----------------------------------------------------------------------------

procedure ModPath();
var
    oldpath:    String;
    newpath:    String;
    updatepath: Boolean;
    pathArr:    TArrayOfString;
    aExecFile:  String;
    aExecArr:   TArrayOfString;
    i, d:       Integer;
    pathdir:    TArrayOfString;
    regroot:    Integer;
    regpath:    String;

begin
    // Get constants from main script and adjust behavior accordingly
    // ModPathType MUST be 'system' or 'user'; force 'user' if invalid
    if ModPathType = 'system' then begin
        regroot := HKEY_LOCAL_MACHINE;
        regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
    end else begin
        regroot := HKEY_CURRENT_USER;
        regpath := 'Environment';
    end;

    // Get array of new directories and act on each individually
    pathdir := ModPathDir();
    for d := 0 to GetArrayLength(pathdir)-1 do begin
        updatepath := true;

        // Modify WinNT path
        if UsingWinNT() = true then begin

            // Get current path, split into an array
            RegQueryStringValue(regroot, regpath, 'Path', oldpath);
            oldpath := oldpath + ';';
            i := 0;

            while (Pos(';', oldpath) > 0) do begin
                SetArrayLength(pathArr, i+1);
                pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
                oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
                i := i + 1;

                // Check if current directory matches app dir
                if pathdir[d] = pathArr[i-1] then begin
                    // if uninstalling, remove dir from path
                    if IsUninstaller() = true then begin
                        continue;
                    // if installing, flag that dir already exists in path
                    end else begin
                        updatepath := false;
                    end;
                end;

                // Add current directory to new path
                if i = 1 then begin
                    newpath := pathArr[i-1];
                end else begin
                    newpath := newpath + ';' + pathArr[i-1];
                end;
            end;

            // Append app dir to path if not already included
            if (IsUninstaller() = false) AND (updatepath = true) then
                newpath := newpath + ';' + pathdir[d];

            // Write new path
            RegWriteStringValue(regroot, regpath, 'Path', newpath);

        // Modify Win9x path
        end else begin

            // Convert to shortened dirname
            pathdir[d] := GetShortName(pathdir[d]);

            // If autoexec.bat exists, check if app dir already exists in path
            aExecFile := 'C:\AUTOEXEC.BAT';
            if FileExists(aExecFile) then begin
                LoadStringsFromFile(aExecFile, aExecArr);
                for i := 0 to GetArrayLength(aExecArr)-1 do begin
                    if IsUninstaller() = false then begin
                        // If app dir already exists while installing, skip add
                        if (Pos(pathdir[d], aExecArr[i]) > 0) then
                            updatepath := false;
                            break;
                    end else begin
                        // If app dir exists and = what we originally set, then delete at uninstall
                        if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
                            aExecArr[i] := '';
                    end;
                end;
            end;

            // If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path
            if (IsUninstaller() = false) AND (updatepath = true) then begin
                SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True);

            // If uninstalling, write the full autoexec out
            end else begin
                SaveStringsToFile(aExecFile, aExecArr, False);
            end;
        end;
    end;
end;

// Split a string into an array using passed delimeter
procedure MPExplode(var Dest: TArrayOfString; Text: String; Separator: String);
var
    i: Integer;
begin
    i := 0;
    repeat
        SetArrayLength(Dest, i+1);
        if Pos(Separator,Text) > 0 then begin
            Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1);
            Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text));
            i := i + 1;
        end else begin
             Dest[i] := Text;
             Text := '';
        end;
    until Length(Text)=0;
end;


procedure CurStepChanged(CurStep: TSetupStep);
var
    taskname:   String;
begin
    taskname := ModPathName;
    if CurStep = ssPostInstall then
        if WizardIsTaskSelected(taskname) then
            ModPath();
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
    aSelectedTasks: TArrayOfString;
    i:              Integer;
    taskname:       String;
    regpath:        String;
    regstring:      String;
    appid:          String;
begin
    // only run during actual uninstall
    if CurUninstallStep = usUninstall then begin
        // get list of selected tasks saved in registry at install time
        appid := '{#emit SetupSetting("AppId")}';
        if appid = '' then appid := '{#emit SetupSetting("AppName")}';
        regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1');
        RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring);
        if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring);

        // check each task; if matches modpath taskname, trigger patch removal
        if regstring <> '' then begin
            taskname := ModPathName;
            MPExplode(aSelectedTasks, regstring, ',');
            if GetArrayLength(aSelectedTasks) > 0 then begin
                for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin
                    if comparetext(aSelectedTasks[i], taskname) = 0 then
                        ModPath();
                end;
            end;
        end;
    end;
end;

function NeedRestart(): Boolean;
var
    taskname:   String;
begin
    taskname := ModPathName;
    if WizardIsTaskSelected(taskname) and not UsingWinNT() then begin
        Result := True;
    end else begin
        Result := False;
    end;
end;
