ReportingHelper.psm1

#region Private Parser Functions and Variables

# REGISTER TYPE ACCELERATORS
$_ps_accelerators = [System.Management.Automation.PSObject].Assembly.GetType('System.Management.Automation.TypeAccelerators', $true, $true) 
if( -not ($_ps_accelerators::Get.ContainsKey("TaskStates"))) { $_ps_accelerators::Add("TaskStates","Logging.TaskStates") }

$KpmgCssStandardStyle = @'
<style>
body {
        font-family: Arial,Sans-Serif;
        font-size: 12px;
     }
td, th {
        border:0;
        border-collapse: collapse;
        text-align: left;
       }
td {
        border-bottom: 1px solid #999999;
        color: #333333;
        padding: 4px 10px;
    }
th {
        color:white;
        background-color: #00338D;
        padding: 8px 10px;
    }
h1 {
        font-size: 18px;
        color: #333333;
        margin:4px 0px 4px 0px;
    }
h2,h3 {
        font-size: 12px;
        color: #666666;
        margin:4px 0px 4px 0px;
    }
p {
        font-size: 9px;
        color: #666666;
        margin:0px 0px 6px 0px;
    }
br { line-height: 18px; }
table, h1,h2,h3,p { margin-left:15px; }
</style>
'@


<# Returns the FQDN with uppercase host part and lowercase domain part #>
function Format-FqdnLabelCase
{
    [CmdletBinding()]
    param
    (
        [Parameter(Position=0, Mandatory=$true)]
        [AllowEmptyString()]
        [string]$Fqdn
    )

    if([string]::IsNullOrWhiteSpace($Fqdn)) { return '' }

    $splitFqdn = "$Fqdn".Split('.')

    for($idx = 0; $idx -lt $splitFqdn.Length; $idx++)
    {
        if($idx -eq 0)
        {
            $splitFqdn[$idx] = "$($splitFqdn[$idx])".ToUpper()
        }
        else
        {
            $splitFqdn[$idx] = "$($splitFqdn[$idx])".ToLower()
        }
    }

    return "$($splitFqdn -join '.')"
}

#endregion

function Initialize-ProgressTracker
{
    [CmdletBinding()]
    [OutputType([void])]
    param
    (
        # ItemList
        [Parameter(Mandatory=$true)]
        [string[]]$ItemList,

        # TaskList
        [Parameter(Mandatory=$true)]
        [string[]]$TaskList
    )

    Begin
    {
        $FunctionName = $MyInvocation.MyCommand.Name

        $AltRowBackColor        = "#f8f8f8"
        $DefaultTableStyle      = "margin-left:15px; font-family: Arial,Sans-Serif; font-size: 12px; border-collapse:collapse;"
        $DefaultCellStyle       = "border:1px solid #cccccc; border-collapse:collapse; color:#333333; padding:4px 10px; border-bottom: 1px solid #999999;"
        $DefaultCellStyleAltRow = "background-color:$AltRowBackColor; $DefaultCellStyle"
    }

    Process
    {
        $ErrPref = $ErrorActionPreference
        $ErrorActionPreference = 'Stop'

        try
        {
            [Logging.ProgressTracker]::InitializeTracker($ItemList, $TaskList)

        # [Logging.ReportManager]::ColumnsDisplayNames.SequenceGroupName = "Account Name"

            [Logging.ReportManager]::InlineStyleTable        = $DefaultTableStyle
            [Logging.ReportManager]::InlineStyleHeaderRow    = "border:0; border-collapse:collapse; text-align:center; color:white; background-color:#00338D; padding: 8px 10px;"
            [Logging.ReportManager]::InlineStyleHeaderColumn = ""

            [Logging.ReportManager]::InlineCellStyleItemName = "$DefaultCellStyle text-align:left; border-left:1px solid #999999; border-right:1px solid #999999;"

            [Logging.ReportManager]::InlineCellStyleSequenceInfo    = "$DefaultCellStyle text-align:left;"
            [Logging.ReportManager]::InlineCellStyleSequenceComment = "$DefaultCellStyle text-align:left; border-right: 1px solid #999999;"
            [Logging.ReportManager]::InlineCellStyleTaskResult      = "$DefaultCellStyle text-align:center;"

            [Logging.ReportManager]::InlineCellStyleAltRowSequenceInfo    = "$DefaultCellStyleAltRow text-align:left;"
            [Logging.ReportManager]::InlineCellStyleAltRowSequenceComment = "$DefaultCellStyleAltRow text-align:left; border-right: 1px solid #999999;"
            [Logging.ReportManager]::InlineCellStyleAltRowTaskResult      = "$DefaultCellStyleAltRow text-align:center;"
        }
        catch
        {
            Write-Error -Exception "$_" -Message "$_" -Category NotSpecified -ErrorId 0 -TargetObject $FunctionName -ErrorAction $errPref
        }
    }

    End
    {

    }
}

function New-HtmlFormattedParagraph
{
    [CmdletBinding()]
    [OutputType([void])]
    param
    (
        # Text
        [Parameter(Mandatory=$false)]
        [string]$Text = "",

        # Format
        [Parameter(Mandatory=$false)]
        [ValidateSet("Heading1","Heading2","Heading3","Paragraph","LineBreak")]
        [string]$Format = "Paragraph"
    )

    Begin
    {
        $FunctionName = $MyInvocation.MyCommand.Name
    }
    
    Process
    {
        $errPref = $ErrorActionPreference
        $ErrorActionPreference = 'Stop'
        
        try
        {
            switch($Format)
            {
                "Heading1"  { return ('<h1 style="font-family:Arial,Sans-Serif; font-size:12px; font-size:18px; color:#333333; margin:4px 0px 4px 0px; margin-left:15px;">{0}</h1>' -f $Text); }
                "Heading2"    { return ('<h2 style="font-family:Arial,Sans-Serif; font-size:12px; font-size:12px; color:#666666; margin:4px 0px 4px 0px; margin-left:15px;">{0}</h2>' -f $Text); }
                "Heading3"    { return ('<h3 style="font-family:Arial,Sans-Serif; font-size:12px; font-size:12px; color:#666666; margin:4px 0px 4px 0px; margin-left:15px;">{0}</h3>' -f $Text); }
                "Paragraph"    { return ('<p style="font-family:Arial,Sans-Serif; font-size:9px; font-size:12px; color:#666666; margin:0px 0px 6px 0px; margin-left:15px;">{0}</p>' -f $Text); }
                "LineBreak"    { return ('<br style="line-height: 18px;"/>'); }
            }
        }
        catch
        {
            Write-Error -Exception "$_" -Message "$_" -Category NotSpecified -ErrorId 0 -TargetObject $FunctionName -ErrorAction $errPref
        }
    }
    
    End
    {
        
    }
}

#region htmldoc dsl functions

function htmldoc
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true,Position=0)]
        [scriptblock]$Body,

        [Parameter(Mandatory=$false,Position=1)]
        [string]$CssStyle,

        [Parameter(Mandatory=$false,Position=2)]
        [string]$JSScript
    )

    begin
    {

    }

    process
    {
        #Default CssStyle
        $CssStyleToUse = Get-Content -Path "$PSScriptRoot\resources\styles.css" -Raw -ErrorAction Stop

        #CssStyle definition
        if ($PSBoundParameters.ContainsKey('CssStyle'))
        {
            $CssStyleToUse += $CssStyle
        }

        #JSFilePath definition
        if ($PSBoundParameters.ContainsKey('JSScript'))
        {
            $JavaScriptTouse = $JSScript
        }

        #Build Result
        $Result = @(
            "<html>"
            "<head>"
            #"<link rel=`"stylesheet`" type=`"text/css`" href=`"$PSScriptRoot\resources\styles.css`"/>"
            "<style>"
            "$CssStyleToUse"
            "</style>"
            "</head>"
            "<body>"
            "$(& $Body)"
            "<script>"
            "$JavaScriptTouse"
            "</script>"
            "</body>"
            "<html>"
        )

        #Return Result
        $StringBuilder = New-Object -TypeName System.Text.StringBuilder -ErrorAction Stop
        foreach ($line in $Result)
        {
            $null = $StringBuilder.AppendLine($line)
        }
        $StringBuilder.ToString()
    }
}

function paragraph
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true,Position=0)]
        [hashtable]$Attributes,

        [Parameter(Mandatory=$true,Position=1)]
        [scriptblock]$Body
    )

    process
    {
        #Process Attributes
        if ($PSBoundParameters.ContainsKey('Attributes'))
        {
            #Check for Custom Style
            if ($Attributes.ContainsKey('style'))
            {
                $CustomStyle = $Attributes['style']
            }

            #Check for Custom Class
            if ($Attributes.ContainsKey('class'))
            {
                $CustomClass = $Attributes['class']
            }
        }

        #Build Result
        $Result = @(
            "<p style=`"$CustomStyle`" class=`"$CustomClass`">$(& $Body)</p>"
        )

        #Return Result
        $StringBuilder = New-Object -TypeName System.Text.StringBuilder -ErrorAction Stop
        foreach ($line in $Result)
        {
            $null = $StringBuilder.AppendLine($line)
        }
        $StringBuilder.ToString()
    }
}

function table
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true,Position=1)]
        [scriptblock]$Body
    )

    process
    {
        #Build Result
        $Result = @(
            "<div style=`"display:inline-block; border:1px solid #000`">$(& $Body)</div>"
        )
        
        #Return Result
        $StringBuilder = New-Object -TypeName System.Text.StringBuilder -ErrorAction Stop
        foreach ($line in $Result)
        {
            $null = $StringBuilder.AppendLine($line)
        }
        $StringBuilder.ToString()
    }
}

function table-column
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true,Position=0)]
        [string]$Label,

        [Parameter(Mandatory=$false,Position=1)]
        [hashtable]$style,

        [Parameter(Mandatory=$true,Position=3)]
        [scriptblock]$Body
    )

    process
    {
        #Process Styles
        if ($PSBoundParameters.ContainsKey('Style'))
        {
            #Check for Custom Class
            if ($style.ContainsKey('class'))
            {
                $CustomClass = " $($style['class'] -join ' ')"
            }

            #Check for Custom Width
            if ($style.ContainsKey('width'))
            {
                $CustomWidth = $style['width']
            }

            #Check for white-space
            if ($style.ContainsKey('white-space'))
            {
                $CustomWhiteSpace = $style['white-space']
            }
        }

        #Build Result
        $Result = @(
            "<div style=`"display:table-cell; border:1px solid #000; width:$CustomWidth; white-space:$CustomWhiteSpace;`">"
            "<div style=`"display:table-row; border:1px solid #000; white-space:$CustomWhiteSpace;`" class=`"label`">$Label</div>"
        )
        
        #Check if Body contains SubElements
        $CheckForSubElements = Get-AstStatement -Ast $Body.Ast -Type CommandAst | Where-Object {$SubElements -contains $_.GetCommandname()}
        if ($CheckForSubElements)
        {
            #In case Body contains SubElements
            $Result += "<div style=`"display:table-row; border:1px solid #000; white-space:$CustomWhiteSpace;`">$(& $Body)</div>"
        }
        else
        {
            #In case Body contains only Data
            $Result += "<div style=`"display:table-row; border:1px solid #000; white-space:$CustomWhiteSpace;`" class=`"cell$CustomClass`">$(& $Body)</div>"
        }
        $Result += '</div>'

        #Return Result
        $StringBuilder = New-Object -TypeName System.Text.StringBuilder -ErrorAction Stop
        foreach ($line in $Result)
        {
            $null = $StringBuilder.AppendLine($line)
        }
        $StringBuilder.ToString()
    }
}

function table-row
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true,Position=1)]
        [scriptblock]$Body
    )

    process
    {
        #Build Result
        $Result = @(
            "<div style=`"display:table-row; border:1px solid #000`">$(& $Body)</div>"
        )

        #Return Result
        $StringBuilder = New-Object -TypeName System.Text.StringBuilder -ErrorAction Stop
        foreach ($line in $Result)
        {
            $null = $StringBuilder.AppendLine($line)
        }
        $StringBuilder.ToString()
    }
}

#endregion

#region htmldoc dsl variables

$SubElements = @(
    'table-column'
    'table-row'
    'table'
)

#endregion