# encoding: ascii
# api: powershell
# title: Write-Console
# description: Writes a message to the console with colored foreground and background. Given messages are split on word boundaries into lines, and each line is padded to $Limit length in order to allow the background color of the message to extend to $Limit consistently.
# version: 0.1
# type: function
# author: jpbruckler
# license: CC0
# function: Write-Console
# x-poshcode-id: 5524
# x-archived: 2014-10-20T18:39:36
# x-published: 2014-10-18T17:25:00
#
# Current implementation breaks down when $Limit is small (10-ish or less)
#
Function Write-Console
{
  <#
    .SYNOPSIS
      Writes colored and wrapped messages to the console using Write-Host
    .DESCRIPTION
      Outputs a given message to the console host wrapped at a given character
      count. The wrapping behavior splits at word boundaries to create lines.
      Each line is then padded to the count provided by the Limit parameter so
      that the colored output is consistent length.
    .PARAMETER Message
      [string] The message to write to the console.
    .PARAMETER Limit
      [int] The maximum string length for any given line of text.
    .PARAMETER Type
      [string] Defines what type of message to output (affects coloring).
      Defaults to Success.
      Possible values:
        Error - Dark red background, light red text
        Success - Dark green background, light green text
        Warning - Black background, yellow text
    .INPUTS
      [string] The message to be printed to the screen.
    .OUTPUTS
      None.
    .EXAMPLE
      PS C:\> Write-Console -Message 'This is a really long message that should be split at 30 characters.' -Limit 30
  #>
  param(
    [Parameter(Mandatory=$true)]
    [string] $Message,
    [int] $Limit = 72,
    [ValidateSet('Error','Warning','Success')]
    [string] $Type = 'Success'
  )

  begin
  {
    $SB = New-Object System.Text.StringBuilder
    $Lines = New-Object System.Collections.ArrayList
    $Words = New-Object System.Collections.ArrayList
  }

  process
  {
    # Setup console colors
    switch ($Type)
    {
      'Success' { $FG = 'Green'; $BG = 'DarkGreen' }
      'Error'   { $FG = 'Red'; $BG = 'DarkRed' }
      'Warning' { $FG = 'Yellow'; $BG = 'Black'}
    }
    
    # Split the input string by spaces, then by length.
    $Message -split ' ' | ForEach-Object {
      if ($PSItem.Length -gt $Limit)
      {
        $Split = [math]::Ceiling($PSItem.Length/$Limit)
        $Parts = [regex]::Split($PSitem,$Split,$Limit)
        $Split
        foreach($Part in $Parts)
        {
          $Part
          $null = $Words.Add($Part)
        }
      }
      else
      {
        $null = $Words.Add($PSItem)
      }
    }
    
    $c = $Words.Count
    for ($i=0;$i -le $c;$i++)
    {     
      # Last word/line case
      if ($i -eq $c)
      {
        $Line = $SB.ToString().PadRight($Limit,' ')
        $null = $SB.Clear()
        $null = $Lines.Add($Line)
        $null = $SB.Append("$($Words[$i]) ")
        break;
      }

      # If the current length of SB plus the Word is less than
      # the defined limit, add Word to SB
      if ($SB.Length + ($Words[$i].Length + 1) -le $Limit)
      {
        $null = $SB.Append("$($Words[$i]) ")
      }
      # If the current length of Word puts SB over limit, then
      # pad SB to Limit, add it to the Lines array, clear SB
      # then add the current Word
      else
      {
        $Line = $SB.ToString().PadRight($Limit,' ')
        $null = $SB.Clear()
        $null = $Lines.Add($Line)
        $null = $SB.Append("$($Words[$i]) ")
      }

    }

    foreach ($Line in $Lines)
    {
      Write-Host $Line -ForegroundColor $FG -BackgroundColor $BG
    }
  }

  end
  {
    $SB,$Lines,$Words = $null
  }
}
