Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Components
Imports Nexamas.UI.Controls
Imports Nexamas.UI.General
Imports Nexamas.UI.Theming
Imports SkiaSharp

Namespace Nexamas.UI.Rendering

    Friend NotInheritable Class MASButtonRenderer
        Implements IDisposable

        Private ReadOnly _res As New UnifiedButtonRenderer.RenderResources()
        Private ReadOnly _primitives As New MASVisualPrimitivesPainter()
        Private ReadOnly _shadow As New MASShadowPainter()

        Private _disposed As Boolean

        Friend Sub RenderSingle(canvas As SKCanvas,
                                ctx As MASThemeContext,
                                rect As SKRect,
                                dpi As Single,
                                spec As MASButtonSpec,
                                state As MASButtonState,
                                contract As MASResolvedComponentContract,
                                Optional drawIcon As Action(Of SKCanvas, SKRect, Single, SKColor) = Nothing,
                                Optional drawIconEmphasis As Action(Of SKCanvas, SKRect, Single, SKColor) = Nothing,
                                Optional iconPlacement As MASButtonIconPlacement = MASButtonIconPlacement.Left)

            If _disposed Then Return
            If canvas Is Nothing OrElse ctx Is Nothing Then Return
            If spec Is Nothing Then Return

            If contract Is Nothing Then
                Throw New ArgumentNullException(NameOf(contract), "MASButtonRenderer requires a resolved architecture contract.")
            End If

            Dim scope As MASContractRenderScope =
    MASArchitectureRuntime.CreateRenderScopeForComponent(Of MASButton)(
        NameOf(MASButtonRenderer),
        contract,
        MASRenderLayer.Surface,
        MASRenderLayer.Shadow,
        MASRenderLayer.Text,
        MASRenderLayer.Hover,
        MASRenderLayer.Pressed,
        MASRenderLayer.Focus)

            scope.RequireAnyLayer(
    MASRenderLayer.Surface,
    MASRenderLayer.Shadow,
    MASRenderLayer.Text,
    MASRenderLayer.Hover,
    MASRenderLayer.Pressed,
    MASRenderLayer.Focus)

            If rect.IsEmpty Then Return

            Dim rectPx As SKRect = PixelSnap.SnapRectHalf(rect)
            If rectPx.Width <= 1.0F OrElse rectPx.Height <= 1.0F Then Return

            Dim effectiveState As MASButtonState = state
            effectiveState.IsEnabled = spec.IsEnabled

            UnifiedButtonRenderer.Draw(
                canvas:=canvas,
                ctx:=ctx,
                primitives:=_primitives,
                shadow:=_shadow,
                rPx:=rectPx,
                personality:=spec.Personality,
                text:=If(spec.Text, String.Empty),
                state:=effectiveState,
                contract:=contract,
                isSelected:=spec.IsSelected,
                isDefault:=spec.IsDefault,
                intent:=spec.Intent,
                drawIcon:=drawIcon,
                drawIconEmphasis:=If(drawIconEmphasis, drawIcon),
                iconPlacement:=iconPlacement,
                dpi:=dpi,
                res:=_res
            )

        End Sub

        Friend Sub RenderMany(canvas As SKCanvas,
                              ctx As MASThemeContext,
                              rects As IReadOnlyList(Of SKRect),
                              dpi As Single,
                              specs As IReadOnlyList(Of MASButtonSpec),
                              states As IReadOnlyList(Of MASButtonState),
                              contract As MASResolvedComponentContract,
                              Optional drawIcons As IReadOnlyList(Of Action(Of SKCanvas, SKRect, Single, SKColor)) = Nothing,
                              Optional drawIconEmphases As IReadOnlyList(Of Action(Of SKCanvas, SKRect, Single, SKColor)) = Nothing)

            If _disposed Then Return
            If canvas Is Nothing OrElse ctx Is Nothing Then Return
            If rects Is Nothing OrElse specs Is Nothing OrElse states Is Nothing Then Return

            If contract Is Nothing Then
                Throw New ArgumentNullException(NameOf(contract), "MASButtonRenderer requires a resolved architecture contract.")
            End If


            If rects.Count = 0 OrElse specs.Count = 0 OrElse states.Count = 0 Then Return
            If rects.Count <> specs.Count OrElse rects.Count <> states.Count Then Return

            If drawIcons IsNot Nothing AndAlso drawIcons.Count <> rects.Count Then Return
            If drawIconEmphases IsNot Nothing AndAlso drawIconEmphases.Count <> rects.Count Then Return

            For i As Integer = 0 To specs.Count - 1
                Dim icon As Action(Of SKCanvas, SKRect, Single, SKColor) = Nothing
                Dim iconEmphasis As Action(Of SKCanvas, SKRect, Single, SKColor) = Nothing

                If drawIcons IsNot Nothing Then
                    icon = drawIcons(i)
                End If

                If drawIconEmphases IsNot Nothing Then
                    iconEmphasis = drawIconEmphases(i)
                End If

                RenderSingle(
                    canvas:=canvas,
                    ctx:=ctx,
                    rect:=rects(i),
                    dpi:=dpi,
                    spec:=specs(i),
                    state:=states(i),
                    contract:=contract,
                    drawIcon:=icon,
                    drawIconEmphasis:=iconEmphasis
                )
            Next

        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            If _disposed Then Return
            _disposed = True

            Try
                _res.Dispose()
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException1)
            End Try

            Try
                _primitives.Dispose()
            Catch masCaughtException2 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException2)
            End Try

            Try
                _shadow.Dispose()
            Catch masCaughtException3 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException3)
            End Try
        End Sub

    End Class

End Namespace
