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

    ''' <summary>
    ''' Official Nexamas UI premium image viewing control. It owns same-surface image viewing,
    ''' zoom, pan, rotate, flip, reset, and transformed export behavior. Image loading, file
    ''' picking, metadata extraction, thumbnail catalogs, galleries, storage prompts, and
    ''' background export jobs remain outside this visual control.
    ''' </summary>
    Partial Public NotInheritable Class MASImageViewer
        Inherits MASControlBase
        Implements IMASLayoutParticipant
        Implements IMASIntrinsicSizeContract

#Region "Fields"

        Private Shared ReadOnly _contract As MASResolvedComponentContract =
            MASArchitectureRuntime.ResolveContractOrThrow(GetType(MASImageViewer))

        Private ReadOnly _primitives As New MASVisualPrimitivesPainter()
        Private _disposedLocal As Boolean

        Private Enum ImageViewerAction
            None = 0
            ZoomOut = 1
            ZoomIn = 2
            Fit = 3
            Actual = 4
            RotateLeft = 5
            RotateRight = 6
            FlipHorizontal = 7
            FlipVertical = 8
            Reset = 9
            Export = 10
        End Enum


        Private _bitmap As SKBitmap
        Private _ownsBitmap As Boolean
        Private _title As String = ImageViewerTokens.DefaultTitle
        Private _subtitle As String = String.Empty
        Private _zoom As Single = ImageViewerTokens.DefaultZoom
        Private _rotationDegrees As Integer
        Private _flippedHorizontal As Boolean
        Private _flippedVertical As Boolean
        Private _panX As Single
        Private _panY As Single
        Private _chromeMode As MASImageViewerChromeMode = MASImageViewerChromeMode.Pinned
        Private _showFooter As Boolean = True
        Private _chromeHot As Boolean
        Private _lastViewerFrameRect As SKRect = SKRect.Empty
        Private _lastToolbarRect As SKRect = SKRect.Empty
        Private _lastViewportRect As SKRect = SKRect.Empty
        Private _lastContentRect As SKRect = SKRect.Empty
        Private _lastFitZoom As Single = ImageViewerTokens.DefaultZoom
        Private _fitMode As Boolean = True
        Private _imageFitMode As MASImageViewerImageFitMode = MASImageViewerImageFitMode.Cover
        Private _hoverAction As ImageViewerAction = ImageViewerAction.None
        Private _pressedAction As ImageViewerAction = ImageViewerAction.None
        Private _draggingPan As Boolean
        Private _dragStartPt As SKPoint
        Private _dragStartPanX As Single
        Private _dragStartPanY As Single
        Private _buttons As MASMediaButtonModel() = Array.Empty(Of MASMediaButtonModel)()

#End Region

#Region "Constructor / Factory"

        Public Sub New()
            MyBase.New()
        End Sub

        Public Shared Function Create(Optional title As String = Nothing,
                                      Optional subtitle As String = Nothing) As MASImageViewer
            Dim control As New MASImageViewer()
            control._title = MASImageViewerVisualPolicy.NormalizeText(title, ImageViewerTokens.DefaultTitle)
            control._subtitle = MASImageViewerVisualPolicy.NormalizeText(subtitle, String.Empty)
            Return control
        End Function

#End Region

#Region "Public API"

        Public Event ImageChanged As EventHandler
        Public Event ViewChanged As EventHandler
        Public Event ExportRequested As EventHandler
        Public Event ImageExported As EventHandler

        Public Property Title As String
            Get
                Return _title
            End Get
            Set(value As String)
                Dim normalized As String = MASImageViewerVisualPolicy.NormalizeText(value, ImageViewerTokens.DefaultTitle)
                If String.Equals(_title, normalized, StringComparison.Ordinal) Then Return
                _title = normalized
                RequestSizeLayoutRefreshForSizeAffectingChange("MASImageViewer.Title")
                InvalidateVisual()
            End Set
        End Property

        Public Property Subtitle As String
            Get
                Return _subtitle
            End Get
            Set(value As String)
                Dim normalized As String = MASImageViewerVisualPolicy.NormalizeText(value, String.Empty)
                If String.Equals(_subtitle, normalized, StringComparison.Ordinal) Then Return
                _subtitle = normalized
                RequestSizeLayoutRefreshForSizeAffectingChange("MASImageViewer.Subtitle")
                InvalidateVisual()
            End Set
        End Property

        Public ReadOnly Property HasImage As Boolean
            Get
                Return _bitmap IsNot Nothing AndAlso _bitmap.Width > 0 AndAlso _bitmap.Height > 0
            End Get
        End Property

        Public ReadOnly Property ImageWidth As Integer
            Get
                If _bitmap Is Nothing Then Return 0
                Return _bitmap.Width
            End Get
        End Property

        Public ReadOnly Property ImageHeight As Integer
            Get
                If _bitmap Is Nothing Then Return 0
                Return _bitmap.Height
            End Get
        End Property


        Friend Property ImageFitMode As MASImageViewerImageFitMode
            Get
                Return _imageFitMode
            End Get
            Set(value As MASImageViewerImageFitMode)
                If _imageFitMode = value Then Return
                _imageFitMode = value
                If _fitMode Then
                    _zoom = ResolveFitZoom()
                    _panX = 0.0F
                    _panY = 0.0F
                Else
                    ClampPanToViewport()
                End If
                RaiseViewChangedSafe()
                InvalidateVisual()
            End Set
        End Property

        Friend Function WithImageFitMode(value As MASImageViewerImageFitMode) As MASImageViewer
            ImageFitMode = value
            Return Me
        End Function

        Public Property Zoom As Single
            Get
                Return _zoom
            End Get
            Set(value As Single)
                _fitMode = False
                SetZoomInternal(value, True)
            End Set
        End Property

        Public Property RotationDegrees As Integer
            Get
                Return _rotationDegrees
            End Get
            Set(value As Integer)
                Dim normalized As Integer = MASImageViewerVisualPolicy.NormalizeRotation(value)
                If _rotationDegrees = normalized Then Return
                _rotationDegrees = normalized
                If _fitMode Then
                    _zoom = ResolveFitZoom()
                    _panX = 0.0F
                    _panY = 0.0F
                Else
                    ClampPanToViewport()
                End If
                RaiseViewChangedSafe()
                InvalidateVisual()
            End Set
        End Property

        Public Property FlippedHorizontal As Boolean
            Get
                Return _flippedHorizontal
            End Get
            Set(value As Boolean)
                If _flippedHorizontal = value Then Return
                _flippedHorizontal = value
                RaiseViewChangedSafe()
                InvalidateVisual()
            End Set
        End Property

        Public Property FlippedVertical As Boolean
            Get
                Return _flippedVertical
            End Get
            Set(value As Boolean)
                If _flippedVertical = value Then Return
                _flippedVertical = value
                RaiseViewChangedSafe()
                InvalidateVisual()
            End Set
        End Property

        Public Property ChromeMode As MASImageViewerChromeMode
            Get
                Return _chromeMode
            End Get
            Set(value As MASImageViewerChromeMode)
                If Not [Enum].IsDefined(GetType(MASImageViewerChromeMode), value) Then value = MASImageViewerChromeMode.AutoHide
                If _chromeMode = value Then Return
                _chromeMode = value
                _chromeHot = (value = MASImageViewerChromeMode.Pinned)
                _hoverAction = ImageViewerAction.None
                _pressedAction = ImageViewerAction.None
                RequestSizeLayoutRefreshForSizeAffectingChange("MASImageViewer.ChromeMode")
                InvalidateVisual()
            End Set
        End Property

        Public Property ShowFooter As Boolean
            Get
                Return _showFooter
            End Get
            Set(value As Boolean)
                If _showFooter = value Then Return
                _showFooter = value
                RequestSizeLayoutRefreshForSizeAffectingChange("MASImageViewer.ShowFooter")
                InvalidateVisual()
            End Set
        End Property

        Public Function WithFooter(Optional visible As Boolean = True) As MASImageViewer
            ShowFooter = visible
            Return Me
        End Function

        Public Function WithChromeMode(mode As MASImageViewerChromeMode) As MASImageViewer
            ChromeMode = mode
            Return Me
        End Function

        Public Shadows Function WithSize(sizeIntent As MASSize) As MASImageViewer
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function

#End Region

    End Class

End Namespace
