Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Internal runtime state for the public selection panel gateway.
    ''' It owns the generated checkbox controls so external SDK consumers receive only
    ''' MASSelectionPanelResult values and never depend on PanelShell internals.
    ''' </summary>
    Friend NotInheritable Class MASSelectionPanelState

        Private NotInheritable Class Entry
            Friend Property Box As MASCheckBox
            Friend Property Item As MASSelectionPanelItem
        End Class

        Private ReadOnly _entries As New List(Of Entry)()
        Private ReadOnly _recommendedBoxes As New HashSet(Of MASCheckBox)()
        Private ReadOnly _selectionMode As MASSelectionPanelSelectionMode
        Private _countLabel As Nexamas.UI.Controls.MASLabel
        Private _summaryFormat As String = String.Empty
        Private _updating As Boolean

        Friend Sub New(selectionMode As MASSelectionPanelSelectionMode)
            _selectionMode = selectionMode
        End Sub

        Friend Sub Reset(countLabel As Nexamas.UI.Controls.MASLabel,
                         summaryFormat As String)

            _entries.Clear()
            _recommendedBoxes.Clear()
            _countLabel = countLabel
            _summaryFormat = If(summaryFormat, String.Empty)
            _updating = False

        End Sub

        Friend Sub Add(box As MASCheckBox,
                       item As MASSelectionPanelItem)

            If box Is Nothing OrElse item Is Nothing Then Return

            _entries.Add(New Entry() With {
                .Box = box,
                .Item = item.Clone()
            })

            If item.Recommended Then
                _recommendedBoxes.Add(box)
            End If

            AddHandler box.CheckedChanged, AddressOf Box_CheckedChanged

        End Sub

        Friend Sub SelectRecommended()

            BeginUpdate()

            Try
                If _selectionMode = MASSelectionPanelSelectionMode.[Single] Then
                    SelectFirstRecommendedForSingleMode()
                Else
                    For Each entry As Entry In _entries
                        If entry Is Nothing OrElse entry.Box Is Nothing Then Continue For
                        entry.Box.Checked = _recommendedBoxes.Contains(entry.Box)
                    Next
                End If
            Finally
                EndUpdate()
            End Try

            RefreshCount()

        End Sub

        Friend Sub SelectAll()

            BeginUpdate()

            Try
                If _selectionMode = MASSelectionPanelSelectionMode.[Single] Then
                    SelectFirstEnabledVisibleBox()
                Else
                    For Each entry As Entry In _entries
                        If entry Is Nothing OrElse entry.Box Is Nothing Then Continue For
                        If entry.Box.Enabled AndAlso entry.Box.Visible Then entry.Box.Checked = True
                    Next
                End If
            Finally
                EndUpdate()
            End Try

            RefreshCount()

        End Sub

        Friend Sub UnselectAll()

            BeginUpdate()

            Try
                For Each entry As Entry In _entries
                    If entry Is Nothing OrElse entry.Box Is Nothing Then Continue For
                    entry.Box.Checked = False
                Next
            Finally
                EndUpdate()
            End Try

            RefreshCount()

        End Sub

        Friend Sub NormalizeSingleSelection()

            If _selectionMode <> MASSelectionPanelSelectionMode.[Single] Then Return

            BeginUpdate()

            Try
                Dim selectedFound As Boolean = False

                For Each entry As Entry In _entries
                    If entry Is Nothing OrElse entry.Box Is Nothing Then Continue For

                    If entry.Box.Checked AndAlso Not selectedFound Then
                        selectedFound = True
                    ElseIf entry.Box.Checked Then
                        entry.Box.Checked = False
                    End If
                Next
            Finally
                EndUpdate()
            End Try

            RefreshCount()

        End Sub

        Friend Sub RefreshCount()

            If _countLabel Is Nothing Then Return

            Dim selectedCount As Integer = 0
            Dim totalCount As Integer = 0

            For Each entry As Entry In _entries
                If entry Is Nothing OrElse entry.Box Is Nothing Then Continue For
                If Not entry.Box.Visible Then Continue For

                totalCount += 1

                If entry.Box.Checked Then
                    selectedCount += 1
                End If
            Next

            _countLabel.Text = BuildSummaryText(selectedCount, totalCount)

        End Sub

        Friend Function ToResult(panelResult As MASApplicationPanelResult,
                                 options As MASSelectionPanelOptions) As MASSelectionPanelResult

            Dim commandId As String = String.Empty
            Dim cancelled As Boolean = True
            Dim userState As Object = Nothing

            If options IsNot Nothing Then userState = options.UserState

            If panelResult IsNot Nothing Then
                commandId = If(panelResult.CommandId, String.Empty)
                cancelled = panelResult.Cancelled
                userState = panelResult.UserState
            End If

            Dim isApply As Boolean = String.Equals(commandId, MASSelectionPanelRequestBuilder.ApplyCommandId, StringComparison.OrdinalIgnoreCase)

            If Not isApply Then
                cancelled = True
            End If

            Dim keys As New List(Of String)()
            Dim items As New List(Of MASSelectionPanelItem)()

            If isApply Then
                For Each entry As Entry In _entries
                    If entry Is Nothing OrElse entry.Box Is Nothing OrElse entry.Item Is Nothing Then Continue For
                    If Not entry.Box.Checked Then Continue For

                    Dim key As String = If(entry.Item.Key, String.Empty).Trim()
                    If key.Length = 0 Then Continue For

                    keys.Add(key)

                    Dim selectedItem As MASSelectionPanelItem = entry.Item.Clone()
                    selectedItem.Selected = True
                    items.Add(selectedItem)
                Next
            End If

            Return New MASSelectionPanelResult(
                commandId:=commandId,
                cancelled:=cancelled,
                selectedKeys:=keys,
                selectedItems:=items,
                userState:=userState)

        End Function

        Private Sub Box_CheckedChanged(sender As Object,
                                       e As EventArgs)

            If _updating Then Return

            Dim changedBox As MASCheckBox = TryCast(sender, MASCheckBox)

            If _selectionMode = MASSelectionPanelSelectionMode.[Single] AndAlso
               changedBox IsNot Nothing AndAlso
               changedBox.Checked Then

                BeginUpdate()

                Try
                    For Each entry As Entry In _entries
                        If entry Is Nothing OrElse entry.Box Is Nothing Then Continue For
                        If Object.ReferenceEquals(entry.Box, changedBox) Then Continue For
                        entry.Box.Checked = False
                    Next
                Finally
                    EndUpdate()
                End Try

            End If

            RefreshCount()

        End Sub

        Private Sub SelectFirstRecommendedForSingleMode()

            Dim selected As Boolean = False

            For Each entry As Entry In _entries
                If entry Is Nothing OrElse entry.Box Is Nothing Then Continue For

                If Not selected AndAlso
                   _recommendedBoxes.Contains(entry.Box) AndAlso
                   entry.Box.Enabled AndAlso
                   entry.Box.Visible Then

                    entry.Box.Checked = True
                    selected = True
                Else
                    entry.Box.Checked = False
                End If
            Next

        End Sub

        Private Sub SelectFirstEnabledVisibleBox()

            Dim selected As Boolean = False

            For Each entry As Entry In _entries
                If entry Is Nothing OrElse entry.Box Is Nothing Then Continue For

                If Not selected AndAlso entry.Box.Enabled AndAlso entry.Box.Visible Then
                    entry.Box.Checked = True
                    selected = True
                Else
                    entry.Box.Checked = False
                End If
            Next

        End Sub

        Private Function BuildSummaryText(selectedCount As Integer,
                                          totalCount As Integer) As String

            Dim format As String = If(_summaryFormat, String.Empty)

            If format.Trim().Length = 0 Then
                format = "{0} of {1} items selected"
            End If

            Try
                Return String.Format(format, selectedCount, totalCount)
            Catch masCaughtException1 As FormatException
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowBoundary(masCaughtException1)
                Return selectedCount.ToString() & " of " & totalCount.ToString() & " items selected"
            End Try

        End Function

        Private Sub BeginUpdate()
            _updating = True
        End Sub

        Private Sub EndUpdate()
            _updating = False
        End Sub

    End Class

End Namespace
