Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Components

Namespace Nexamas.UI.Quality

    ''' <summary>
    ''' Friend-only architecture relation coverage probe for the Phase-1 product control set.
    ''' </summary>
    ''' <remarks>
    ''' The gate verifies declared component-graph coverage only. It does not promote a preview
    ''' control to production and it does not treat relation coverage as virtualization or
    ''' performance evidence.
    ''' </remarks>
    Friend NotInheritable Class MASProductControlRelationCoverageGate

        Private Sub New()
        End Sub

        Friend Shared Function Passes() As Boolean
            Try
                Dim graph As MASComponentGraph = MASComponentGraphBuilder.Build()
                If graph Is Nothing Then Return False

                For Each productType As Type In ProductControlTypes()
                    If Not HasCoverageFor(productType, graph) Then Return False
                    If HasBrokenProductEndpoint(productType, graph) Then Return False
                Next

                Return True
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASProductControlRelationCoverageGate")
                Return False
            End Try
        End Function

        Friend Shared Function HasCoverageFor(componentType As Type) As Boolean
            Try
                Return HasCoverageFor(componentType, MASComponentGraphBuilder.Build())
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASProductControlRelationCoverageGate.HasCoverageFor")
                Return False
            End Try
        End Function

        Private Shared Function HasCoverageFor(componentType As Type,
                                               graph As MASComponentGraph) As Boolean
            If componentType Is Nothing OrElse graph Is Nothing Then Return False

            Dim outgoing As IReadOnlyList(Of MASComponentRelation) = graph.GetOutgoing(componentType)
            If outgoing IsNot Nothing AndAlso outgoing.Count > 0 Then Return True

            Dim incoming As IReadOnlyList(Of MASComponentRelation) = graph.GetIncoming(componentType)
            Return incoming IsNot Nothing AndAlso incoming.Count > 0
        End Function

        Private Shared Function HasBrokenProductEndpoint(componentType As Type,
                                                         graph As MASComponentGraph) As Boolean
            If componentType Is Nothing OrElse graph Is Nothing Then Return True

            For Each relation As MASComponentRelation In graph.MissingEndpointRelations
                If relation Is Nothing Then Continue For
                If relation.SourceType Is componentType OrElse relation.TargetType Is componentType Then Return True
            Next

            Return False
        End Function

        Private Shared Function ProductControlTypes() As IEnumerable(Of Type)
            Return New Type() {
                GetType(MASTreeGrid),
                GetType(MASPivotTable),
                GetType(MASKanbanBoard),
                GetType(MASAgendaView),
                GetType(MASDashboardGrid),
                GetType(MASMasterDetailView),
                GetType(MASAppLayout),
                GetType(MASSplitView)
            }
        End Function

    End Class

End Namespace
