Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports Nexamas.UI.Values

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Friend-only DashboardGrid widget-window snapshot. It proves the control can
    ''' retain a large widget layout while rendering/input diagnostics realize only a
    ''' bounded widget window. It is not child hosting, not a data-refresh provider,
    ''' not external storage, and not a public dashboard virtualization API.
    ''' </summary>
    Friend NotInheritable Class MASDashboardGridWidgetWindowSnapshot

        Private ReadOnly _widgetKeys As IReadOnlyList(Of String)

        Friend Sub New(firstWidgetIndex As Integer,
                       lastWidgetIndex As Integer,
                       totalWidgets As Integer,
                       requestedViewportCapacity As Integer,
                       selectedWidgetKey As String,
                       topIndex As Integer,
                       widgetKeys As IEnumerable(Of String))
            Me.FirstWidgetIndex = Math.Max(0, firstWidgetIndex)
            Me.LastWidgetIndex = lastWidgetIndex
            Me.TotalWidgets = Math.Max(0, totalWidgets)
            Me.RequestedViewportCapacity = Math.Max(1, requestedViewportCapacity)
            Me.SelectedWidgetKey = MASDashboardGridPolicy.NormalizeText(selectedWidgetKey)
            Me.TopIndex = Math.Max(0, topIndex)

            Dim normalized As New List(Of String)()
            If widgetKeys IsNot Nothing Then
                For Each key As String In widgetKeys
                    Dim value As String = MASDashboardGridPolicy.NormalizeText(key)
                    If value.Length > 0 Then normalized.Add(value)
                Next
            End If
            _widgetKeys = New ReadOnlyCollection(Of String)(normalized.ToArray())
        End Sub

        Friend ReadOnly Property FirstWidgetIndex As Integer
        Friend ReadOnly Property LastWidgetIndex As Integer
        Friend ReadOnly Property TotalWidgets As Integer
        Friend ReadOnly Property RequestedViewportCapacity As Integer
        Friend ReadOnly Property SelectedWidgetKey As String
        Friend ReadOnly Property TopIndex As Integer

        Friend ReadOnly Property RealizedWidgetKeys As IReadOnlyList(Of String)
            Get
                Return _widgetKeys
            End Get
        End Property

        Friend ReadOnly Property RealizedWidgetCount As Integer
            Get
                Return _widgetKeys.Count
            End Get
        End Property

        Friend ReadOnly Property IsEmpty As Boolean
            Get
                Return TotalWidgets <= 0 OrElse RealizedWidgetCount <= 0
            End Get
        End Property

        Friend ReadOnly Property IsBounded As Boolean
            Get
                Return RealizedWidgetCount <= RequestedViewportCapacity AndAlso
                       RealizedWidgetIndexCount <= RequestedViewportCapacity
            End Get
        End Property

        Friend ReadOnly Property CoversPartialDashboard As Boolean
            Get
                Return TotalWidgets > RealizedWidgetCount
            End Get
        End Property

        Private ReadOnly Property RealizedWidgetIndexCount As Integer
            Get
                If TotalWidgets <= 0 OrElse LastWidgetIndex < FirstWidgetIndex Then Return 0
                Return LastWidgetIndex - FirstWidgetIndex + 1
            End Get
        End Property

        Friend Function ContainsWidgetKey(widgetKey As String) As Boolean
            Dim normalized As String = MASDashboardGridPolicy.NormalizeText(widgetKey)
            If normalized.Length = 0 Then Return False
            For Each key As String In _widgetKeys
                If String.Equals(key, normalized, StringComparison.Ordinal) Then Return True
            Next
            Return False
        End Function

    End Class

    Partial Public NotInheritable Class MASDashboardGrid

#Region "Friend widget-window diagnostics"

        Friend Function CreateWidgetWindowSnapshot(Optional requestedViewportCapacity As Integer = 0) As MASDashboardGridWidgetWindowSnapshot
            Dim capacity As Integer = ResolveDiagnosticWidgetViewportCapacity(requestedViewportCapacity)

            If _widgets.Count <= 0 Then
                Return New MASDashboardGridWidgetWindowSnapshot(0,
                                                                -1,
                                                                0,
                                                                capacity,
                                                                String.Empty,
                                                                0,
                                                                Array.Empty(Of String)())
            End If

            _topIndex = MASDashboardGridPolicy.EnsureVisibleIndex(_selectedIndex, _topIndex, _widgets.Count, capacity)
            Dim firstIndex As Integer = Math.Max(0, Math.Min(_topIndex, _widgets.Count - 1))
            Dim lastIndex As Integer = Math.Min(_widgets.Count - 1, firstIndex + capacity - 1)
            Dim keys As New List(Of String)()

            For index As Integer = firstIndex To lastIndex
                Dim widget As DashboardWidgetState = _widgets(index)
                If widget IsNot Nothing Then keys.Add(widget.Key)
            Next

            Return New MASDashboardGridWidgetWindowSnapshot(firstIndex,
                                                            lastIndex,
                                                            _widgets.Count,
                                                            capacity,
                                                            SelectedWidgetKey,
                                                            _topIndex,
                                                            keys)
        End Function

        Friend Function GetRealizedWidgetKeys(Optional requestedViewportCapacity As Integer = 0) As IReadOnlyList(Of String)
            Dim snapshot As MASDashboardGridWidgetWindowSnapshot = CreateWidgetWindowSnapshot(requestedViewportCapacity)
            Dim keys As New List(Of String)()
            For Each key As String In snapshot.RealizedWidgetKeys
                keys.Add(key)
            Next
            Return New ReadOnlyCollection(Of String)(keys.ToArray())
        End Function

        Friend Function HasBoundedWidgetWindow(totalWidgetThreshold As Integer,
                                               maxRealizedWidgets As Integer) As Boolean
            Dim snapshot As MASDashboardGridWidgetWindowSnapshot = CreateWidgetWindowSnapshot(maxRealizedWidgets)
            Dim capacity As Integer = Math.Max(1, maxRealizedWidgets)
            Return snapshot.TotalWidgets >= Math.Max(1, totalWidgetThreshold) AndAlso
                   snapshot.RealizedWidgetCount <= capacity AndAlso
                   snapshot.IsBounded AndAlso
                   snapshot.CoversPartialDashboard
        End Function

        Friend Function SetDiagnosticWidgetViewportCapacity(capacity As Integer) As Boolean
            Dim normalized As Integer = Math.Max(1, Math.Min(Math.Max(1, capacity), DashboardGridTokens.MaxVisibleWidgets))
            If _lastVisibleCount = normalized Then Return True
            _lastVisibleCount = normalized
            _topIndex = MASDashboardGridPolicy.EnsureVisibleIndex(_selectedIndex, _topIndex, _widgets.Count, _lastVisibleCount)
            InvalidateVisual()
            Return True
        End Function

        Friend Function EnsureWidgetVisible(widgetKey As String) As Boolean
            Dim index As Integer = FindWidgetIndex(widgetKey)
            If index < 0 Then Return False
            SetSelectedIndex(index, False)
            Return String.Equals(SelectedWidgetKey, MASDashboardGridPolicy.NormalizeKey(widgetKey, "widget", 1), StringComparison.Ordinal)
        End Function

        Friend Function RestoreLayoutSnapshotForLargeLayoutProof(snapshot As MASDashboardGridLayoutSnapshot) As Boolean
            Return RestoreLayoutSnapshotCore(snapshot, DashboardGridTokens.MaxLargeLayoutProofWidgets, "MASDashboardGrid.RestoreLayoutSnapshotForLargeLayoutProof")
        End Function

        Private Function ResolveDiagnosticWidgetViewportCapacity(requestedViewportCapacity As Integer) As Integer
            Dim fallback As Integer = Math.Max(1, _lastVisibleCount)
            Dim requested As Integer = If(requestedViewportCapacity > 0, requestedViewportCapacity, fallback)
            If _widgets.Count <= 0 Then Return Math.Max(1, Math.Min(requested, DashboardGridTokens.MaxVisibleWidgets))
            Return Math.Max(1, Math.Min(requested, Math.Min(_widgets.Count, DashboardGridTokens.MaxVisibleWidgets)))
        End Function

#End Region

    End Class

End Namespace
