/* 
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information 
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC. 
 */

using Syncfusion.Maui.DataGrid;
using Syncfusion.Maui.DataGrid.Exporting;

using Syncfusion.Pdf;
using Syncfusion.Pdf.Grid;
using Syncfusion.Pdf.Graphics;

using DXLib.UI;

using SizeF = Syncfusion.Drawing.SizeF;
using PointF = Syncfusion.Drawing.PointF; 

namespace iStatVball3;

/*
 * Exports a data grid into a PDF document including both the grid and grid title. PDF configuration occurs via external JSON.
 */
public class PDFGrid
{
    /* Fields */
    private PdfPage page;

    // Cached fonts
    private PdfFont regularFont;
    private PdfFont boldFont;

    // Syncfusion grid
    private Grid grid;

    // Configuration
    private JsonGridPdf json;

    /* Methods */
    public PDFGrid()
    {}

    // Post construction initialization
    public async Task Init()
    {
        // Cache fonts
        regularFont = await PDFUtils.GetFont( PDFUtils.RegularFont, 8 );
        boldFont = await PDFUtils.GetFont( PDFUtils.BoldFont, 8 );
    }

    // Draws title and grid to PDF page at specified location
    public async Task<float> Draw( PdfDocument document, GridCard card, float y )
    {
        grid = card.Grid;
        json = grid.Json.PDF ?? new JsonGridPdf();

		// First page set here
		page ??= document.Pages[ document.PageCount - 1 ];

        float localY = y;
        SizeF size = page.GetClientSize();

        // Start new page if title will not fit
        if ( (localY + PDFReport.TitleHt) > size.Height )
        {
            page = document.Pages.Add();
            localY = 0;
        }

        // Listen for pagination
        document.Pages.PageAdded += OnPageAdded;

        // Grid title
        localY = await PDFUtils.DrawText( page, card.Title, PDFUtils.BoldFont, 12, PDFUtils.GetColor( DXColors.Dark1 ), 0, localY );

        DataGridPdfExportingController exporter = new();

        // Register for export events
        exporter.RowExporting += OnRowExporting;
        exporter.CellExporting += OnCellExporting;

        // Configure styling
        DataGridPdfExportingOption options = new()
        {
            StartPageIndex = 1,
            CanRepeatHeaders = true,
            CanApplyGridStyle = true,
            GridLineType = GridLineType.Both,

            // Force to full page width?
            CanFitAllColumnsInOnePage = json.FullWidth,

            CanExportAllPages = true,
            CanExportStackedHeaders = true,
            CanExportUnboundRows = true,
            CanExportRowHeight = true,

            // 0 = use grid column widths
            CanExportColumnWidth = (json.ColumnWidth == 0),
            
            PdfDocument = document
        };

        // Column width if not forced full width
        if ( json.ColumnWidth > 0 )
        {
            options.DefaultColumnWidth = json.ColumnWidth;
        }

        PdfGrid pdfGrid = exporter.ExportToPdfGrid( grid, grid.View!, options, document );

        // Some grids require tighter cell padding
        float pad = json.LessPad ? 2 : 5;

        // Configure layout
        pdfGrid.Style = new PdfGridStyle
        {
            CellPadding = new PdfPaddings( pad, pad, 1, 1 ),
            CellSpacing = 0
        };
        
        // Configure pagination
        PdfGridLayoutFormat format = new()
        {
            Break = PdfLayoutBreakType.FitColumnsToPage,
            Layout = PdfLayoutType.Paginate
        };

        int index = json.FixedIndex;

        // Fixed width column defined via JSON
        if ( index >= 0 )
        {
            pdfGrid.Columns[ index ].Width = json.FixedWidth;
        }

        // Highlighted column wider
        if ( json.HighlightLast )
        {
            int last = (pdfGrid.Columns.Count - 1);

            pdfGrid.Columns[ last ].Width = 75;
        }

        localY += PDFReport.TitleSpacing;

        // Draw
        PdfLayoutResult result = pdfGrid.Draw( page, new PointF( 1, localY ), format );

        document.Pages.PageAdded -= OnPageAdded;

        return result.Bounds.Bottom;
    }

    /* Event Callbacks */

    // Required for correct pagination
    private void OnPageAdded( object sender, PageAddedEventArgs args )
    {
        page = args.Page;
    }

    // Applies alternating row colors
    private void OnRowExporting( object sender, DataGridRowPdfExportingEventArgs args )
    {
        if ( args.RowType == ExportRowType.RecordRow )
        {
            int? index = grid.View?.Records.IndexOf( args.Record );

            // Choose alternating color
            Color color = ((index == null) || ((index % 2) == 0)) ? DXColors.Light4 : DXColors.Light2;
            
            // Apply to row
            args.PdfRow.Style.BackgroundBrush = new PdfSolidBrush( PDFUtils.GetColor( color ) );
        }   
	}

    // Applies custom styling at the cellular level
    private void OnCellExporting( object sender, DataGridCellPdfExportingEventArgs args )
    {
        PdfGridCellStyle style = args.PdfGridCell.Style;
        string key = args.ColumnName;

        switch ( args.CellType )
        {
            // Header cells bold
            case ExportCellType.StackedHeaderCell:
            case ExportCellType.HeaderCell:
            {
                style.Font = boldFont;
                break;
            }
            // Regular cells
            case ExportCellType.RecordCell:
            {
                // Optionally highlight last column
                if ( json.HighlightLast )
                {
                    ColumnCollection columns = grid.Columns;
                    int index = columns.IndexOf( columns.LastOrDefault() );

                    DataGridColumn column = columns[ index ];
                    bool lastCol = (column.MappingName == key);

                    // Change background color
                    if ( lastCol )
                    {
                        style.BackgroundBrush = PDFUtils.GetBrush( DXColors.Accent2 );
                    }

                    // Change font
                    style.Font = lastCol ? boldFont : regularFont;
                }
                // Normal
                else
                {
                    style.Font = regularFont;
                }

                break;
            }
            // Totals row
            case ExportCellType.FixedBottomUnboundCell:
            {
                // Bold
                style.Font = boldFont;

                JsonColumn column = grid.Json.GetColumn( key );

                if ( column != null )
                {
                    string type = column.Type;
                    string value = args.CellValue.ToString();

                    if ( value != null )
                    {
                        // Must manually set format for totals cells
                        switch ( type )
                        {
                            // '1,000'
                            case AnalyzeKeys.IntKey:
                            {
                                args.CellValue = float.Parse( value ).ToString( "N0" );
                                break;
                            }
                            // '5.0', '0.300', '35.0%'
                            case AnalyzeKeys.FloatKey:
                            case AnalyzeKeys.FixedKey:
                            case AnalyzeKeys.PercentKey:
                            {
                                string format = Grid.GetNumericFormat( column.Type );

                                args.CellValue = float.Parse( value ).ToString( format );
                                break;
                            }
                        }
                    }
                }

                break;
            }
        }
    }
}

//
