Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Windows.Forms
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Components.ListPopup
Imports Nexamas.UI.Components.ListRendering
Imports Nexamas.UI.Composition
Imports Nexamas.UI.Controls
Imports Nexamas.UI.FloatRuntime
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    Partial Public NotInheritable Class MASComboBox

#Region "Public API"

        Friend Property SurfaceSizeProvider As Func(Of SKSizeI) = Nothing

        Friend Property FloatRuntime As MASFloatRuntime
            Get
                Return _floatRuntime
            End Get
            Set(value As MASFloatRuntime)
                If Object.ReferenceEquals(_floatRuntime, value) Then Return

                CloseDropdownSafe()
                _floatRuntime = value
                InvalidateVisual()
            End Set
        End Property

#Region "SDK Fluent API"

        Public Shared Function Create() As MASComboBox
            Return New MASComboBox()
        End Function

        Friend Shared Function [Default]() As MASComboBox
            Return Create()
        End Function

        Friend Function SetBounds(bounds As SKRect) As MASComboBox
            SetLocalLayoutBoundsInternal(bounds)
            Return Me
        End Function

        Friend Function WithBounds(bounds As SKRect) As MASComboBox
            Return SetBounds(bounds)
        End Function

        Friend Function WithBounds(x As Single,
                                   y As Single,
                                   width As Single,
                                   height As Single) As MASComboBox

             SetLocalLayoutBoundsInternal(New SKRect(
                x,
                y,
                x + Math.Max(0.0F, width),
                y + Math.Max(0.0F, height)))

            Return Me
        End Function

        Public Function WithItems(items As IEnumerable(Of String)) As MASComboBox
            SetItems(items)
            Return Me
        End Function

        Public Function AddRange(items As IEnumerable(Of String)) As MASComboBox
            AddItems(items)
            Return Me
        End Function

        Public Function Clear() As MASComboBox
            ClearItems()
            Return Me
        End Function

        Public Function SelectIndex(index As Integer) As MASComboBox
            SelectedIndex = index
            Return Me
        End Function

        Public Function SelectFirstItem() As MASComboBox
            SelectFirst()
            Return Me
        End Function

        Friend Function WithSurfaceSizeProvider(provider As Func(Of SKSizeI)) As MASComboBox
            SurfaceSizeProvider = provider
            Return Me
        End Function

        Friend Function WithFloatRuntime(runtime As MASFloatRuntime) As MASComboBox
            Me.FloatRuntime = runtime
            Return Me
        End Function

        Friend Function OnSelectionChanged(handler As EventHandler) As MASComboBox
            If handler IsNot Nothing Then
                AddHandler SelectionChanged, handler
            End If

            Return Me
        End Function

        Friend Function OnSelectionChanged(action As Action(Of MASComboBox, Integer, String)) As MASComboBox
            If action Is Nothing Then Return Me

            AddHandler SelectionChanged,
                Sub(sender As Object, e As EventArgs)
                    action.Invoke(Me, SelectedIndex, SelectedText)
                End Sub

            Return Me
        End Function

        Friend Function GetPreferredLayoutSize(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutParticipant.GetPreferredLayoutSize
            Return MeasureIntrinsicSize(CreateSizeContext(context), SizeIntent).DesiredSize
        End Function

        Friend Function GetMinLayoutSize(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutParticipant.GetMinLayoutSize
            Return MeasureIntrinsicSize(CreateSizeContext(context), SizeIntent).MinSize
        End Function

        Friend Function MeasureIntrinsicSize(context As MASSizeContext, intent As MASSize) As MASSizeResult Implements IMASIntrinsicSizeContract.MeasureIntrinsicSize
            Dim safeContext As MASSizeContext = MASIntrinsicControlSizeMetrics.EnsureContext(context)
            Dim desiredTextWidth As Single = ResolveIntrinsicTextWidth(safeContext)
            Dim desired As SKSize = MASIntrinsicControlSizeMetrics.ResolveComboBoxDesiredSize(desiredTextWidth)
            Dim minimum As SKSize = MASIntrinsicControlSizeMetrics.ResolveComboBoxMinimumSize()
            Dim contentInset As MASLayoutInset = MASIntrinsicControlSizeMetrics.CreateComboBoxContentInset()

            Return MASSizeResolver.FromMeasured(
                desiredSize:=desired,
                minSize:=minimum,
                maxSize:=New SKSize(Single.PositiveInfinity, Single.PositiveInfinity),
                intent:=intent,
                context:=safeContext,
                canGrowWidth:=False,
                canGrowHeight:=False,
                contentInset:=contentInset,
                visualOverflowInset:=MASIntrinsicControlSizeMetrics.InputVisualOverflowInset,
                hitOverflowInset:=MASIntrinsicControlSizeMetrics.CreateTouchHitOverflowInset(desired, safeContext.Density),
                isFallback:=False)
        End Function

        Friend Function ResolveLayoutSemanticBounds(outerBounds As SKRect,
                                                    sizeResult As MASSizeResult,
                                                    defaultSlot As MASLayoutSlot) As MASLayoutSemanticBounds Implements IMASLayoutSemanticBoundsProvider.ResolveLayoutSemanticBounds
            Return MASLayoutSemanticBoundsPolicy.ForInputPopupTriggerSurface(defaultSlot)
        End Function

        Private Function ResolveIntrinsicTextWidth(context As MASSizeContext) As Single
            Dim width As Single = MeasureIntrinsicText(context, If(String.IsNullOrEmpty(SelectedText), InputTokens.DefaultComboPlaceholder, SelectedText))
            For Each item As String In _items
                width = Math.Max(width, MeasureIntrinsicText(context, item))
            Next
            Return width
        End Function

        Private Shared Function MeasureIntrinsicText(context As MASSizeContext, text As String) As Single
            Dim result As MASTextMeasureResult =
                MASLayoutTextMeasureGateway.Measure(
                    If(context Is Nothing, Nothing, context.IntegrationContext),
                    If(text, String.Empty),
                    MASTypography.MASTextStyle.SelectionText,
                    Single.PositiveInfinity,
                    allowWrap:=False)
            Return Math.Max(0.0F, result.Size.Width)
        End Function

        Private Shared Function CreateSizeContext(context As MASLayoutMeasureContext) As MASSizeContext
            If context Is Nothing Then Return MASIntrinsicControlSizeMetrics.EnsureContext(Nothing)
            Return context.ToSizeContext()
        End Function

#End Region
#End Region

#Region "Unified MASSize Fluent API"

        ''' <summary>
        ''' Strongly typed entry into the shared MASSize intent API.
        ''' This method keeps fluent chains on the concrete element while delegating all sizing decisions to MASControlBase/MASSize.
        ''' </summary>
        Public Shadows Function WithSize(sizeIntent As Nexamas.UI.Layout.MASSize) As MASComboBox
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function






#End Region

    End Class

End Namespace
