Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Windows.Forms
Imports Nexamas.UI.Components
Imports Nexamas.UI.General
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Scroll
Imports Nexamas.UI.SkiaScroll
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Layout
Imports SkiaSharp

Namespace Nexamas.UI.FloatRuntime

    Partial Friend NotInheritable Class MASMessageBoxFloatContent
#Region "Pointer"

        Friend Function HitTestFloat(ctx As MASThemeContext,
                                     boundsPx As SKRect,
                                     ptPx As SKPoint) As Boolean Implements IMASFloatRoutedInputContent.HitTestFloat

            Dim panel As SKRect =
                If(Not _panelRectPx.IsEmpty, _panelRectPx, boundsPx)

            Return Contains(panel, ptPx)

        End Function

        Friend Sub PointerMoveFloat(ctx As MASThemeContext,
                            ptPx As SKPoint) Implements IMASFloatRoutedInputContent.PointerMoveFloat

            If PointerMoveFloatVisualChanged(ctx, ptPx) Then
                RequestInvalidate()
            End If

        End Sub

        Friend Function PointerMoveFloatVisualChanged(ctx As MASThemeContext,
                                                      ptPx As SKPoint) As Boolean Implements IMASFloatPointerMoveChangeAwareContent.PointerMoveFloatVisualChanged

            If _disposed Then Return False
            If _layout Is Nothing Then Return False

            If _panelShellDrag.IsDragging Then
                Dim targetBoundsPx As SKRect =
                    _panelShellDrag.DragTo(ptPx, ResolveAvailableBoundsPx())

                If _session IsNot Nothing Then
                    _session.TrySetBoundsPx(targetBoundsPx)
                End If

                Return True
            End If

            If HandleContentScrollMove(ptPx) Then
                Return True
            End If

            Dim changed As Boolean = False

            Dim closeHover As Boolean =
        _request.AllowCloseButton AndAlso Contains(_layout.CloseRect, ptPx)

            If _state.CloseHover <> closeHover Then
                _state.CloseHover = closeHover
                changed = True
            End If

            Dim checkHover As Boolean = IsCheckBoxHit(ptPx)

            If _state.CheckBoxHover <> checkHover Then
                _state.CheckBoxHover = checkHover
                changed = True
            End If

            If SyncButtonStatesFromPointer(ptPx, _pressedButtonIndex) Then
                changed = True
            End If

            Return changed
        End Function

        Friend Function PointerDownFloat(ctx As MASThemeContext,
                                 ptPx As SKPoint,
                                 button As MouseButtons) As Boolean Implements IMASFloatRoutedInputContent.PointerDownFloat

            If _disposed Then Return False
            If button <> MouseButtons.Left Then Return False
            If _layout Is Nothing Then Return False

            ResetPointerState(clearHover:=False)
            PointerMoveFloat(ctx, ptPx)

            If _request.AllowCloseButton AndAlso Contains(_layout.CloseRect, ptPx) Then
                _pressedClose = True
                _state.ClosePressed = True
                ClearButtonPressedStates()
                RequestInvalidate()
                Return True
            End If

            If IsCheckBoxHit(ptPx) Then
                _pressedCheckBox = True
                _state.CheckBoxPressed = True
                ClearButtonPressedStates()
                RequestInvalidate()
                Return True
            End If

            If HandleContentScrollDown(ptPx) Then
                Return True
            End If

            Dim index As Integer = HitButtonIndex(ptPx)

            If index >= 0 Then
                _pressedButtonIndex = index
                SyncButtonStatesFromPointer(ptPx, _pressedButtonIndex)
                RequestInvalidate()
                Return True
            End If

            If TryBeginPanelShellDrag(ptPx, button) Then
                Return True
            End If

            Return Contains(_panelRectPx, ptPx)

        End Function

        Friend Function PointerUpFloat(ctx As MASThemeContext,
                               ptPx As SKPoint,
                               button As MouseButtons) As Boolean Implements IMASFloatRoutedInputContent.PointerUpFloat

            If _disposed Then Return False
            If button <> MouseButtons.Left Then Return False
            If _layout Is Nothing Then Return False

            If _panelShellDrag.IsDragging Then
                _panelShellDrag.EndDrag()
                RequestInvalidate()
                Return True
            End If

            If _scrollDragging Then
                _scrollDragging = False
                CompleteContentScrollPointerUp()
                RequestInvalidate()
                Return True
            End If

            Dim handled As Boolean = False

            If _pressedClose Then
                handled = True

                If _request.AllowCloseButton AndAlso Contains(_layout.CloseRect, ptPx) Then
                    ResetPointerState(clearHover:=True)
                    Complete(MessageBoxResult.Close, MASFloatCloseReason.Cancelled)
                    Return True
                End If
            End If

            If _pressedCheckBox Then
                handled = True

                If IsCheckBoxHit(ptPx) Then
                    _request.CheckBoxChecked = Not _request.CheckBoxChecked
                End If

                ResetPointerState(clearHover:=False)
                SyncButtonStatesFromPointer(ptPx, -1)
                RequestInvalidate()
                Return True
            End If

            If _pressedButtonIndex >= 0 Then
                handled = True

                Dim downIndex As Integer = _pressedButtonIndex
                Dim upIndex As Integer = HitButtonIndex(ptPx)

                If upIndex = downIndex Then
                    Dim result As MessageBoxResult =
                ResolveButtonResult(downIndex)

                    ResetPointerState(clearHover:=True)
                    Complete(result)
                    Return True
                End If
            End If

            ResetPointerState(clearHover:=False)
            SyncButtonStatesFromPointer(ptPx, -1)
            RequestInvalidate()

            Return handled

        End Function

        Private Function TryBeginPanelShellDrag(ptPx As SKPoint,
                                                button As MouseButtons) As Boolean
            If _session Is Nothing Then Return False
            If _layout Is Nothing OrElse _layout.ShellResult Is Nothing Then Return False
            If _layout.ShellResult.HitTest(ptPx) <> MASPanelShellHitTarget.Header Then Return False

            Dim currentBoundsPx As SKRect = SKRect.Empty
            If Not _session.TryGetBoundsPx(currentBoundsPx) Then Return False

            Return _panelShellDrag.BeginDrag(
                pointerPx:=ptPx,
                shellResult:=_layout.ShellResult,
                currentBoundsPx:=currentBoundsPx,
                button:=button)
        End Function

        Private Function ResolveAvailableBoundsPx() As SKRect
            If _session Is Nothing Then Return SKRect.Empty

            Try
                Return _session.AvailableBoundsPx
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowBoundary(masCaughtException1, "MessageBox.Float.ResolveAvailableBounds")
            End Try

            Return SKRect.Empty
        End Function

        Friend Function PointerWheelFloat(ctx As MASThemeContext,
                                          ptPx As SKPoint,
                                          delta As Integer) As Boolean Implements IMASFloatRoutedInputContent.PointerWheelFloat

            If _disposed Then Return False
            If _layout Is Nothing Then Return False
            If Not _layout.HasScrollableContent Then Return False

            If Not Contains(_layout.ContentViewportRect, ptPx) AndAlso
               Not Contains(_layout.ContentScrollRailRect, ptPx) Then

                Return False
            End If

            Dim stepY As Single = Math.Max(12.0F, _layout.ContentViewportRect.Height * 0.12F)

            If _scroll IsNot Nothing Then
                Try
                    _scroll.MouseWheel(delta, stepY)
                Catch masCaughtException2 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException2, "MessageBox.Float.ScrollWheel")
                End Try
            Else
                If delta > 0 Then
                    _state.ContentScrollOffsetY -= stepY
                ElseIf delta < 0 Then
                    _state.ContentScrollOffsetY += stepY
                End If
            End If

            SyncScrollOffsetFromAdapter()
            ClampScrollOffset()
            RequestInvalidate()

            Return True

        End Function

#End Region
    End Class

End Namespace
