Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports Nexamas.UI.Components
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Values

Namespace Nexamas.UI.Controls

    ''' <summary>
    ''' Friend-only progress value and presentation policy for MASProgressBar. It owns
    ''' determinate range normalization, percent/value text, state tone normalization,
    ''' label-placement safety, frame/material defaults, and the no-clock rendering
    ''' boundary. Rendering remains owned by ProgressBarRenderer and operation lifetime
    ''' remains outside the progress element.
    ''' </summary>
    Friend NotInheritable Class MASProgressBarValuePolicy
        Private Sub New()
        End Sub

        Friend Shared Function NormalizeRangeEndpoint(value As Double,
                                                       fallback As Double) As Double
            If Double.IsNaN(value) OrElse Double.IsInfinity(value) Then Return fallback
            Return value
        End Function

        Friend Shared Function NormalizeRange(minimum As Double,
                                               maximum As Double,
                                               value As Double) As MASProgressBarRangeSnapshot
            Dim minValue As Double = NormalizeRangeEndpoint(minimum, 0.0R)
            Dim maxValue As Double = NormalizeRangeEndpoint(maximum, 100.0R)

            If maxValue < minValue Then
                Dim swap As Double = minValue
                minValue = maxValue
                maxValue = swap
            End If

            Dim safeValue As Double = NormalizeValue(value, minValue, maxValue)
            Return New MASProgressBarRangeSnapshot(minValue, maxValue, safeValue)
        End Function

        Friend Shared Function NormalizeValue(value As Double,
                                              minimum As Double,
                                              maximum As Double) As Double
            Dim minValue As Double = NormalizeRangeEndpoint(minimum, 0.0R)
            Dim maxValue As Double = NormalizeRangeEndpoint(maximum, 100.0R)
            If maxValue < minValue Then
                Dim swap As Double = minValue
                minValue = maxValue
                maxValue = swap
            End If

            If Double.IsNaN(value) OrElse Double.IsInfinity(value) Then value = minValue
            Return Clamp(value, minValue, maxValue)
        End Function

        Friend Shared Function NormalizePercent(value As Double) As Double
            If Double.IsNaN(value) OrElse Double.IsInfinity(value) Then Return 0.0R
            Return Clamp(value, 0.0R, 100.0R)
        End Function

        Friend Shared Function ResolveValueFromPercent(minimum As Double,
                                                       maximum As Double,
                                                       percent As Double) As Double
            Dim snapshot As MASProgressBarRangeSnapshot = NormalizeRange(minimum, maximum, minimum)
            Dim safePercent As Double = NormalizePercent(percent)
            Return snapshot.Minimum + ((snapshot.Maximum - snapshot.Minimum) * (safePercent / 100.0R))
        End Function

        Friend Shared Function ResolveProgressFraction(minimum As Double,
                                                       maximum As Double,
                                                       value As Double) As Single
            Dim snapshot As MASProgressBarRangeSnapshot = NormalizeRange(minimum, maximum, value)
            If snapshot.Maximum <= snapshot.Minimum Then Return 0.0F

            Dim fraction As Double = (snapshot.Value - snapshot.Minimum) / (snapshot.Maximum - snapshot.Minimum)
            If Double.IsNaN(fraction) OrElse Double.IsInfinity(fraction) Then Return 0.0F
            If fraction < 0.0R Then Return 0.0F
            If fraction > 1.0R Then Return 1.0F
            Return CSng(fraction)
        End Function

        Friend Shared Function ResolvePercentText(minimum As Double,
                                                  maximum As Double,
                                                  value As Double) As String
            Dim percent As Integer = CInt(Math.Round(ResolveProgressFraction(minimum, maximum, value) * 100.0F, MidpointRounding.AwayFromZero))
            If percent < 0 Then percent = 0
            If percent > 100 Then percent = 100
            Return percent.ToString(CultureInfo.InvariantCulture) & "%"
        End Function

        Friend Shared Function ResolveAccessibleValueText(minimum As Double,
                                                          maximum As Double,
                                                          value As Double) As String
            Dim snapshot As MASProgressBarRangeSnapshot = NormalizeRange(minimum, maximum, value)
            Return snapshot.Value.ToString("0.###", CultureInfo.InvariantCulture) & " / " & snapshot.Maximum.ToString("0.###", CultureInfo.InvariantCulture)
        End Function

        Friend Shared Function NormalizeVisualState(value As MASProgressBarState) As MASProgressBarState
            Select Case value
                Case MASProgressBarState.Normal,
                     MASProgressBarState.Success,
                     MASProgressBarState.Warning,
                     MASProgressBarState.Danger
                    Return value
                Case Else
                    Return MASProgressBarState.Normal
            End Select
        End Function

        Friend Shared Function NormalizeFrameMode(value As MASProgressBarFrameMode) As MASProgressBarFrameMode
            Select Case value
                Case MASProgressBarFrameMode.None,
                     MASProgressBarFrameMode.ContainedField
                    Return value
                Case Else
                    Return MASProgressBarFrameMode.None
            End Select
        End Function

        Friend Shared Function NormalizeContainerMaterialKey(value As String) As String
            Dim key As String = If(value, String.Empty).Trim()
            If key.Length = 0 Then Return MASSurfaceMaterialIds.PlatformDefault
            Return key
        End Function

        Friend Shared Function NormalizeSurfaceStrength(value As MASSurfaceStrength) As MASSurfaceStrength
            Select Case value
                Case MASSurfaceStrength.ThemeDefault,
                     MASSurfaceStrength.Level1,
                     MASSurfaceStrength.Level2,
                     MASSurfaceStrength.Level3,
                     MASSurfaceStrength.Level4,
                     MASSurfaceStrength.Level5,
                     MASSurfaceStrength.Level6
                    Return value
                Case Else
                    Return MASSurfaceStrength.ThemeDefault
            End Select
        End Function

        Friend Shared Function NormalizeSizeMode(value As MASProgressBarSize) As MASProgressBarSize
            Select Case value
                Case MASProgressBarSize.Compact,
                     MASProgressBarSize.[Default],
                     MASProgressBarSize.Large,
                     MASProgressBarSize.Jumbo
                    Return value
                Case Else
                    Return MASProgressBarSize.[Default]
            End Select
        End Function

        Friend Shared Function NormalizeLabelPlacement(value As MASProgressBarLabelPlacement) As MASProgressBarLabelPlacement
            Select Case value
                Case MASProgressBarLabelPlacement.None,
                     MASProgressBarLabelPlacement.Top,
                     MASProgressBarLabelPlacement.Bottom,
                     MASProgressBarLabelPlacement.Left,
                     MASProgressBarLabelPlacement.Right,
                     MASProgressBarLabelPlacement.InsideCenter
                    Return value
                Case Else
                    Return MASProgressBarLabelPlacement.None
            End Select
        End Function

        Friend Shared Function NormalizeLogicalExtent(value As Single) As Single
            If Single.IsNaN(value) OrElse Single.IsInfinity(value) OrElse value < 0.0F Then Return 0.0F
            Return value
        End Function

        Friend Shared Function Clamp(value As Double,
                                     minimum As Double,
                                     maximum As Double) As Double
            If value < minimum Then Return minimum
            If value > maximum Then Return maximum
            Return value
        End Function

        Friend Shared Function NearlyEqual(left As Double,
                                           right As Double) As Boolean
            If Double.IsNaN(left) OrElse Double.IsNaN(right) Then Return False
            If Double.IsInfinity(left) OrElse Double.IsInfinity(right) Then Return left.Equals(right)
            Return Math.Abs(left - right) < 0.0000001R
        End Function

        Friend Shared Function NearlyEqual(left As Single,
                                           right As Single) As Boolean
            Return Math.Abs(left - right) < 0.001F
        End Function

        Friend Shared Function HasDeterminateRangePolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasStateTonePolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasLabelPlacementPolicy() As Boolean
            Return True
        End Function

        Friend Shared Function HasNoAnimationClockRoute() As Boolean
            Return True
        End Function
    End Class

    Friend NotInheritable Class MASProgressBarRangeSnapshot
        Friend Sub New(minimum As Double,
                       maximum As Double,
                       value As Double)
            Me.Minimum = minimum
            Me.Maximum = maximum
            Me.Value = value
        End Sub

        Friend ReadOnly Property Minimum As Double
        Friend ReadOnly Property Maximum As Double
        Friend ReadOnly Property Value As Double
    End Class

End Namespace
