Noveris.Logger.psm1

<#
#>


$script:LoggerTypes = @{}
$script:LoggerDefault = $null

$ErrorActionPreference = "Stop"

Class LoggerType
{
    [string]$Name
    [string]$Prefix
    [Nullable[System.ConsoleColor]]$Color
    [string]$LogPath
    [bool]$WriteHost
    [bool]$WriteOutput
    [ScriptBlock]$FormatBlock
    [ScriptBlock]$OutputBlock

    LoggerType([string]$Name)
    {
        $this.Name = $Name
        $this.Prefix = [string]::Empty
        $this.Color = $null
        $this.LogPath = [string]::Empty
        $this.WriteHost = $false
        $this.WriteOutput = $false
        $this.FormatBlock = $null
        $this.OutputBlock = $null
    }

    LoggerType([LoggerType] $loggerType)
    {
        $this.Name = $loggerType.Name
        $this.Prefix = $loggerType.Prefix
        $this.Color = $loggerType.Color
        $this.LogPath = $loggerType.LogPath
        $this.WriteHost = $loggerType.WriteHost
        $this.WriteOutput = $loggerType.WriteOutput
        $this.FormatBlock = $loggerType.FormatBlock
        $this.OutputBlock = $loggerType.OutputBlock
    }
}

<#
#>

Function New-LoggerType
{
    param(
        [Parameter(Mandatory=$true,Position=0)]
        [string]$Name,

        [Parameter(Mandatory=$false)]
        [string]$Prefix = [string]::Empty,

        [Parameter(Mandatory=$false)]
        [Nullable[System.ConsoleColor]]$Color = $null,

        [Parameter(Mandatory=$false)]
        [string]$LogPath = [string]::Empty,

        [Parameter(Mandatory=$false)]
        [switch]$WriteHost = $false,

        [Parameter(Mandatory=$false)]
        [switch]$WriteOutput = $false,

        [Parameter(Mandatory=$false)]
        [ScriptBlock]$FormatBlock = $null,

        [Parameter(Mandatory=$false)]
        [ScriptBlock]$OutputBlock = $null,

        [Parameter(Mandatory=$false)]
        [switch]$Default = $false
    )

    if ([string]::IsNullOrEmpty($Name))
    {
        throw New-Object ArgumentException -ArgumentList "Name supplied to New-Logger is null or empty"
    }

    if ($script:LoggerTypes.ContainsKey($Name))
    {
        throw New-Object ArgumentException -ArgumentList "Name supplied to New-Logger already exists"
    }

    $newType = New-Object LoggerType -ArgumentList $Name
    $newType.WriteHost = $WriteHost
    $newType.WriteOutput = $WriteOutput

    foreach ($param in $PSBoundParameters.Keys)
    {
        switch ($param)
        {
            "Prefix" {
                $newType.Prefix = $Prefix
                break
            }
            "Color" {
                $newType.Color = $Color
                break
            }
            "LogPath" {
                $newType.LogPath = $LogPath
                break
            }
            "FormatBlock" {
                $newType.FormatBlock = $FormatBlock
                break
            }
            "OutputBlock" {
                $newType.OutputBlock = $OutputBlock
                break
            }
        }
    }

    $script:LoggerTypes[$Name] = $newType

    if ($Default)
    {
        $script:LoggerDefault = $Name
    }

    Get-LoggerType $Name
}

<#
#>

Function Get-LoggerType
{
    param(
        [Parameter(Mandatory=$false,Position=0)]
        [string]$Name = [string]::Empty
    )

    $types = $script:LoggerTypes.Keys
    if ($PSBoundParameters.Keys -contains "Name" -and ![string]::IsNullOrEmpty($Name))
    {
        if (!$script:LoggerTypes.ContainsKey($Name))
        {
            throw New-Object ArgumentException -ArgumentList "Name supplied to Get-LoggerType does not exist"
        }

        $types = $($Name)
    }

    $types | ForEach-Object { New-Object LoggerType -ArgumentList $script:LoggerTypes[$_] }
}

<#
#>

Function Update-LoggerType
{
    param(
        [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName)]
        [string]$Name,

        [Parameter(Mandatory=$false)]
        $Prefix = $null,

        [Parameter(Mandatory=$false)]
        [Nullable[System.ConsoleColor]]$Color = $null,

        [Parameter(Mandatory=$false)]
        $LogPath = $null,

        [Parameter(Mandatory=$false)]
        [switch]$WriteHost = $null,

        [Parameter(Mandatory=$false)]
        [switch]$WriteOutput = $null,

        [Parameter(Mandatory=$false)]
        [ScriptBlock]$FormatBlock = $null,

        [Parameter(Mandatory=$false)]
        [ScriptBlock]$OutputBlock = $null,

        [Parameter(Mandatory=$false)]
        [switch]$RemoveFormatBlock = $false,

        [Parameter(Mandatory=$false)]
        [switch]$RemoveOutputBlock = $false,

        [Parameter(Mandatory=$false)]
        [switch]$Default = $false
    )

    process
    {
        if ([string]::IsNullOrEmpty($Name))
        {
            throw New-Object ArgumentException -ArgumentList "Null or empty Name supplied to Update-LoggerType"
        }

        if (!$script:LoggerTypes.ContainsKey($Name))
        {
            throw New-Object ArgumentException -ArgumentList "Name supplied to Update-LoggerType does not exist"
        }

        $loggerType = $script:LoggerTypes[$Name]

        if ($RemoveFormatBlock)
        {
            $loggerType.FormatBlock = $null
        }

        if ($RemoveOutputBlock)
        {
            $loggerType.OutputBlock = $null
        }

        foreach ($param in $PSBoundParameters.Keys)
        {
            switch ($param)
            {
                "Prefix" {
                    $loggerType.Prefix = $Prefix
                    break
                }
                "Color" {
                    $loggerType.Color = $Color
                    break
                }
                "LogPath" {
                    $loggerType.LogPath = $LogPath
                    break
                }
                "WriteHost" {
                    $loggerType.WriteHost = $WriteHost
                    break
                }
                "WriteOutput" {
                    $loggerType.WriteOutput = $WriteOutput
                    break
                }
                "FormatBlock" {
                    $loggerType.FormatBlock = $FormatBlock
                    break
                }
                "OutputBlock" {
                    $loggerType.OutputBlock = $OutputBlock
                    break
                }
                "Default" {
                    if ($Default -eq $true)
                    {
                        $script:LoggerDefault = $Name
                        break
                    }

                    if ($script:LoggerDefault -eq $Name)
                    {
                        $script:LoggerDefault = $null
                    }
                }
            }
        }

        Get-LoggerType $Name
    }
}

<#
#>

Function Remove-LoggerType
{
    param(
        [Parameter(Mandatory=$true,Position=0)]
        [string]$Name
    )

    if ([string]::IsNullOrEmpty($Name))
    {
        throw New-Object ArgumentException -ArgumentList "Null or empty Name passed to Remove-LoggerType"
    }

    if (!$script:LoggerTypes.ContainsKey($Name))
    {
        return
    }

    $null = $script:LoggerTypes.Remove($Name)

    if ($script:LoggerDefault -ne $null -and $script:LoggerDefault -eq $Name)
    {
        $script:LoggerDefault = $null
    }
}

<#
#>

Function Get-DefaultLoggerType
{
    if ([string]::IsNullOrEmpty($script:LoggerDefault))
    {
        return
    }

    if (!$script:LoggerTypes.Contains($script:LoggerDefault))
    {
        # Shouldn't happen - just assume there isn't a default
        return
    }

    Get-LoggerType $script:LoggerDefault
}

<#
#>

Function Reset-DefaultLoggerType
{
    $script:LoggerDefault = $null
}

<#
#>

Function Write-Logger
{
    param(
        [Parameter(Mandatory=$true,Position=0)]
        [string]$Message,
        
        [Parameter(Mandatory=$false)]
        [string]$Name = [string]::Empty
    )

    # Determine LoggerType name to use
    $LogTypeName = $script:LoggerDefault
    if ($PSBoundParameters.Keys -contains "Name")
    {
        $LogTypeName = $Name
    }

    if ([string]::IsNullOrEmpty($LogTypeName) -or !$script:LoggerTypes.Contains($LogTypeName))
    {
        throw New-Object ArgumentException -ArgumentList "Logger type supplied or default logger (${Name}) does not exist"
    }

    # Get LoggerType
    $type = $script:LoggerTypes[$LogTypeName]

    # Determine colour to use. Default to Grey
    $color = $type.Color
    if ($color -eq $null)
    {
        $color = [System.ConsoleColor]::Gray
    }

    $msg = $Message

    # Use format block to pre-process message, if defined
    if ($type.FormatBlock -ne $null)
    {
        $msg = ($msg | ForEach-Object $type.FormatBlock).ToString()
    }

    # Add prefix to message
    if (![string]::IsNullOrEmpty($type.Prefix))
    {
        $msg = [string]::Format("{0}{1}", $type.Prefix, $msg)
    }

    # Write host output, if required
    if ($type.WriteHost)
    {
        Write-Host -ForegroundColor $color $msg
    }

    # Write object output, if required
    if ($type.WriteOutput)
    {
        Write-Output $msg
    }

    # Write to file, if defined
    if (![string]::IsNullOrEmpty($type.LogPath))
    {
        $msg | Out-File -Append -FilePath $type.LogPath -Encoding UTF8
    }

    # Send message to script block, if defined
    if ($type.OutputBlock -ne $null)
    {
        $null = $msg | ForEach-Object $type.OutputBlock
    }
}