Option Strict On
Option Explicit On

Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Linq

Namespace Nexamas.UI.Virtualization

    ''' <summary>
    ''' Central VIRT-02 gate for virtualization consumer dispatcher/lifecycle ownership. The gate keeps the policy attached to
    ''' the current catalog instead of spreading one-off assumptions across controls: active controls must use either
    ''' MASControlRuntimeServices or the Float session as their repeat dispatcher, and lifecycle loss must cancel the active
    ''' scroll-repeat/drag state. Composed consumers are accepted only through their catalog child consumers.
    ''' </summary>
    Friend NotInheritable Class MASVirtualizationConsumerLifecycleGate

        Friend Const MissingLifecycleProofCode As String = "MASVirtualizationConsumerLifecycle.MissingProof"
        Friend Const MissingOfficialDispatcherCode As String = "MASVirtualizationConsumerLifecycle.MissingOfficialDispatcher"
        Friend Const MissingDetachCancellationCode As String = "MASVirtualizationConsumerLifecycle.MissingDetachCancellation"
        Friend Const ControlRuntimeServicesDispatcherOwner As String = "MASControlRuntimeServices"
        Friend Const FloatSessionDispatcherOwner As String = "IMASFloatSession"
        Friend Const ComposedChildDispatcherOwner As String = "ComposedChildConsumers"
        Friend Const RequiredActiveControlRuntimeDispatcherConsumers As Integer = 5
        Friend Const RequiredFloatSessionDispatcherConsumers As Integer = 1
        Friend Const RequiredComposedChildLifecycleConsumers As Integer = 1
        Friend Const RequiredGovernedConsumerCount As Integer = 7

        Private Shared ReadOnly RequiredLifecycleBindings As IReadOnlyList(Of MASVirtualizationConsumerLifecycleBinding) =
            New ReadOnlyCollection(Of MASVirtualizationConsumerLifecycleBinding)(New MASVirtualizationConsumerLifecycleBinding() {
                New MASVirtualizationConsumerLifecycleBinding("MASListBox", ControlRuntimeServicesDispatcherOwner, True, True, True, True, False),
                New MASVirtualizationConsumerLifecycleBinding("MASListView", ControlRuntimeServicesDispatcherOwner, True, True, True, True, False),
                New MASVirtualizationConsumerLifecycleBinding("MASDataGrid", ControlRuntimeServicesDispatcherOwner, True, True, True, True, False),
                New MASVirtualizationConsumerLifecycleBinding("MASTreeView", ControlRuntimeServicesDispatcherOwner, True, True, True, True, False),
                New MASVirtualizationConsumerLifecycleBinding("MASTileBox", ControlRuntimeServicesDispatcherOwner, True, True, True, True, False),
                New MASVirtualizationConsumerLifecycleBinding("MASDropDownListFloatContent", FloatSessionDispatcherOwner, True, False, True, True, False),
                New MASVirtualizationConsumerLifecycleBinding("MASFileExplorerView", ComposedChildDispatcherOwner, False, False, False, False, True)
            })

        Private Sub New()
        End Sub

        Friend Shared Function EvaluateCurrentConsumers() As MASVirtualizationConsumerLifecycleReport
            Return Evaluate(MASVirtualizationConsumerCatalog.GetCurrentConsumers())
        End Function

        Friend Shared Function Evaluate(bindings As IEnumerable(Of MASVirtualizationConsumerBinding)) As MASVirtualizationConsumerLifecycleReport
            Dim safeBindings As MASVirtualizationConsumerBinding() = If(bindings, Enumerable.Empty(Of MASVirtualizationConsumerBinding)()).Where(Function(binding) binding IsNot Nothing).ToArray()
            Dim findings As New List(Of MASVirtualizationReadinessFinding)()

            For Each binding As MASVirtualizationConsumerBinding In safeBindings
                If Not binding.IsActiveOrComposedSharedControllerConsumer Then Continue For

                Dim lifecycle As MASVirtualizationConsumerLifecycleBinding = FindRequiredLifecycleBinding(binding.Id)
                If lifecycle Is Nothing Then
                    findings.Add(New MASVirtualizationReadinessFinding(MissingLifecycleProofCode, binding.Id & " has no VIRT-02 dispatcher/lifecycle contract.", MASVirtualizationFindingSeverity.Error))
                    Continue For
                End If

                If Not lifecycle.IsReady Then
                    findings.Add(New MASVirtualizationReadinessFinding(MissingLifecycleProofCode, binding.Id & " has an incomplete VIRT-02 dispatcher/lifecycle contract.", MASVirtualizationFindingSeverity.Error))
                End If

                If binding.Stage = MASVirtualizationIntegrationStage.ActiveSharedControllerConsumer AndAlso Not lifecycle.RequiresOfficialDispatcher Then
                    findings.Add(New MASVirtualizationReadinessFinding(MissingOfficialDispatcherCode, binding.Id & " must use an official owner dispatcher for scroll repeat pulses.", MASVirtualizationFindingSeverity.Error))
                End If

                If binding.Stage = MASVirtualizationIntegrationStage.ActiveSharedControllerConsumer AndAlso
                   Not (lifecycle.RequiresRuntimeUnbindCancellation OrElse lifecycle.RequiresOwnerDetachCancellation) Then
                    findings.Add(New MASVirtualizationReadinessFinding(MissingDetachCancellationCode, binding.Id & " must cancel scroll repeat lifecycle state when owner dispatcher/session is detached.", MASVirtualizationFindingSeverity.Error))
                End If
            Next

            Return New MASVirtualizationConsumerLifecycleReport(safeBindings, RequiredLifecycleBindings, findings)
        End Function

        Friend Shared Function GetRequiredLifecycleBindings() As IReadOnlyList(Of MASVirtualizationConsumerLifecycleBinding)
            Return RequiredLifecycleBindings
        End Function

        Private Shared Function FindRequiredLifecycleBinding(consumerId As String) As MASVirtualizationConsumerLifecycleBinding
            Dim safeId As String = If(consumerId, String.Empty).Trim()
            If safeId.Length = 0 Then Return Nothing
            Return RequiredLifecycleBindings.FirstOrDefault(Function(binding) String.Equals(binding.ConsumerId, safeId, Global.System.StringComparison.Ordinal))
        End Function

    End Class

End Namespace
