Classes/PSColorStyle.ps1

<#
.SYNOPSIS
    PSColorStyle class for managing reusable color and style configurations

.DESCRIPTION
    The PSColorStyle class provides a comprehensive system for defining and managing
    color and style profiles for Write-ColorEX output. It implements a singleton pattern
    for default styles and a named profiles system for common output patterns.

    KEY FEATURES:
    - Singleton default style accessible via [PSColorStyle]::Default
    - Named profile collection via [PSColorStyle]::Profiles
    - Built-in profiles: Default, Error, Warning, Info, Success, Critical, Debug
    - Performance-optimized parameter caching (36x faster with ToWriteColorParams())
    - Full support for all Write-ColorEX features including AutoPad
    - Clone method for creating style variations

    USAGE PATTERN:
    - Create custom styles with New-ColorStyle function
    - Access built-in profiles: [PSColorStyle]::Profiles['Error']
    - Set default style: $style.SetAsDefault()
    - Register profiles: $style.AddToProfiles()

.NOTES
    Author: MarkusMcNugen
    License: MIT
    Requires: PowerShell 5.1 or later

    This class is automatically loaded when the PSWriteColorEX module is imported.
    Default profiles are initialized via InitializeDefaultProfiles() static method.

.LINK
    https://github.com/MarkusMcNugen/PSWriteColorEX

.LINK
    New-ColorStyle

.LINK
    Set-ColorDefault

.EXAMPLE
    # Create and register a custom style
    $style = [PSColorStyle]::new("Header", "Cyan", $null)
    $style.Bold = $true
    $style.Underline = $true
    $style.HorizontalCenter = $true
    $style.AddToProfiles()

.EXAMPLE
    # Use a built-in profile
    $errorStyle = [PSColorStyle]::Profiles['Error']
    Write-ColorEX -Text "Failed!" -StyleProfile $errorStyle

.EXAMPLE
    # Clone and modify a profile
    $customError = [PSColorStyle]::Profiles['Error'].Clone()
    $customError.Name = "MyError"
    $customError.Italic = $true
#>


class PSColorStyle {
    [string]$Name
    [object]$ForegroundColor
    [object]$BackgroundColor
    [object[]]$Gradient
    [string[]]$Style
    [int]$StartTab
    [int]$StartSpaces
    [int]$LinesBefore
    [int]$LinesAfter
    [bool]$Bold
    [bool]$Italic
    [bool]$Underline
    [bool]$Blink
    [bool]$Faint
    [bool]$CrossedOut
    [bool]$DoubleUnderline
    [bool]$Overline
    [bool]$ShowTime
    [bool]$NoNewLine
    [bool]$HorizontalCenter
    [int]$AutoPad = 0
    [bool]$PadLeft = $false
    [char]$PadChar = ' '

    # Static property for singleton default instance
    static [PSColorStyle]$Default

    # Static property for named profiles
    static [hashtable]$Profiles = @{}

    # Hidden cached params hashtable
    hidden [hashtable]$_cachedParams = $null

    # Constructor
    PSColorStyle() {
        $this.Initialize("Custom", "Gray", $null)
    }
    
    PSColorStyle([string]$name) {
        $this.Initialize($name, "Gray", $null)
    }
    
    PSColorStyle([string]$name, [object]$foreground, [object]$background) {
        $this.Initialize($name, $foreground, $background)
    }
    
    hidden [void]Initialize([string]$name, [object]$foreground, [object]$background) {
        $this.Name = $name
        $this.ForegroundColor = $foreground
        $this.BackgroundColor = $background
        $this.Gradient = $null
        $this.Style = @()
        $this.StartTab = 0
        $this.StartSpaces = 0
        $this.LinesBefore = 0
        $this.LinesAfter = 0
        $this.Bold = $false
        $this.Italic = $false
        $this.Underline = $false
        $this.Blink = $false
        $this.Faint = $false
        $this.CrossedOut = $false
        $this.DoubleUnderline = $false
        $this.Overline = $false
        $this.ShowTime = $false
        $this.NoNewLine = $false
        $this.HorizontalCenter = $false
        $this.AutoPad = 0
        $this.PadLeft = $false
        $this.PadChar = ' '
    }
    
    # Method to set as default
    [void]SetAsDefault() {
        [PSColorStyle]::Default = $this
    }
    
    # Method to add to profiles
    [void]AddToProfiles() {
        [PSColorStyle]::Profiles[$this.Name] = $this
    }
    
    # Static method to get profile
    static [PSColorStyle]GetProfile([string]$name) {
        $styleProfile = [PSColorStyle]::Profiles[$name]
        if ($styleProfile) {
            return $styleProfile
        }
        return $null
    }
    
    # Static method to initialize default profiles
    static [void]InitializeDefaultProfiles() {
        # Default profile
        $defaultProfile = [PSColorStyle]::new("Default", "Gray", $null)
        [PSColorStyle]::Default = $defaultProfile
        [PSColorStyle]::Profiles["Default"] = $defaultProfile

        # Error profile
        $errorProfile = [PSColorStyle]::new("Error", "Red", $null)
        $errorProfile.Bold = $true
        $errorProfile.AddToProfiles()

        # Warning profile
        $warningProfile = [PSColorStyle]::new("Warning", "Yellow", $null)
        $warningProfile.AddToProfiles()

        # Info profile
        $infoProfile = [PSColorStyle]::new("Info", "Cyan", $null)
        $infoProfile.AddToProfiles()

        # Success profile
        $successProfile = [PSColorStyle]::new("Success", "Green", $null)
        $successProfile.AddToProfiles()

        # Critical profile
        $criticalProfile = [PSColorStyle]::new("Critical", "White", "DarkRed")
        $criticalProfile.Bold = $true
        $criticalProfile.Blink = $true
        $criticalProfile.AddToProfiles()

        # Debug profile
        $debugProfile = [PSColorStyle]::new("Debug", "DarkGray", $null)
        $debugProfile.Italic = $true
        $debugProfile.AddToProfiles()

        # Pre-warm cache for default profiles (performance optimization)
        $null = $defaultProfile.ToWriteColorParams()
        $null = $errorProfile.ToWriteColorParams()
        $null = $warningProfile.ToWriteColorParams()
        $null = $infoProfile.ToWriteColorParams()
        $null = $successProfile.ToWriteColorParams()
        $null = $criticalProfile.ToWriteColorParams()
        $null = $debugProfile.ToWriteColorParams()
    }
    
    # Method to apply style to Write-ColorEX parameters (with caching)
    [hashtable]ToWriteColorParams() {
        # Return cached params if available
        if ($null -ne $this._cachedParams) {
            # Return a shallow copy to prevent external modification
            return $this._cachedParams.Clone()
        }

        # Build params hashtable
        $params = @{}

        # Important: If Gradient is present, don't include ForegroundColor (gradient takes precedence)
        if ($this.Gradient -and $this.Gradient.Count -ge 2) {
            $params['Gradient'] = $this.Gradient
        } elseif ($this.ForegroundColor) {
            $params['Color'] = $this.ForegroundColor
        }
        if ($this.BackgroundColor) { $params['BackGroundColor'] = $this.BackgroundColor }
        if ($this.Style.Count -gt 0) { $params['Style'] = $this.Style }
        if ($this.StartTab -gt 0) { $params['StartTab'] = $this.StartTab }
        if ($this.StartSpaces -gt 0) { $params['StartSpaces'] = $this.StartSpaces }
        if ($this.LinesBefore -gt 0) { $params['LinesBefore'] = $this.LinesBefore }
        if ($this.LinesAfter -gt 0) { $params['LinesAfter'] = $this.LinesAfter }
        if ($this.Bold) { $params['Bold'] = $true }
        if ($this.Italic) { $params['Italic'] = $true }
        if ($this.Underline) { $params['Underline'] = $true }
        if ($this.Blink) { $params['Blink'] = $true }
        if ($this.Faint) { $params['Faint'] = $true }
        if ($this.CrossedOut) { $params['CrossedOut'] = $true }
        if ($this.DoubleUnderline) { $params['DoubleUnderline'] = $true }
        if ($this.Overline) { $params['Overline'] = $true }
        if ($this.ShowTime) { $params['ShowTime'] = $true }
        if ($this.NoNewLine) { $params['NoNewLine'] = $true }
        if ($this.HorizontalCenter) { $params['HorizontalCenter'] = $true }
        if ($this.AutoPad -gt 0) { $params['AutoPad'] = $this.AutoPad }
        if ($this.PadLeft) { $params['PadLeft'] = $true }
        if ($this.PadChar -ne ' ') { $params['PadChar'] = $this.PadChar }

        # Cache for future calls
        $this._cachedParams = $params

        return $params.Clone()
    }

    # Method to invalidate cache (call after property changes)
    hidden [void]InvalidateCache() {
        $this._cachedParams = $null
    }
    
    # Clone method for creating variations
    # Note: Explicit property copying ensures compatibility with PowerShell 5.1
    [PSColorStyle]Clone() {
        # Clones should not share cache
        $newStyle = [PSColorStyle]::new($this.Name + "_Copy", $this.ForegroundColor, $this.BackgroundColor)
        $newStyle._cachedParams = $null
        $newStyle.Gradient = $this.Gradient
        $newStyle.Style = $this.Style
        $newStyle.StartTab = $this.StartTab
        $newStyle.StartSpaces = $this.StartSpaces
        $newStyle.LinesBefore = $this.LinesBefore
        $newStyle.LinesAfter = $this.LinesAfter
        $newStyle.Bold = $this.Bold
        $newStyle.Italic = $this.Italic
        $newStyle.Underline = $this.Underline
        $newStyle.Blink = $this.Blink
        $newStyle.Faint = $this.Faint
        $newStyle.CrossedOut = $this.CrossedOut
        $newStyle.DoubleUnderline = $this.DoubleUnderline
        $newStyle.Overline = $this.Overline
        $newStyle.ShowTime = $this.ShowTime
        $newStyle.NoNewLine = $this.NoNewLine
        $newStyle.HorizontalCenter = $this.HorizontalCenter
        $newStyle.AutoPad = $this.AutoPad
        $newStyle.PadLeft = $this.PadLeft
        $newStyle.PadChar = $this.PadChar
        return $newStyle
    }
}