Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports System.Text

Namespace Nexamas.UI.DataBinding

    ''' <summary>
    ''' Friend-only deterministic delimited-text writer for MASPivotExportSnapshot.
    ''' It writes to memory only so product controls do not own files, dialogs,
    ''' clipboard, Excel, PDF, or persistence boundaries.
    ''' </summary>
    Friend NotInheritable Class MASPivotDelimitedExportWriter
        Private Sub New()
        End Sub

        Friend Shared Function CreateDelimitedText(snapshot As MASPivotExportSnapshot,
                                                   Optional options As MASPivotDelimitedExportOptions = Nothing) As String
            If options Is Nothing Then options = MASPivotDelimitedExportOptions.CreateDefault()
            If snapshot Is Nothing Then Return String.Empty

            Dim delimiter As Char = options.Delimiter
            Dim builder As New StringBuilder()
            AppendCell(builder, "", delimiter)
            For Each columnKey As String In snapshot.Columns
                builder.Append(delimiter)
                AppendCell(builder, columnKey, delimiter)
            Next
            If options.IncludeRowTotals Then
                builder.Append(delimiter)
                AppendCell(builder, "Row Total", delimiter)
            End If
            builder.AppendLine()

            For Each rowKey As String In snapshot.Rows
                AppendCell(builder, rowKey, delimiter)
                Dim rowTotal As Decimal = 0D
                For Each columnKey As String In snapshot.Columns
                    Dim value As Decimal = FindCellValue(snapshot, rowKey, columnKey)
                    rowTotal += value
                    builder.Append(delimiter)
                    AppendCell(builder, FormatDecimal(value), delimiter)
                Next
                If options.IncludeRowTotals Then
                    builder.Append(delimiter)
                    AppendCell(builder, FormatDecimal(rowTotal), delimiter)
                End If
                builder.AppendLine()
            Next

            If options.IncludeColumnTotals Then
                AppendCell(builder, "Column Total", delimiter)
                For Each columnKey As String In snapshot.Columns
                    Dim columnTotal As Decimal = 0D
                    For Each rowKey As String In snapshot.Rows
                        columnTotal += FindCellValue(snapshot, rowKey, columnKey)
                    Next
                    builder.Append(delimiter)
                    AppendCell(builder, FormatDecimal(columnTotal), delimiter)
                Next
                If options.IncludeRowTotals Then
                    builder.Append(delimiter)
                    AppendCell(builder, FormatDecimal(snapshot.GrandTotal), delimiter)
                End If
                builder.AppendLine()
            End If

            Return builder.ToString()
        End Function

        Private Shared Function FindCellValue(snapshot As MASPivotExportSnapshot,
                                              rowKey As String,
                                              columnKey As String) As Decimal
            For Each cell As MASPivotExportCell In snapshot.Cells
                If cell Is Nothing Then Continue For
                If String.Equals(cell.RowKey, rowKey, StringComparison.Ordinal) AndAlso
                   String.Equals(cell.ColumnKey, columnKey, StringComparison.Ordinal) Then Return cell.Value
            Next
            Return 0D
        End Function

        Private Shared Function FormatDecimal(value As Decimal) As String
            Return value.ToString("0.#############################", CultureInfo.InvariantCulture)
        End Function

        Private Shared Sub AppendCell(builder As StringBuilder,
                                      value As String,
                                      delimiter As Char)
            Dim text As String = If(value, String.Empty)
            Dim quote As Char = ChrW(34)
            Dim mustQuote As Boolean = text.IndexOf(delimiter) >= 0 OrElse text.IndexOf(quote) >= 0 OrElse text.IndexOf(ControlChars.Cr) >= 0 OrElse text.IndexOf(ControlChars.Lf) >= 0
            If Not mustQuote Then
                builder.Append(text)
                Return
            End If
            builder.Append(quote)
            builder.Append(text.Replace(quote.ToString(), quote.ToString() & quote.ToString()))
            builder.Append(quote)
        End Sub
    End Class

End Namespace
