Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports Nexamas.UI.Values

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Friend-owned range/value policy for MASSlider. It centralizes normalization,
    ''' step snapping, keyboard increments, tick density, and culture-aware value text so
    ''' the visual control does not duplicate numeric policy inside rendering/input code.
    ''' </summary>
    Friend NotInheritable Class MASSliderRangePolicy
        Private Sub New()
        End Sub

        Friend Shared Sub NormalizeRange(ByRef minimum As Double,
                                         ByRef maximum As Double)
            minimum = NormalizeNumber(minimum, SliderTokens.DefaultMinimum)
            maximum = NormalizeNumber(maximum, SliderTokens.DefaultMaximum)
            If maximum < minimum Then
                Dim tmp As Double = minimum
                minimum = maximum
                maximum = tmp
            End If
            If maximum - minimum < SliderTokens.MinRangeSpan Then maximum = minimum + 1.0
        End Sub

        Friend Shared Function NormalizeValue(candidate As Double,
                                              minimum As Double,
                                              maximum As Double,
                                              stepValue As Double) As Double
            Dim safeMin As Double = minimum
            Dim safeMax As Double = maximum
            NormalizeRange(safeMin, safeMax)

            Dim value As Double = NormalizeNumber(candidate, safeMin)
            value = Math.Max(safeMin, Math.Min(safeMax, value))
            If stepValue > 0.0 Then
                Dim steps As Double = Math.Round((value - safeMin) / stepValue, MidpointRounding.AwayFromZero)
                value = safeMin + steps * stepValue
                value = Math.Max(safeMin, Math.Min(safeMax, value))
            End If
            Return value
        End Function

        Friend Shared Function NormalizeStep(value As Double) As Double
            If Double.IsNaN(value) OrElse Double.IsInfinity(value) OrElse value < 0.0 Then Return 0.0
            Return value
        End Function

        Friend Shared Function ResolveKeyboardStep(stepValue As Double,
                                                   minimum As Double,
                                                   maximum As Double) As Double
            If stepValue > 0.0 Then Return stepValue
            Return Math.Max(1.0, (maximum - minimum) / SliderTokens.KeyboardAutoStepDivisor)
        End Function

        Friend Shared Function ResolveKeyboardPageStep(stepValue As Double,
                                                       minimum As Double,
                                                       maximum As Double) As Double
            Return ResolveKeyboardStep(stepValue, minimum, maximum) * SliderTokens.KeyboardPageStepMultiplier
        End Function

        Friend Shared Function ResolveTickFrequency(tickFrequency As Double,
                                                    stepValue As Double) As Double
            If tickFrequency > 0.0 Then Return tickFrequency
            If stepValue > 0.0 Then Return stepValue
            Return 0.0
        End Function

        Friend Shared Function ResolveTickCount(minimum As Double,
                                                maximum As Double,
                                                frequency As Double) As Integer
            If frequency <= 0.0 Then Return 0
            Dim span As Double = maximum - minimum
            If span <= SliderTokens.MinRangeSpan Then Return 0
            Dim count As Integer = CInt(Math.Floor(span / frequency))
            If count < 0 OrElse count > SliderTokens.MaxTickCount Then Return 0
            Return count
        End Function

        Friend Shared Function FormatValue(value As Double) As String
            Return value.ToString(SliderTokens.ValueFormat, CultureInfo.CurrentCulture)
        End Function

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

End Namespace
