Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
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 MASPivotTable

#Region "Geometry and selection"

        Private Function GetRowHeaderRect(rect As SKRect, dpi As Single, isRtl As Boolean) As SKRect
            Dim width As Single = Math.Max(PivotTableTokens.RowHeaderMinWidthDip * dpi, rect.Width * PivotTableTokens.RowHeaderPreferredRatio)
            width = Math.Min(width, rect.Width * 0.46F)
            If isRtl Then Return New SKRect(rect.Right - width, rect.Top, rect.Right, rect.Bottom)
            Return New SKRect(rect.Left, rect.Top, rect.Left + width, rect.Bottom)
        End Function

        Private Function GetTotalColumnRect(rect As SKRect, rowHeaderRect As SKRect, dpi As Single, isRtl As Boolean) As SKRect
            Dim width As Single = Math.Min(PivotTableTokens.TotalColumnWidthDip * dpi, rect.Width * 0.18F)
            If isRtl Then
                Return New SKRect(rect.Left, rect.Top, rect.Left + width, rect.Bottom)
            End If
            Return New SKRect(rect.Right - width, rect.Top, rect.Right, rect.Bottom)
        End Function

        Private Function GetVisibleValueColumnRects(rect As SKRect,
                                                    rowHeaderRect As SKRect,
                                                    totalRect As SKRect,
                                                    dpi As Single,
                                                    isRtl As Boolean,
                                                    maxVisibleColumns As Integer) As List(Of SKRect)
            Dim result As New List(Of SKRect)()
            Dim left As Single = If(isRtl, totalRect.Right, rowHeaderRect.Right)
            Dim right As Single = If(isRtl, rowHeaderRect.Left, totalRect.Left)
            Dim available As Single = Math.Max(1.0F, right - left)
            Dim minValueColumnWidth As Single = Math.Max(76.0F * dpi, 1.0F)
            Dim maxColumnsFromSpace As Integer = Math.Max(1, CInt(Math.Floor(available / minValueColumnWidth)))
            _columnViewportCapacity = Math.Max(1, Math.Min(Math.Max(1, maxVisibleColumns), maxColumnsFromSpace))
            Dim maxLeft As Integer = Math.Max(0, _columns.Count - _columnViewportCapacity)
            _leftColumnIndex = Math.Max(0, Math.Min(_leftColumnIndex, maxLeft))
            Dim visibleCount As Integer = Math.Min(_columnViewportCapacity, Math.Max(0, _columns.Count - _leftColumnIndex))
            If visibleCount <= 0 Then Return result
            Dim width As Single = available / CSng(visibleCount)
            For i As Integer = 0 To visibleCount - 1
                If isRtl Then
                    Dim cellRight As Single = right - CSng(i) * width
                    result.Add(New SKRect(cellRight - width, rect.Top, cellRight, rect.Bottom))
                Else
                    Dim cellLeft As Single = left + CSng(i) * width
                    result.Add(New SKRect(cellLeft, rect.Top, cellLeft + width, rect.Bottom))
                End If
            Next
            Return result
        End Function

        Private Function HitTestCell(point As SKPoint) As PivotCellHit
            For Each hit As PivotCellHit In _cellHits
                If hit.Rect.Contains(point) Then Return hit
            Next
            Return Nothing
        End Function

        Private Function HasScrollableRowViewport() As Boolean
            Return _rows.Count > Math.Max(1, _rowViewportCapacity)
        End Function

        Private Function ResolveRowViewportMaxTop() As Integer
            Return Math.Max(0, _rows.Count - Math.Max(1, _rowViewportCapacity))
        End Function

        Private Function CanScrollRowViewport(delta As Integer) As Boolean
            If Not HasScrollableRowViewport() Then Return False
            Dim maxTop As Integer = ResolveRowViewportMaxTop()
            If delta < 0 Then Return _topRowIndex < maxTop
            If delta > 0 Then Return _topRowIndex > 0
            Return False
        End Function

        Private Sub MoveSelectionBy(rowDelta As Integer, columnDelta As Integer)
            EnsureSelectionExists()
            Dim rowIndex As Integer = GetSelectedRowIndex()
            Dim columnIndex As Integer = GetSelectedColumnIndex()
            SetSelection(rowIndex + rowDelta, columnIndex + columnDelta, True)
        End Sub

        Private Sub SetSelection(rowIndex As Integer,
                                 columnIndex As Integer,
                                 shouldRaiseSelectionEvent As Boolean)
            Dim normalizedRow As Integer = MASPivotTablePolicy.ClampIndex(rowIndex, _rows.Count)
            Dim normalizedColumn As Integer = MASPivotTablePolicy.ClampIndex(columnIndex, _columns.Count)
            If normalizedRow < 0 OrElse normalizedColumn < 0 Then
                StopSelectionMotion()
                _selectedRowKey = String.Empty
                _selectedColumnKey = String.Empty
                Return
            End If
            Dim newRowKey As String = _rows(normalizedRow).Key
            Dim newColumnKey As String = _columns(normalizedColumn).Key
            Dim previousRowKey As String = _selectedRowKey
            Dim previousColumnKey As String = _selectedColumnKey
            Dim changed As Boolean = Not String.Equals(previousRowKey, newRowKey, StringComparison.Ordinal) OrElse Not String.Equals(previousColumnKey, newColumnKey, StringComparison.Ordinal)
            _selectedRowKey = newRowKey
            _selectedColumnKey = newColumnKey
            _topRowIndex = MASPivotTablePolicy.EnsureVisibleIndex(normalizedRow, _topRowIndex, _rows.Count, Math.Max(1, _rowViewportCapacity))
            _leftColumnIndex = MASPivotTablePolicy.EnsureVisibleIndex(normalizedColumn, _leftColumnIndex, _columns.Count, Math.Max(1, _columnViewportCapacity))
            If changed Then StartSelectionMotion(previousRowKey, previousColumnKey, newRowKey, newColumnKey)
            InvalidateVisual()
            If changed AndAlso shouldRaiseSelectionEvent Then RaiseSelectedCellChangedSafe()
        End Sub

        Private Sub EnsureSelectionExists()
            If _rows.Count = 0 OrElse _columns.Count = 0 Then
                _selectedRowKey = String.Empty
                _selectedColumnKey = String.Empty
                Return
            End If
            If FindRow(_selectedRowKey) Is Nothing OrElse FindColumn(_selectedColumnKey) Is Nothing Then
                SetSelection(0, 0, False)
            End If
        End Sub

        Private Sub NormalizeViewState()
            EnsureSelectionExists()
            _topRowIndex = MASPivotTablePolicy.EnsureVisibleIndex(GetSelectedRowIndex(), _topRowIndex, _rows.Count, Math.Max(1, _rowViewportCapacity))
            _leftColumnIndex = MASPivotTablePolicy.EnsureVisibleIndex(GetSelectedColumnIndex(), _leftColumnIndex, _columns.Count, Math.Max(1, _columnViewportCapacity))
        End Sub

        Private Function GetSelectedRowIndex() As Integer
            Dim index As Integer = -1
            If _rowIndexByKey.TryGetValue(_selectedRowKey, index) Then Return index
            Return -1
        End Function

        Private Function GetSelectedColumnIndex() As Integer
            Dim index As Integer = -1
            If _columnIndexByKey.TryGetValue(_selectedColumnKey, index) Then Return index
            Return -1
        End Function

#End Region

    End Class

End Namespace
