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

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

using DXLib.UI;

using SizeF = Syncfusion.Drawing.SizeF;

namespace iStatVball3;

/*
 * Exports a Shot Chart into a PDF document including both the shot chart and report title.
 */
public class PDFShot
{
	/* Fields */
	private ShotCard shotCard;

	// Calculated draw info
	private float chartWd;
	private float chartHt;

	private float courtSize;
	private float netWd;

	private float courtX, courtX2;
	private float courtY;

	// Required for arrows/circles
	private float size;

	private float radius;
	private float outerRadius;

	private float strokeWd;
	private float arrowLen;
	private float arrowGap;

	private float fullWd;
	private float halfNet;

	/* Methods */

	// Draws title and Shot Chart to PDF page at specified location
	public async Task<float> Draw( PdfDocument document, ShotCard card, float y )
	{
		shotCard = card;

		float localY = y;

		// Use current page
		PdfPage page = document.Pages[ document.PageCount - 1 ];
		SizeF pageSize = page.Graphics.ClientSize;

		chartWd = pageSize.Width;
		chartHt = (chartWd * 0.50f);

		// Start new page if will not fit
		if ( (localY + chartHt) > pageSize.Height )
		{
			page = document.Pages.Add();

			localY = 0;
		}

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

		// Court
		localY = DrawCourt( page, (localY + PDFReport.TitleSpacing), chartWd, chartHt );

		// Circle size relative to canvas
		size = (chartHt * 0.040f);

		// All components relative to circle size
		strokeWd = (size * 0.18f);
		arrowLen = (size * 0.73f);
		arrowGap = (strokeWd * 1.50f);

		radius = (size * 0.50f);
		outerRadius = (radius + (strokeWd * 1.20f));

		// Shot lines
		DrawShots( page );

		return localY;
	}

	// Draws court, net and lines (copied from ShotView)
	private float DrawCourt( PdfPage page, float y, float wd, float ht )
	{
		/* Layout Calculations */

		// Minimum out of bounds area
		float minOutWd = (ht * 0.130f);
		float minOutHt = (ht * 0.100f);

		// Proportional net size
		netWd = (ht * 0.030f);
		halfNet = (netWd * 0.50f);

		// Court size determined by minimum out-of-bounds
		float maxWd = (wd - (minOutWd * 2) - netWd) / 2;
		float maxHt = (ht - (minOutHt * 2));

		courtSize = Math.Min( maxWd, maxHt );
		fullWd = (courtSize + netWd + courtSize);

		// Courts always perfect square
		courtX = (wd - (courtSize * 2) - netWd) / 2;
		courtX2 = (courtX + courtSize + netWd);

		courtY = (y + ((ht - courtSize) / 2));
		float courtY2 = (courtY + courtSize);

		float netX = (courtX + courtSize);
		float netY = courtY;

		float antennaeSize = netWd;

		float frontrowWd = (courtSize / 3);
		float backrowWd = (frontrowWd * 2);

		// Line thickness proportional to court size
		float lineSize = (courtSize * 0.008f);

		// Colors
		PdfColor outerColor = PDFUtils.GetColor( HeatView.OuterColor );
		PdfColor innerColor = PDFUtils.GetColor( HeatView.InnerColor );

		PdfColor lineColor = PDFUtils.GetColor( HeatView.LineColor );
		PdfColor netColor = PDFUtils.GetColor( HeatView.NetColor );

		/* Drawing */

		// Fill outer court area
		PDFUtils.FillRectangle( page, outerColor, 0, y, wd, ht );

		// Fill inner court area
		PDFUtils.FillRectangle( page, innerColor, courtX, courtY, fullWd, courtSize );

		// Draw court lines
		PDFUtils.DrawRectangle( page, lineColor, lineSize, courtX, courtY, fullWd, courtSize );

		// Draw net (no shadow)
		PDFUtils.FillRectangle( page, netColor, netX, netY, netWd, courtSize );

		// Draw antennae (no shadow)
		PDFUtils.FillRectangle( page, netColor, netX, (courtY - antennaeSize), antennaeSize, antennaeSize );
		PDFUtils.FillRectangle( page, netColor, netX, courtY2, antennaeSize, antennaeSize );

		// Draw 10ft lines
		float lineX = (courtX + backrowWd);
		float lineX2 = (courtX2 + frontrowWd);

		PDFUtils.DrawLine( page, lineColor, lineSize, lineX, courtY, lineX, courtY2 );
		PDFUtils.DrawLine( page, lineColor, lineSize, lineX2, courtY, lineX2, courtY2 );

		return (y + ht);
	}

	// Draws all shot arrows/circles onto court
	private void DrawShots( PdfPage page )
	{
		// Calculate data
		List<Stat> shots = shotCard.Chart.FilterShots();

		// Draw each shot
		foreach ( Stat shot in shots )
		{
			DrawShot( page, shot );
		}
	}

	// Draws marker (start, arrow, end) for specified shot
	private void DrawShot( PdfPage page, Stat shot )
	{
		ShotView view = shotCard.View;

		float startX = shot.StartX;
		float startY = shot.StartY;

		float endX = shot.EndX;
		float endY = shot.EndY;

		// Clip left/top
		endX = (float) Math.Max( endX, -0.1 );
		endY = (float) Math.Max( endY, -0.1 );

		// Clip right/bottom
		endX = (float) Math.Min( endX, 1.1 );
		endY = (float) Math.Min( endY, 1.1 );

		PointF normStart;
		PointF normEnd;

		bool startA = (startX < 0.5);

		// Team 1 always left-to-right, Team 2 always right-to-left
		bool team1 = shotCard.IsTeam1;

		// Already correct side
		if ( (startA && team1) || (!startA && !team1) )
		{
			normStart = new PointF( startX, startY );
			normEnd = new PointF( endX, endY );
		}
		// Normalize 
		else
		{
			bool endA = (endX < 0.5);

			Point startPt = RecordCourt.NormalizeSide( startX, startY, (team1 ? RecordCourt.Side.SideA : RecordCourt.Side.SideB) );
			Point endPt = RecordCourt.NormalizeSide( endX, endY, (endA ? RecordCourt.Side.SideB : RecordCourt.Side.SideA) );

			normStart = new PointF( (float)startPt.X, (float)startPt.Y );
			normEnd = new PointF( (float)endPt.X, (float)endPt.Y );
		}

		// Start location
		float x1 = (courtX + (normStart.X * fullWd));
		float y1 = (courtY + (normStart.Y * courtSize));

		// Account for net
		if ( startX > 0.5 )
		{
			x1 += netWd;
		}
		else if ( !(startX < 0.5) )
		{
			x1 += halfNet;
		}

		// End location			
		float x2 = (courtX + (normEnd.X * fullWd));
		float y2 = (courtY + (normEnd.Y * courtSize));

		// Account for net
		if ( endX > 0.5 )
		{
			x2 += netWd;
		}
		else if ( !(endX < 0.5) )
		{
			x2 += halfNet;
		}

		// Line/outer color
		PdfColor color = GetColor( shot, ShotView.ColorMode.Normal );

		// Start circle
		if ( view.ShowStart )
		{
			// Outer stroke
			PDFUtils.FillCircle( page, color, x1, y1, outerRadius );

			PdfColor innerColor = GetColor( shot, ShotView.ColorMode.Dark );

			// Dark inside
			PDFUtils.FillCircle( page, innerColor, x1, y1, radius );
		}

		// Arrow
		if ( view.ShowArrow )
		{
			PDFUtils.DrawArrow( page, color, strokeWd, x1, y1, x2, y2, arrowLen, radius, radius, arrowGap, 0 );
		}

		// End circle
		if ( view.ShowEnd )
		{
			// Outer stroke
			PDFUtils.FillCircle( page, color, x2, y2, outerRadius );

			PdfColor innerColor = GetColor( shot, ShotView.ColorMode.Light );

			// Light inside
			PDFUtils.FillCircle( page, innerColor, x2, y2, radius );
		}
	}

	// Returns PDF color for specified shot component
	private PdfColor GetColor( Stat shot, ShotView.ColorMode colorMode )
	{
		return PDFUtils.GetColor( shotCard.View.GetColor( shot, colorMode ) );
	}
}

//
