function Install-SoftwarePackage($context, [string] $location, [string[]] $argumentList = @("/S"), [switch]$local) {
    . "$PSScriptRoot/Context.ps1";
    [Context]$context = $context;
    [string]$filePath = "";
    [string]$tempDir = $null;

    if (-not ($local.IsPresent)) {
        $tempDir = $context.GetTempDirectory();
        Write-Information "Determining the file name of $location";
        $fileName = ([uri]$location).Segments[-1];
        Write-Information "$fileName";
        $filePath = Join-Path $tempDir $fileName;

        Write-Information "Downloading setup file from $location";
        Invoke-WebRequest $location -OutFile $filePath;
    } else {
        $filePath = $location;
    }

    $fileName = [System.IO.Path]::GetFileName($filePath);
    Write-Information "Starting installation of $fileName";
    Start-Process -Wait -FilePath $filePath -ArgumentList $argumentList;

    if ($tempDir) {
        Remove-Item -Recurse $tempDir;
    }
}

<#
    .SYNOPSIS
    Checks whether the specified package has been installed using Chocolatey.

    .PARAMETER Name
    The name of the package to check.
#>
function Test-ChocoPackage {
    [OutputType([bool])]
    param(
        [string] $Name
    );

    -not [string]::IsNullOrEmpty((choco list --limit-output --exact $name));
}

<#
    .SYNOPSIS
    Checks whether a `winget` package with the specified id is installed.

    .PARAMETER ID
    The id of the package to check.
#>
function Test-WingetPackage {
    [OutputType([bool])]
    param(
        [string] $ID
    )

    & { $null = winget list --accept-source-agreements -e --id $ID; $?; };
}

<#
    .SYNOPSIS
    Checks whether a command with the specified name exists.

    .PARAMETER Name
    The name of the command to check.
#>
function Test-Command {
    param (
        [string] $Name
    )

    [bool] (Get-Command $Name -ErrorAction SilentlyContinue);
}

<#
    .SYNOPSIS
    Checks whether `winget` is working properly.
#>
function Test-Winget {
    (Test-Command winget) -and (
        & {
            $output = winget source update winget;

            $? -and -not ([System.Linq.Enumerable]::Any(
                [string[]]($output),
                [System.Func[string,bool]]{ param($line) $line -eq "Cancelled"; }));
        });
}

<#
    .SYNOPSIS
    Checks whether a package with the specified name is installed.

    .PARAMETER Name
    The name of the package to check.
#>
function Test-PSPackage {
    param(
        [string] $Name
    )

    [bool] (Get-Package $Name -ErrorAction SilentlyContinue);
}