Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Linq

Namespace Nexamas.UI.Visualization

    ''' <summary>
    ''' Immutable chart definition for the initial dashboard/report chart foundation.
    ''' </summary>
    Friend NotInheritable Class MASChartDefinition

        Private ReadOnly _series As IReadOnlyList(Of MASChartSeries)

        Friend Sub New(kind As MASChartKind,
                       title As String,
                       series As IEnumerable(Of MASChartSeries),
                       Optional categoryAxisLabel As String = "",
                       Optional valueAxisLabel As String = "",
                       Optional donutHoleRatio As Double = 0.55R)
            Me.Kind = kind
            Me.Title = MASChartDataPoint.NormalizeText(title)
            Me.CategoryAxisLabel = MASChartDataPoint.NormalizeText(categoryAxisLabel)
            Me.ValueAxisLabel = MASChartDataPoint.NormalizeText(valueAxisLabel)
            Me.DonutHoleRatio = Clamp(donutHoleRatio, 0.2R, 0.85R)
            _series = New ReadOnlyCollection(Of MASChartSeries)(NormalizeSeries(series))
        End Sub

        Friend ReadOnly Property Kind As MASChartKind
        Friend ReadOnly Property Title As String
        Friend ReadOnly Property CategoryAxisLabel As String
        Friend ReadOnly Property ValueAxisLabel As String
        Friend ReadOnly Property DonutHoleRatio As Double

        Friend ReadOnly Property Series As IReadOnlyList(Of MASChartSeries)
            Get
                Return _series
            End Get
        End Property

        Friend ReadOnly Property SeriesCount As Integer
            Get
                Return _series.Count
            End Get
        End Property

        Friend ReadOnly Property DataPointCount As Integer
            Get
                Return _series.Sum(Function(seriesItem) seriesItem.PointCount)
            End Get
        End Property

        Friend ReadOnly Property IsSupportedKind As Boolean
            Get
                Return Kind = MASChartKind.Line OrElse
                       Kind = MASChartKind.Bar OrElse
                       Kind = MASChartKind.Pie OrElse
                       Kind = MASChartKind.Donut OrElse
                       Kind = MASChartKind.Kpi OrElse
                       Kind = MASChartKind.Sparkline
            End Get
        End Property

        Friend ReadOnly Property IsValid As Boolean
            Get
                Return IsSupportedKind AndAlso
                       Title.Length > 0 AndAlso
                       SeriesCount > 0 AndAlso
                       DataPointCount > 0 AndAlso
                       _series.All(Function(seriesItem) seriesItem.IsValid)
            End Get
        End Property

        Friend Shared Function Line(title As String, ParamArray series As MASChartSeries()) As MASChartDefinition
            Return New MASChartDefinition(MASChartKind.Line, title, series)
        End Function

        Friend Shared Function Bar(title As String, ParamArray series As MASChartSeries()) As MASChartDefinition
            Return New MASChartDefinition(MASChartKind.Bar, title, series)
        End Function

        Friend Shared Function Pie(title As String, series As MASChartSeries) As MASChartDefinition
            Return New MASChartDefinition(MASChartKind.Pie, title, New MASChartSeries() {series})
        End Function

        Friend Shared Function Donut(title As String, series As MASChartSeries) As MASChartDefinition
            Return New MASChartDefinition(MASChartKind.Donut, title, New MASChartSeries() {series})
        End Function

        Friend Shared Function Kpi(title As String, series As MASChartSeries) As MASChartDefinition
            Return New MASChartDefinition(MASChartKind.Kpi, title, New MASChartSeries() {series})
        End Function

        Friend Shared Function Sparkline(title As String, series As MASChartSeries) As MASChartDefinition
            Return New MASChartDefinition(MASChartKind.Sparkline, title, New MASChartSeries() {series})
        End Function

        Private Shared Function NormalizeSeries(series As IEnumerable(Of MASChartSeries)) As List(Of MASChartSeries)
            Dim result As New List(Of MASChartSeries)()
            If series Is Nothing Then Return result

            For Each item As MASChartSeries In series
                If item IsNot Nothing Then result.Add(item)
            Next

            Return result
        End Function

        Private Shared Function Clamp(value As Double, minimum As Double, maximum As Double) As Double
            If value < minimum Then Return minimum
            If value > maximum Then Return maximum
            Return value
        End Function

    End Class

End Namespace
