Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports System.Windows.Forms
Imports Nexamas.UI.Values

Namespace Nexamas.UI.Controls

    ''' <summary>
    ''' Friend-owned flow policy for MASStepper. It centralizes title/description hygiene,
    ''' orientation/state normalization, current-index clamping, enabled-step traversal,
    ''' keyboard navigation, RTL direction facts, and connector/render-state decisions while
    ''' keeping workflow engines, validation sessions, page hosts, schedulers, timers, and
    ''' parallel flow services outside the visual step-progress control.
    ''' </summary>
    Friend NotInheritable Class MASStepperFlowPolicy
        Private Sub New()
        End Sub

        Friend Shared Function NormalizeStepTitle(value As String) As String
            Return NormalizeText(value, StepperTokens.DefaultStepTitle, 72)
        End Function

        Friend Shared Function NormalizeStepDescription(value As String) As String
            Return NormalizeText(value, StepperTokens.DefaultStepDescription, 120)
        End Function

        Friend Shared Function NormalizeOrientation(value As MASStepperOrientation) As MASStepperOrientation
            If [Enum].IsDefined(GetType(MASStepperOrientation), value) Then Return value
            Return MASStepperOrientation.Horizontal
        End Function

        Friend Shared Function NormalizeState(value As MASStepperStepState) As MASStepperStepState
            Select Case value
                Case MASStepperStepState.Pending,
                     MASStepperStepState.Current,
                     MASStepperStepState.Completed,
                     MASStepperStepState.[Error],
                     MASStepperStepState.Disabled
                    Return value
                Case Else
                    Return MASStepperStepState.Pending
            End Select
        End Function

        Friend Shared Function NormalizeCurrentIndex(value As Integer,
                                                     stepCount As Integer) As Integer
            If stepCount <= 0 Then Return -1
            If value < 0 Then Return 0
            If value >= stepCount Then Return stepCount - 1
            Return value
        End Function

        Friend Shared Function ResolveRenderState(index As Integer,
                                                  currentIndex As Integer,
                                                  explicitState As MASStepperStepState) As MASStepperStepState
            Dim normalizedState As MASStepperStepState = NormalizeState(explicitState)
            If normalizedState = MASStepperStepState.Disabled OrElse normalizedState = MASStepperStepState.[Error] Then Return normalizedState
            If index = currentIndex Then Return MASStepperStepState.Current
            If index < currentIndex AndAlso normalizedState = MASStepperStepState.Pending Then Return MASStepperStepState.Completed
            Return normalizedState
        End Function

        Friend Shared Function ResolveNextEnabledIndex(currentIndex As Integer,
                                                       stepCount As Integer,
                                                       canUseStep As Func(Of Integer, Boolean)) As Integer
            If stepCount <= 0 OrElse canUseStep Is Nothing Then Return -1

            Dim start As Integer = Math.Max(0, currentIndex + 1)
            For i As Integer = start To stepCount - 1
                If canUseStep(i) Then Return i
            Next

            Return currentIndex
        End Function

        Friend Shared Function ResolvePreviousEnabledIndex(currentIndex As Integer,
                                                           stepCount As Integer,
                                                           canUseStep As Func(Of Integer, Boolean)) As Integer
            If stepCount <= 0 OrElse canUseStep Is Nothing Then Return -1

            Dim start As Integer = If(currentIndex < 0, stepCount - 1, currentIndex - 1)
            For i As Integer = start To 0 Step -1
                If canUseStep(i) Then Return i
            Next

            Return currentIndex
        End Function

        Friend Shared Function ResolveFirstEnabledIndex(stepCount As Integer,
                                                        canUseStep As Func(Of Integer, Boolean)) As Integer
            If stepCount <= 0 OrElse canUseStep Is Nothing Then Return -1
            For i As Integer = 0 To stepCount - 1
                If canUseStep(i) Then Return i
            Next
            Return -1
        End Function

        Friend Shared Function ResolveLastEnabledIndex(stepCount As Integer,
                                                       canUseStep As Func(Of Integer, Boolean)) As Integer
            If stepCount <= 0 OrElse canUseStep Is Nothing Then Return -1
            For i As Integer = stepCount - 1 To 0 Step -1
                If canUseStep(i) Then Return i
            Next
            Return -1
        End Function

        Friend Shared Function ResolveKeyboardStepIndex(keyCode As Keys,
                                                        currentIndex As Integer,
                                                        stepCount As Integer,
                                                        orientation As MASStepperOrientation,
                                                        isRtl As Boolean,
                                                        canUseStep As Func(Of Integer, Boolean)) As Integer
            Select Case keyCode
                Case Keys.Home
                    Return ResolveFirstEnabledIndex(stepCount, canUseStep)
                Case Keys.End
                    Return ResolveLastEnabledIndex(stepCount, canUseStep)
                Case Keys.Down
                    Return If(orientation = MASStepperOrientation.Vertical,
                              ResolveNextEnabledIndex(currentIndex, stepCount, canUseStep),
                              currentIndex)
                Case Keys.Up
                    Return If(orientation = MASStepperOrientation.Vertical,
                              ResolvePreviousEnabledIndex(currentIndex, stepCount, canUseStep),
                              currentIndex)
                Case Keys.Right
                    If orientation <> MASStepperOrientation.Horizontal Then Return currentIndex
                    Return If(isRtl,
                              ResolvePreviousEnabledIndex(currentIndex, stepCount, canUseStep),
                              ResolveNextEnabledIndex(currentIndex, stepCount, canUseStep))
                Case Keys.Left
                    If orientation <> MASStepperOrientation.Horizontal Then Return currentIndex
                    Return If(isRtl,
                              ResolveNextEnabledIndex(currentIndex, stepCount, canUseStep),
                              ResolvePreviousEnabledIndex(currentIndex, stepCount, canUseStep))
                Case Else
                    Return currentIndex
            End Select
        End Function

        Friend Shared Function ResolveRightToLeft() As Boolean
            Return Nexamas.UI.Localization.MASLocalization.IsCurrentRightToLeft()
        End Function

        Friend Shared Function NormalizeStepCount(count As Integer) As Integer
            If count < 0 Then Return 0
            Return Math.Min(count, 64)
        End Function

        Friend Shared ReadOnly Property HasConnectorPolicy As Boolean
            Get
                Return True
            End Get
        End Property

        Friend Shared ReadOnly Property HasNoParallelFlowService As Boolean
            Get
                Return True
            End Get
        End Property

        Friend Shared ReadOnly Property HasNoValidationSessionOwner As Boolean
            Get
                Return True
            End Get
        End Property

        Private Shared Function NormalizeText(value As String,
                                              fallback As String,
                                              maxLength As Integer) As String
            Dim text As String = If(value, String.Empty).Trim()
            If text.Length = 0 Then text = If(fallback, String.Empty)
            Dim limit As Integer = Math.Max(0, maxLength)
            If limit > 0 AndAlso text.Length > limit Then text = text.Substring(0, limit)
            Return text
        End Function
    End Class

End Namespace
