Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Components

    Friend Partial NotInheritable Class MASTimePickerClockView

#Region "Rendering"

        Protected Overrides Sub Render(canvas As SKCanvas,
                                       ctx As MASThemeContext,
                                       pixelBounds As SKRect)
            If canvas Is Nothing OrElse ctx Is Nothing Then Return
            If pixelBounds.Width <= 1.0F OrElse pixelBounds.Height <= 1.0F Then Return

            _contract.AssertConsumable()

            Dim dpi As Single = PixelSnap.SafeDpi(ctx.Dpi)
            Dim app As IMASAppTheme = ctx.Theme
            If app Is Nothing Then Return

            Dim surfTheme As IMASFoundationSurfaceTheme = MASAppThemeContracts.Foundation(app).Surface
            If surfTheme Is Nothing Then Return

            Dim card As SKRect = PixelSnap.SnapRectHalf(pixelBounds)
            Dim plan As MASTimePickerClockLayoutPlan = MASTimePickerClockLayoutPlan.Create(ctx, card, SizeIntent)
            _lastLayoutPlan = plan
            Dim metricDpi As Single = plan.MetricDpi

            _shadowPainter.DrawLayeredShadow(canvas, card, _contract, dpi, surfTheme)
            _primitives.DrawAcrylicSurface(canvas, ctx, card, dpi, _contract)

            Dim inner As SKRect = Inset(card, plan.OuterPadPx)
            If inner.Width <= 1.0F OrElse inner.Height <= 1.0F Then Return

            Dim textTheme As IMASTextColorTheme = ctx.TextColorTheme
            Dim brand As IMASBrandTheme = ctx.BrandTheme
            Dim neutral As IMASNeutralTheme = ctx.NeutralTheme

            Dim primaryText As SKColor = If(textTheme Is Nothing, SKColors.Black, textTheme.PrimaryText)
            Dim secondaryText As SKColor = If(textTheme Is Nothing, SKColors.DimGray, textTheme.SecondaryText)
            Dim mutedText As SKColor = If(textTheme Is Nothing, SKColors.Gray, textTheme.MutedText)
            Dim brandPrimary As SKColor = If(brand Is Nothing, SKColors.DodgerBlue, brand.BrandPrimary)
            Dim onBrand As SKColor = If(textTheme Is Nothing, SKColors.White, textTheme.OnBrandPrimaryText)
            Dim border As SKColor = If(neutral Is Nothing, SKColors.Gray.WithAlpha(75), neutral.BorderSubtle)

            Dim header As New SKRect(inner.Left, inner.Top, inner.Right, inner.Top + plan.HeaderHeightPx)
            DrawHeader(canvas, ctx, header, metricDpi, plan, primaryText, mutedText, border)

            Dim displayTop As Single = header.Bottom + plan.InnerGapPx
            Dim display As New SKRect(inner.Left, displayTop, inner.Right, displayTop + plan.DisplayHeightPx)
            DrawDisplay(canvas, ctx, display, metricDpi, primaryText, mutedText, brandPrimary, border)

            Dim controlTop As Single = display.Bottom + plan.InnerGapPx
            Dim controls As New SKRect(inner.Left, controlTop, inner.Right, Math.Min(controlTop + plan.StepperHeightPx, inner.Bottom))
            DrawSteppers(canvas, ctx, controls, metricDpi, plan, primaryText, secondaryText, brandPrimary)

            Dim footerTop As Single = controls.Bottom + plan.InnerGapPx
            Dim footer As New SKRect(inner.Left, footerTop, inner.Right, inner.Bottom)
            DrawFooter(canvas, ctx, footer, metricDpi, plan, secondaryText, mutedText, brandPrimary, onBrand)
        End Sub

        Private Sub DrawHeader(canvas As SKCanvas,
                               ctx As MASThemeContext,
                               header As SKRect,
                               dpi As Single,
                               plan As MASTimePickerClockLayoutPlan,
                               primaryText As SKColor,
                               mutedText As SKColor,
                               border As SKColor)
            TypographyTextPrimitives.DrawSingleLineText(canvas, ctx, "Select time", header, dpi, MASTypography.MASTextStyle.Body, primaryText, TypographyTextPrimitives.TextAlign.Left, False)

            If plan.ShowHeaderMeta Then
                Dim stepText As String = String.Format(CultureInfo.CurrentCulture, "{0} min step", _minuteStep)
                TypographyTextPrimitives.DrawSingleLineText(canvas, ctx, stepText, header, dpi, MASTypography.MASTextStyle.Small, mutedText, TypographyTextPrimitives.TextAlign.Right, False)
            End If

            Using p As New SKPaint()
                p.IsAntialias = True
                p.Style = SKPaintStyle.Stroke
                p.StrokeWidth = Math.Max(1.0F, 1.0F * dpi)
                p.Color = border.WithAlpha(90)
                canvas.DrawLine(header.Left, header.Bottom, header.Right, header.Bottom, p)
            End Using
        End Sub

        Private Sub DrawDisplay(canvas As SKCanvas,
                                ctx As MASThemeContext,
                                display As SKRect,
                                dpi As Single,
                                primaryText As SKColor,
                                mutedText As SKColor,
                                brandPrimary As SKColor,
                                border As SKColor)
            display = PixelSnap.SnapRectHalf(display)
            _lastDisplayRect = display
            Dim radius As Single = Math.Max(8.0F * dpi, display.Height * 0.28F)
            Dim hover As Boolean = IsSameHit(_hoverTarget, HitPart.DisplayEditor)
            Dim pressed As Boolean = IsSameHit(_pressedTarget, HitPart.DisplayEditor)

            Using p As New SKPaint()
                p.IsAntialias = True
                p.Style = SKPaintStyle.Fill
                p.Color = brandPrimary.WithAlpha(If(_isEditingTime, TimePickerTokens.ButtonHoverOverlayAlpha, TimePickerTokens.DisplayWashAlpha))
                canvas.DrawRoundRect(display, radius, radius, p)

                If _isEditingTime AndAlso _editSelectAll Then
                    Dim selectionRect As SKRect = Inset(display, 5.0F * dpi)
                    p.Color = brandPrimary.WithAlpha(TimePickerTokens.ButtonHoverOverlayAlpha)
                    canvas.DrawRoundRect(selectionRect, Math.Max(5.0F * dpi, selectionRect.Height * 0.24F), Math.Max(5.0F * dpi, selectionRect.Height * 0.24F), p)
                ElseIf pressed Then
                    p.Color = brandPrimary.WithAlpha(TimePickerTokens.ButtonPressedOverlayAlpha)
                    canvas.DrawRoundRect(display, radius, radius, p)
                ElseIf hover Then
                    p.Color = brandPrimary.WithAlpha(TimePickerTokens.ButtonHoverOverlayAlpha)
                    canvas.DrawRoundRect(display, radius, radius, p)
                End If

                p.Style = SKPaintStyle.Stroke
                p.StrokeWidth = Math.Max(1.0F, If(_isEditingTime, 1.35F, 1.0F) * dpi)
                p.Color = If(_isEditingTime, brandPrimary.WithAlpha(185), border.WithAlpha(120))
                canvas.DrawRoundRect(display, radius, radius, p)
            End Using

            DrawTimeValueMotionPulse(canvas, display, radius, dpi, brandPrimary)

            Dim valueRect As New SKRect(display.Left + (12.0F * dpi), display.Top, display.Right - (12.0F * dpi), display.Bottom)
            Dim displayText As String = If(_isEditingTime, ResolveManualEditDisplayText(), MASTimePicker.FormatTime(_workingTime))
            Dim color As SKColor = If(_isEditingTime AndAlso _editBuffer.Length = 0, mutedText, primaryText)
            TypographyTextPrimitives.DrawSingleLineText(canvas, ctx, displayText, valueRect, dpi, MASTypography.MASTextStyle.Title, color, TypographyTextPrimitives.TextAlign.Center, False)

            If _isEditingTime Then
                DrawManualEditCaret(canvas, valueRect, dpi, primaryText)
            End If
        End Sub

        Private Shared Sub DrawManualEditCaret(canvas As SKCanvas,
                                               valueRect As SKRect,
                                               dpi As Single,
                                               color As SKColor)
            Dim caretHeight As Single = Math.Max(12.0F * dpi, valueRect.Height * 0.42F)
            Dim caretX As Single = valueRect.MidX + (32.0F * dpi)
            Using p As New SKPaint()
                p.IsAntialias = True
                p.Style = SKPaintStyle.Stroke
                p.StrokeWidth = Math.Max(1.0F, 1.0F * dpi)
                p.Color = color.WithAlpha(150)
                canvas.DrawLine(caretX, valueRect.MidY - (caretHeight * 0.5F), caretX, valueRect.MidY + (caretHeight * 0.5F), p)
            End Using
        End Sub

        Private Sub DrawSteppers(canvas As SKCanvas,
                                 ctx As MASThemeContext,
                                 controls As SKRect,
                                 dpi As Single,
                                 plan As MASTimePickerClockLayoutPlan,
                                 primaryText As SKColor,
                                 secondaryText As SKColor,
                                 brandPrimary As SKColor)
            Dim gap As Single = Math.Min(plan.ColumnGapPx, Math.Max(0.0F, controls.Width * 0.18F))
            Dim colWidth As Single = (controls.Width - gap) * 0.5F
            If colWidth <= 1.0F OrElse controls.Height <= 1.0F Then
                _lastHourUpRect = SKRect.Empty
                _lastHourDownRect = SKRect.Empty
                _lastMinuteUpRect = SKRect.Empty
                _lastMinuteDownRect = SKRect.Empty
                Return
            End If
            Dim hourCol As New SKRect(controls.Left, controls.Top, controls.Left + colWidth, controls.Bottom)
            Dim minuteCol As New SKRect(hourCol.Right + gap, controls.Top, controls.Right, controls.Bottom)

            DrawStepperColumn(canvas, ctx, hourCol, dpi, plan, MASTimePickerClockFormatPolicy.FormatHourLabel(_workingTime, _clockFormat), MASTimePickerClockFormatPolicy.FormatHourDigits(_workingTime, _clockFormat), HitPart.HourDown, HitPart.HourUp, primaryText, secondaryText, brandPrimary)
            DrawStepperColumn(canvas, ctx, minuteCol, dpi, plan, "Minute", _workingTime.Minutes.ToString("00", CultureInfo.CurrentCulture), HitPart.MinuteDown, HitPart.MinuteUp, primaryText, secondaryText, brandPrimary)
        End Sub

        Private Sub DrawStepperColumn(canvas As SKCanvas,
                                      ctx As MASThemeContext,
                                      column As SKRect,
                                      dpi As Single,
                                      plan As MASTimePickerClockLayoutPlan,
                                      label As String,
                                      value As String,
                                      downPart As HitPart,
                                      upPart As HitPart,
                                      primaryText As SKColor,
                                      secondaryText As SKColor,
                                      brandPrimary As SKColor)
            Dim buttonH As Single = plan.StepperButtonHeightPx
            Dim labelH As Single = plan.StepperLabelHeightPx
            Dim gap As Single = plan.StepperGapPx

            Dim upRect As SKRect = PixelSnap.SnapRectHalf(New SKRect(column.Left, column.Top, column.Right, column.Top + buttonH))
            Dim valueRect As SKRect = PixelSnap.SnapRectHalf(New SKRect(column.Left, upRect.Bottom + gap, column.Right, column.Bottom - buttonH - gap))
            Dim downRect As SKRect = PixelSnap.SnapRectHalf(New SKRect(column.Left, column.Bottom - buttonH, column.Right, column.Bottom))
            Dim labelRect As New SKRect(valueRect.Left, valueRect.Top, valueRect.Right, valueRect.Top + labelH)
            Dim numberRect As New SKRect(valueRect.Left, labelRect.Bottom, valueRect.Right, valueRect.Bottom)

            If upRect.Width <= 1.0F OrElse upRect.Height <= 1.0F OrElse downRect.Width <= 1.0F OrElse downRect.Height <= 1.0F OrElse valueRect.Width <= 1.0F OrElse valueRect.Height <= 1.0F Then
                If upPart = HitPart.HourUp Then
                    _lastHourUpRect = SKRect.Empty
                    _lastHourDownRect = SKRect.Empty
                Else
                    _lastMinuteUpRect = SKRect.Empty
                    _lastMinuteDownRect = SKRect.Empty
                End If
                Return
            End If

            If upPart = HitPart.HourUp Then
                _lastHourUpRect = upRect
                _lastHourDownRect = downRect
            Else
                _lastMinuteUpRect = upRect
                _lastMinuteDownRect = downRect
            End If

            DrawActionButton(canvas, ctx, upRect, dpi, "+", upPart, primaryText, brandPrimary, False)
            DrawActionButton(canvas, ctx, downRect, dpi, "−", downPart, primaryText, brandPrimary, False)

            TypographyTextPrimitives.DrawSingleLineText(canvas, ctx, label, labelRect, dpi, MASTypography.MASTextStyle.Small, secondaryText, TypographyTextPrimitives.TextAlign.Center, False)
            TypographyTextPrimitives.DrawSingleLineText(canvas, ctx, value, numberRect, dpi, MASTypography.MASTextStyle.Title, primaryText, TypographyTextPrimitives.TextAlign.Center, False)
        End Sub

        Private Sub DrawFooter(canvas As SKCanvas,
                               ctx As MASThemeContext,
                               footer As SKRect,
                               dpi As Single,
                               plan As MASTimePickerClockLayoutPlan,
                               secondaryText As SKColor,
                               mutedText As SKColor,
                               brandPrimary As SKColor,
                               onBrand As SKColor)
            Dim gap As Single = Math.Min(plan.FooterGapPx, Math.Max(0.0F, footer.Width * 0.12F))
            Dim buttonH As Single = Math.Min(plan.FooterButtonHeightPx, footer.Height)
            Dim buttonTop As Single = footer.Bottom - buttonH
            If footer.Width <= 1.0F OrElse buttonH <= 1.0F Then
                _lastNowRect = SKRect.Empty
                _lastClearRect = SKRect.Empty
                _lastConfirmRect = SKRect.Empty
                Return
            End If
            If plan.ShowFooterSecondary Then
                Dim smallW As Single = Math.Max(58.0F * dpi, (footer.Width - (gap * 2.0F)) * 0.24F)
                Dim confirmW As Single = footer.Width - (smallW * 2.0F) - (gap * 2.0F)

                _lastNowRect = PixelSnap.SnapRectHalf(New SKRect(footer.Left, buttonTop, footer.Left + smallW, footer.Bottom))
                _lastClearRect = PixelSnap.SnapRectHalf(New SKRect(_lastNowRect.Right + gap, buttonTop, _lastNowRect.Right + gap + smallW, footer.Bottom))
                _lastConfirmRect = PixelSnap.SnapRectHalf(New SKRect(_lastClearRect.Right + gap, buttonTop, _lastClearRect.Right + gap + confirmW, footer.Bottom))

                DrawActionButton(canvas, ctx, _lastNowRect, dpi, "Now", HitPart.NowAction, secondaryText, brandPrimary, False)
                DrawActionButton(canvas, ctx, _lastClearRect, dpi, "Clear", HitPart.ClearAction, mutedText, brandPrimary, False)
            Else
                _lastNowRect = SKRect.Empty
                _lastClearRect = SKRect.Empty
                _lastConfirmRect = PixelSnap.SnapRectHalf(New SKRect(footer.Left, buttonTop, footer.Right, footer.Bottom))
            End If
            DrawActionButton(canvas, ctx, _lastConfirmRect, dpi, "Done", HitPart.ConfirmAction, onBrand, brandPrimary, True)
        End Sub

        Private Sub DrawActionButton(canvas As SKCanvas,
                                     ctx As MASThemeContext,
                                     rect As SKRect,
                                     dpi As Single,
                                     text As String,
                                     part As HitPart,
                                     textColor As SKColor,
                                     brandPrimary As SKColor,
                                     filled As Boolean)
            Dim hover As Boolean = IsSameHit(_hoverTarget, part)
            Dim pressed As Boolean = IsSameHit(_pressedTarget, part)
            Dim radius As Single = Math.Max(5.0F * dpi, rect.Height * 0.32F)

            Using p As New SKPaint()
                p.IsAntialias = True
                p.Style = SKPaintStyle.Fill
                If filled Then
                    p.Color = If(pressed, brandPrimary.WithAlpha(TimePickerTokens.ButtonPressedFillAlpha), brandPrimary.WithAlpha(TimePickerTokens.ButtonFillAlpha))
                    canvas.DrawRoundRect(rect, radius, radius, p)
                ElseIf pressed Then
                    p.Color = brandPrimary.WithAlpha(TimePickerTokens.ButtonPressedOverlayAlpha)
                    canvas.DrawRoundRect(rect, radius, radius, p)
                ElseIf hover Then
                    p.Color = brandPrimary.WithAlpha(TimePickerTokens.ButtonHoverOverlayAlpha)
                    canvas.DrawRoundRect(rect, radius, radius, p)
                End If
            End Using

            TypographyTextPrimitives.DrawSingleLineText(canvas, ctx, text, rect, dpi, MASTypography.MASTextStyle.Body, textColor, TypographyTextPrimitives.TextAlign.Center, False)
        End Sub

#End Region

    End Class

End Namespace
