Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Virtualization

    ''' <summary>
    ''' Executed lifecycle/dispatcher proof result for current virtualization consumers. It complements the behavior gate by
    ''' proving that repeat clocks cannot keep running through stale dispatcher state after a control or float session detaches.
    ''' </summary>
    Friend NotInheritable Class MASVirtualizationConsumerLifecycleReport

        Private ReadOnly _bindings As IReadOnlyList(Of MASVirtualizationConsumerBinding)
        Private ReadOnly _lifecycleBindings As IReadOnlyList(Of MASVirtualizationConsumerLifecycleBinding)
        Private ReadOnly _findings As IReadOnlyList(Of MASVirtualizationReadinessFinding)

        Friend Sub New(bindings As IEnumerable(Of MASVirtualizationConsumerBinding),
                       lifecycleBindings As IEnumerable(Of MASVirtualizationConsumerLifecycleBinding),
                       findings As IEnumerable(Of MASVirtualizationReadinessFinding))
            _bindings = New ReadOnlyCollection(Of MASVirtualizationConsumerBinding)(If(bindings, Enumerable.Empty(Of MASVirtualizationConsumerBinding)()).Where(Function(binding) binding IsNot Nothing).ToArray())
            _lifecycleBindings = New ReadOnlyCollection(Of MASVirtualizationConsumerLifecycleBinding)(If(lifecycleBindings, Enumerable.Empty(Of MASVirtualizationConsumerLifecycleBinding)()).Where(Function(binding) binding IsNot Nothing).ToArray())
            _findings = New ReadOnlyCollection(Of MASVirtualizationReadinessFinding)(If(findings, Enumerable.Empty(Of MASVirtualizationReadinessFinding)()).Where(Function(finding) finding IsNot Nothing).ToArray())
        End Sub

        Friend ReadOnly Property Bindings As IReadOnlyList(Of MASVirtualizationConsumerBinding)
            Get
                Return _bindings
            End Get
        End Property

        Friend ReadOnly Property LifecycleBindings As IReadOnlyList(Of MASVirtualizationConsumerLifecycleBinding)
            Get
                Return _lifecycleBindings
            End Get
        End Property

        Friend ReadOnly Property Findings As IReadOnlyList(Of MASVirtualizationReadinessFinding)
            Get
                Return _findings
            End Get
        End Property

        Friend ReadOnly Property GovernedConsumerCount As Integer
            Get
                Return _lifecycleBindings.Count
            End Get
        End Property

        Friend ReadOnly Property ActiveControlRuntimeDispatcherConsumerCount As Integer
            Get
                Return CountLifecycleBindings(Function(binding) binding.IsControlRuntimeDispatcher AndAlso binding.RequiresOfficialDispatcher AndAlso binding.RequiresRuntimeUnbindCancellation)
            End Get
        End Property

        Friend ReadOnly Property FloatSessionDispatcherConsumerCount As Integer
            Get
                Return CountLifecycleBindings(Function(binding) binding.IsFloatSessionDispatcher AndAlso binding.RequiresOfficialDispatcher AndAlso binding.RequiresOwnerDetachCancellation)
            End Get
        End Property

        Friend ReadOnly Property ComposedChildLifecycleConsumerCount As Integer
            Get
                Return CountLifecycleBindings(Function(binding) binding.RequiresComposedChildLifecycleProof AndAlso binding.IsComposedDispatcher)
            End Get
        End Property

        Friend ReadOnly Property AllActiveConsumersHaveOfficialDispatcherLifecycle As Boolean
            Get
                Dim activeBindings As MASVirtualizationConsumerBinding() =
                    _bindings.Where(Function(binding) binding IsNot Nothing AndAlso binding.Stage = MASVirtualizationIntegrationStage.ActiveSharedControllerConsumer).ToArray()

                If activeBindings.Length = 0 Then Return False

                For Each binding As MASVirtualizationConsumerBinding In activeBindings
                    Dim lifecycle As MASVirtualizationConsumerLifecycleBinding = FindLifecycleBinding(binding.Id)
                    If lifecycle Is Nothing OrElse Not lifecycle.IsReady Then Return False
                    If lifecycle.RequiresComposedChildLifecycleProof Then Return False
                Next

                Return True
            End Get
        End Property

        Friend ReadOnly Property AllComposedConsumersHaveChildLifecycleProof As Boolean
            Get
                Dim composedBindings As MASVirtualizationConsumerBinding() =
                    _bindings.Where(Function(binding) binding IsNot Nothing AndAlso binding.Stage = MASVirtualizationIntegrationStage.ComposedSharedControllerConsumer).ToArray()

                If composedBindings.Length = 0 Then Return False

                For Each binding As MASVirtualizationConsumerBinding In composedBindings
                    Dim lifecycle As MASVirtualizationConsumerLifecycleBinding = FindLifecycleBinding(binding.Id)
                    If lifecycle Is Nothing OrElse Not lifecycle.IsReady OrElse Not lifecycle.RequiresComposedChildLifecycleProof Then Return False
                Next

                Return True
            End Get
        End Property

        Friend ReadOnly Property IsReady As Boolean
            Get
                Return Not _findings.Any(Function(finding) finding.Severity = MASVirtualizationFindingSeverity.Error) AndAlso
                       AllActiveConsumersHaveOfficialDispatcherLifecycle AndAlso
                       AllComposedConsumersHaveChildLifecycleProof
            End Get
        End Property


        Private Function CountLifecycleBindings(predicate As Func(Of MASVirtualizationConsumerLifecycleBinding, Boolean)) As Integer
            If predicate Is Nothing Then Return 0

            Dim count As Integer = 0
            For Each binding As MASVirtualizationConsumerLifecycleBinding In _lifecycleBindings
                If binding IsNot Nothing AndAlso predicate(binding) Then
                    count += 1
                End If
            Next

            Return count
        End Function

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

    End Class

End Namespace
