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>
    ''' Public immutable MasterDetailView snapshot. It captures the retained visual
    ''' master/detail items, selected item key, and master viewport only; it deliberately
    ''' does not own application routing, object inspection, data providers, storage,
    ''' or command execution.
    ''' </summary>
    Public NotInheritable Class MASMasterDetailViewSnapshot
        Public Sub New(version As Integer,
                       title As String,
                       selectedItemKey As String,
                       topIndex As Integer,
                       items As IEnumerable(Of MASMasterDetailItemSnapshot))
            Me.Version = Math.Max(1, version)
            Me.Title = MASMasterDetailViewPolicy.NormalizeTitle(title)
            Dim normalizedSelected As String = MASMasterDetailViewPolicy.NormalizeText(selectedItemKey)
            Me.SelectedItemKey = If(normalizedSelected.Length = 0, String.Empty, MASMasterDetailViewPolicy.NormalizeKey(normalizedSelected, "item", 1))
            Me.TopIndex = Math.Max(0, topIndex)
            Dim copy As New List(Of MASMasterDetailItemSnapshot)()
            If items IsNot Nothing Then
                For Each item As MASMasterDetailItemSnapshot In items
                    If item IsNot Nothing Then copy.Add(item)
                Next
            End If
            Me.Items = New ReadOnlyCollection(Of MASMasterDetailItemSnapshot)(copy)
        End Sub

        Public ReadOnly Property Version As Integer
        Public ReadOnly Property Title As String
        Public ReadOnly Property SelectedItemKey As String
        Public ReadOnly Property TopIndex As Integer
        Public ReadOnly Property Items As IReadOnlyList(Of MASMasterDetailItemSnapshot)
    End Class

    ''' <summary>
    ''' Public immutable item entry used by MASMasterDetailViewSnapshot.
    ''' </summary>
    Public NotInheritable Class MASMasterDetailItemSnapshot
        Public Sub New(key As String,
                       title As String,
                       subtitle As String,
                       detailTitle As String,
                       detailText As String,
                       badgeText As String)
            Me.Key = MASMasterDetailViewPolicy.NormalizeKey(key, "item", 1)
            Me.Title = MASMasterDetailViewPolicy.NormalizeItemTitle(title)
            Me.Subtitle = MASMasterDetailViewPolicy.NormalizeSubtitle(subtitle)
            Me.DetailTitle = MASMasterDetailViewPolicy.NormalizeDetailTitle(detailTitle, title)
            Me.DetailText = MASMasterDetailViewPolicy.NormalizeDetailText(detailText)
            Me.BadgeText = MASMasterDetailViewPolicy.NormalizeBadgeText(badgeText)
        End Sub

        Public ReadOnly Property Key As String
        Public ReadOnly Property Title As String
        Public ReadOnly Property Subtitle As String
        Public ReadOnly Property DetailTitle As String
        Public ReadOnly Property DetailText As String
        Public ReadOnly Property BadgeText As String
    End Class

    Partial Public NotInheritable Class MASMasterDetailView

        Public Function CreateViewSnapshot() As MASMasterDetailViewSnapshot
            Dim items As New List(Of MASMasterDetailItemSnapshot)()
            For Each item As MasterDetailItemState In _items
                If item Is Nothing Then Continue For
                items.Add(New MASMasterDetailItemSnapshot(item.Key,
                                                          item.Title,
                                                          item.Subtitle,
                                                          item.DetailTitle,
                                                          item.DetailText,
                                                          item.BadgeText))
            Next
            Return New MASMasterDetailViewSnapshot(1, _title, SelectedItemKey, _topIndex, items)
        End Function

        Public Function RestoreViewSnapshot(snapshot As MASMasterDetailViewSnapshot) As Boolean
            If snapshot Is Nothing Then Return False
            ClearMasterDetailSourceLinkForManualMutation()
            _items.Clear()
            _hits.Clear()
            _selectedIndex = -1
            _hoverIndex = -1
            _pressedIndex = -1
            _topIndex = 0

            Dim usedKeys As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
            For Each itemSnapshot As MASMasterDetailItemSnapshot In snapshot.Items
                If itemSnapshot Is Nothing Then Continue For
                If _items.Count >= MasterDetailViewTokens.MaxItems Then Exit For
                Dim key As String = ResolveUniqueMasterDetailKey(itemSnapshot.Key, "item", _items.Count + 1, usedKeys)
                _items.Add(New MasterDetailItemState(key,
                                                     itemSnapshot.Title,
                                                     itemSnapshot.Subtitle,
                                                     itemSnapshot.DetailTitle,
                                                     itemSnapshot.DetailText,
                                                     itemSnapshot.BadgeText))
            Next

            _title = MASMasterDetailViewPolicy.NormalizeTitle(snapshot.Title)
            _topIndex = Math.Max(0, Math.Min(snapshot.TopIndex, ResolveMasterViewportMaxTop()))
            If snapshot.SelectedItemKey.Length > 0 Then
                Dim selected As Integer = FindItemIndex(snapshot.SelectedItemKey)
                If selected >= 0 Then _selectedIndex = selected
            End If
            If _selectedIndex < 0 AndAlso _items.Count > 0 Then _selectedIndex = 0
            NormalizeViewState()

            RequestSizeLayoutRefreshForSizeAffectingChange("MASMasterDetailView.RestoreViewSnapshot")
            InvalidateVisual()
            RaiseMasterDetailChangedSafe()
            RaiseSelectedItemChangedSafe()
            Return True
        End Function

        Public Function ResetMasterViewport() As MASMasterDetailView
            _topIndex = 0
            InvalidateVisual()
            Return Me
        End Function

        Friend Function HasViewSnapshotForTests() As Boolean
            Dim snapshot As MASMasterDetailViewSnapshot = CreateViewSnapshot()
            Return snapshot IsNot Nothing AndAlso snapshot.Items.Count = _items.Count
        End Function

    End Class

End Namespace
