Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports System.IO
Imports System.Windows.Forms
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Composition
Imports Nexamas.UI.Controls
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    Partial Public NotInheritable Class MASImageViewer
#Region "Input"

        Protected Overrides Sub OnMouseMove(ctx As MASThemeContext, ptPx As SKPoint)
            Dim chromeChanged As Boolean = UpdateChromeHotState(ptPx)

            If _draggingPan Then
                _panX = _dragStartPanX + (ptPx.X - _dragStartPt.X)
                _panY = _dragStartPanY + (ptPx.Y - _dragStartPt.Y)
                ClampPanToViewport()
                InvalidateVisual()
                Return
            End If

            Dim action As ImageViewerAction = HitTestToolbar(ptPx)
            If _hoverAction = action Then
                If chromeChanged Then InvalidateVisual()
                Return
            End If
            _hoverAction = action
            InvalidateVisual()
        End Sub

        Protected Overrides Function OnMouseDown(ctx As MASThemeContext,
                                                 ptPx As SKPoint,
                                                 button As Integer) As Boolean
            If button <> CInt(MouseButtons.Left) Then Return False

            Dim action As ImageViewerAction = HitTestToolbar(ptPx)
            If action <> ImageViewerAction.None Then
                _chromeHot = True
                _pressedAction = action
                InvalidateVisual()
                Return True
            End If

            If HasImage AndAlso _lastContentRect.Contains(ptPx.X, ptPx.Y) Then
                If CanPanCurrentView() Then
                    _fitMode = False
                    _draggingPan = True
                    _dragStartPt = ptPx
                    _dragStartPanX = _panX
                    _dragStartPanY = _panY
                End If
                Return True
            End If

            Return _lastViewportRect.Contains(ptPx.X, ptPx.Y)
        End Function

        Protected Overrides Function OnMouseUp(ctx As MASThemeContext,
                                               ptPx As SKPoint,
                                               button As Integer) As Boolean
            If button <> CInt(MouseButtons.Left) Then Return False

            If _pressedAction <> ImageViewerAction.None Then
                Dim pressed As ImageViewerAction = _pressedAction
                _pressedAction = ImageViewerAction.None
                If HitTestToolbar(ptPx) = pressed Then ExecuteToolbarAction(pressed)
                InvalidateVisual()
                Return True
            End If

            If _draggingPan Then
                _draggingPan = False
                ClampPanToViewport()
                RaiseViewChangedSafe()
                InvalidateVisual()
                Return True
            End If

            Return False
        End Function

        Friend Overrides Function WantsPointerWheel(ctx As MASThemeContext, ptPx As SKPoint) As Boolean
            Return HasImage AndAlso _lastContentRect.Contains(ptPx.X, ptPx.Y)
        End Function

        Friend Overrides Function CanHandlePointerWheel(ctx As MASThemeContext, delta As Integer, ptPx As SKPoint) As Boolean
            If Not WantsPointerWheel(ctx, ptPx) Then Return False
            If delta > 0 Then Return _zoom < ImageViewerTokens.MaxZoom - 0.0001F
            If delta < 0 Then Return _zoom > ResolveFitZoom() + 0.0001F
            Return False
        End Function

        Protected Overrides Sub OnMouseWheel(ctx As MASThemeContext,
                                             delta As Integer,
                                             ptPx As SKPoint)
            If delta > 0 Then
                SetZoomAroundPoint(_zoom * ImageViewerTokens.ZoomStep, ptPx, True)
            ElseIf delta < 0 Then
                SetZoomAroundPoint(_zoom / ImageViewerTokens.ZoomStep, ptPx, True)
            End If
        End Sub

        Protected Overrides Sub OnMouseLeave(ctx As MASThemeContext)
            If _draggingPan Then Return
            If _hoverAction = ImageViewerAction.None AndAlso _pressedAction = ImageViewerAction.None AndAlso Not _chromeHot Then Return
            _hoverAction = ImageViewerAction.None
            _pressedAction = ImageViewerAction.None
            _chromeHot = False
            InvalidateVisual()
        End Sub

        Protected Overrides Sub OnMouseCancel(ctx As MASThemeContext)
            ClearInteractionState()
            InvalidateVisual()
        End Sub

        Protected Overrides Sub OnHostLostFocus(ctx As MASThemeContext)
            ClearInteractionState()
            InvalidateVisual()
        End Sub

        Protected Overrides Function OnKeyDown(ctx As MASThemeContext,
                                               keyCode As Keys) As Boolean
            If _chromeMode = MASImageViewerChromeMode.AutoHide Then _chromeHot = True
            Select Case keyCode
                Case Keys.Add, Keys.Oemplus
                    ZoomIn()
                    Return True
                Case Keys.Subtract, Keys.OemMinus
                    ZoomOut()
                    Return True
                Case Keys.F
                    FitToView()
                    Return True
                Case Keys.D0, Keys.NumPad0
                    ActualSize()
                    Return True
                Case Keys.R
                    RotateRight()
                    Return True
                Case Keys.L
                    RotateLeft()
                    Return True
                Case Keys.H
                    FlipHorizontal()
                    Return True
                Case Keys.V
                    FlipVertical()
                    Return True
                Case Keys.Home
                    ResetView()
                    Return True
                Case Keys.Left
                    PanBy(If(MASImageViewerVisualPolicy.ResolveRightToLeft(), ImageViewerTokens.PanKeyboardStepDip, -ImageViewerTokens.PanKeyboardStepDip) * PixelSnap.SafeDpi(ctx.Dpi), 0.0F)
                    Return True
                Case Keys.Right
                    PanBy(If(MASImageViewerVisualPolicy.ResolveRightToLeft(), -ImageViewerTokens.PanKeyboardStepDip, ImageViewerTokens.PanKeyboardStepDip) * PixelSnap.SafeDpi(ctx.Dpi), 0.0F)
                    Return True
                Case Keys.Up
                    PanBy(0.0F, -ImageViewerTokens.PanKeyboardStepDip * PixelSnap.SafeDpi(ctx.Dpi))
                    Return True
                Case Keys.Down
                    PanBy(0.0F, ImageViewerTokens.PanKeyboardStepDip * PixelSnap.SafeDpi(ctx.Dpi))
                    Return True
            End Select
            Return False
        End Function

        Protected Overrides Function WantsKeyboardFocus() As Boolean
            Return MASCompositeContentFocusPolicy.CanReceiveKeyboardFocus(_contract, Visible, Enabled)
        End Function

        Protected Overrides Function WantsPointerFocus() As Boolean
            Return MASCompositeContentFocusPolicy.AllowsPointerFocusForCompositeContent(_contract, Visible, Enabled)
        End Function

#End Region

#Region "Interaction Helpers"

        Private Function UpdateChromeHotState(ptPx As SKPoint) As Boolean
            If _chromeMode <> MASImageViewerChromeMode.AutoHide Then Return False
            If _pressedAction <> ImageViewerAction.None OrElse _draggingPan Then Return False

            Dim hot As Boolean = False
            If _lastToolbarRect.Width > 1.0F AndAlso _lastToolbarRect.Height > 1.0F Then
                hot = _lastToolbarRect.Contains(ptPx.X, ptPx.Y)
            End If

            If _chromeHot = hot Then Return False
            _chromeHot = hot
            Return True
        End Function

        Private Function HitTestToolbar(ptPx As SKPoint) As ImageViewerAction
            If Not ShouldRenderToolbarChrome() Then Return ImageViewerAction.None

            Dim actionId As Integer = 0
            If Not MASMediaButtonHitTester.TryHitTest(_buttons, ptPx, actionId) Then Return ImageViewerAction.None

            Dim action As ImageViewerAction = CType(actionId, ImageViewerAction)
            If IsToolbarActionEnabled(action) Then Return action
            Return ImageViewerAction.None
        End Function

        Private Sub ExecuteToolbarAction(action As ImageViewerAction)
            If Not HasImage Then Return
            Select Case action
                Case ImageViewerAction.ZoomOut
                    ZoomOut()
                Case ImageViewerAction.ZoomIn
                    ZoomIn()
                Case ImageViewerAction.Fit
                    FitToView()
                Case ImageViewerAction.Actual
                    ActualSize()
                Case ImageViewerAction.RotateLeft
                    RotateLeft()
                Case ImageViewerAction.RotateRight
                    RotateRight()
                Case ImageViewerAction.FlipHorizontal
                    FlipHorizontal()
                Case ImageViewerAction.FlipVertical
                    FlipVertical()
                Case ImageViewerAction.Reset
                    ResetView()
                Case ImageViewerAction.Export
                    RaiseExportRequestedSafe()
            End Select
        End Sub

#End Region

    End Class

End Namespace
