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

namespace iStatVball3;

using Side = RecordCourt.Side;
using Row = RecordCourt.Row;

/*
 * Provides static utility methods for working with court tap regions.
 */ 
public static class Court
{
	/* Constants */

	// Court tap regions
	public enum Region
	{
		Unknown,
		FrontRowA,
		FrontRowB,
		BackRowA,
		BackRowB,
		ServiceA,
		ServiceB,
		OutA,
		OutB,
		Net,
		Antennae,
		BlockZone,
		OutZone
	};

	/* Methods */

	// Determines if specified region is on Side A of the court
	public static bool SideA( Region region )
	{
		return region switch
		{
			Region.BackRowA or 
			Region.FrontRowA or 
			Region.ServiceA or 
			Region.OutA => true,
			
			_ => false
		};
	}

	// Determines if specified region is on Side B of the court
	public static bool SideB( Region region )
	{
		return region switch
		{
			Region.BackRowB or 
			Region.FrontRowB or 
			Region.ServiceB or 
			Region.OutB => true,
			
			_ => false
		};
	}

	// Determines if specified region is anywhere in-bounds on Court A
	public static bool CourtA( Region region )
	{
		return region switch
		{
			Region.BackRowA or 
			Region.FrontRowA => true,
			
			_ => false
		};
	}

	// Determines if specified region is anywhere in-bounds on Court B
	public static bool CourtB( Region region )
	{
		return region switch
		{
			Region.BackRowB or 
			Region.FrontRowB => true,
			
			_ => false
		};
	}

	// Determines if region is on same side of court as specified side
	public static bool SameSide( Side side, Region region )
	{
		return (side == Side.SideA) ? SideA( region ) : SideB( region );
	}

	// Determines if region is service area on same side of court
	public static bool SameServiceArea( Side side, Region region )
	{
		// Side A
		if ( side == Side.SideA )
		{
			return region switch
			{
				Region.ServiceA => true,
				
				_ => false
			};
		}

		// Side B
		return region switch
		{
			Region.ServiceB => true,
			
			_ => false
		};
	}

	// Determines if region is in-bounds opposite side of court
	public static bool OppositeCourt( Side side, Region region )
	{
		// Side A
		if ( side == Side.SideA )
		{
			return region switch
			{
				Region.FrontRowB or 
				Region.BackRowB => true,
				
				_ => false
			};
		}

		// Side B
		return region switch
		{
			Region.FrontRowA or 
			Region.BackRowA => true,
			
			_ => false
		};
	}

	// Determines if region is out-of-bounds on opposite side of court
	public static bool OppositeOut( Side side, Region region )
	{
		// Side A
		if ( side == Side.SideA )
		{
			return region switch
			{
				Region.OutB or 
				Region.ServiceB => true,
				
				_ => false
			};
		}

		// Side B
		return region switch
		{
			Region.OutA or 
			Region.ServiceA => true,
			
			_ => false
		};
	}

	// Determines if region is current block zone (switches during rally)
	public static bool BlockZone( Region region )
	{
		return (region == Region.BlockZone);
	}

	// Determines if region is current out zone (switches during rally)
	public static bool OutZone( Region region )
	{
		return (region == Region.OutZone);
	}

	// Determines whether specified region is front or back row on court
	public static Row CourtRow( Region region )
	{
		return region switch
		{
			// Backrow
			Region.BackRowA or 
			Region.BackRowB => Row.Backrow,
			
			// Frontrow
			Region.FrontRowA or 
			Region.FrontRowB => Row.Frontrow,
				
			_ => Row.Unknown
		};
	}

	// Converts normalized X,Y position to court zone (1-6, 0 if out)
	public static byte CourtZone( double normX, double normY )
	{
		// Court A
		if ( normX is >= 0.0 and < 0.5 )
		{
			// Backrow (5-6-1)
			if ( normX < 0.33 )
			{
				if ( normY >= 0.0 )
				{
					if ( normY < 0.33 ) return 5;
					if ( normY < 0.67 ) return 6;
					if ( normY <= 1.0 ) return 1;
				}
			}
			// Frontrow (4-3-2)
			else
			{
				if ( normY >= 0.0 )
				{
					if ( normY < 0.33 ) return 4;
					if ( normY < 0.67 ) return 3;
					if ( normY <= 1.0 ) return 2;
				}
			}
		}
		// Court B
		else if ( normX is > 0.5 and <= 1.0 )
		{
			// Frontrow (2-3-4)
			if ( normX < 0.67 )
			{
				if ( normY >= 0.0 )
				{
					if ( normY < 0.33 ) return 2;
					if ( normY < 0.67 ) return 3;
					if ( normY <= 1.0 ) return 4;
				}
			}
			// Backrow (1-6-5)
			else
			{
				if ( normY >= 0.0 )
				{
					if ( normY < 0.33 ) return 1;
					if ( normY < 0.67 ) return 6;
					if ( normY <= 1.0 ) return 5;
				}
			}
		}

		// Out-of-bounds
		return 0;
	}

	// Converts normalized X,Y position to court zone (1-6 including out)
	public static byte ExtendedCourtZone( double normX, double normY, Side side )
	{
		// Side A
		if ( normX < 0.5 )
		{
			return ExtendedCourtA( normX, normY );
		}

		// Side B
		if ( normX > 0.5 )
		{
			return ExtendedCourtB( normX, normY );
		}

		// Net/Antenna (0.5)
		return (side == Side.SideA) ? ExtendedCourtA( normY, normY ) : ExtendedCourtB( normX, normY );
	}

	// Converts normalized X,Y position to court zone on side A
	private static byte ExtendedCourtA( double normX, double normY )
	{
		// Backrow (5-6-1)
		if ( normX < 0.33 )
		{
			if ( normY < 0.33 ) return 5;
			if ( normY < 0.67 ) return 6;
			
			return 1;
		}

		// Frontrow (4-3-2)
		if ( normY < 0.33 ) return 4;
		if ( normY < 0.67 ) return 3;
		
		return 2;
	}

	// Converts normalized X,Y position to court zone on side B
	private static byte ExtendedCourtB( double normX, double normY )
	{
		// Frontrow (2-3-4)
		if ( normX < 0.67 )
		{
			if ( normY < 0.33 ) return 2;
			if ( normY < 0.67 ) return 3;
			
			return 4;
		}

		// Backrow (1-6-5)
		if ( normY < 0.33 ) return 1;
		if ( normY < 0.67 ) return 6;
		
		return 5;
	}

	/* Sides */

	// Converts court side LUT key to internal enum constant
	public static Side SideFromKey( string key )
	{
		return (key == RecordCourt.SideAKey) ? Side.SideA : Side.SideB;
	}

	// Converts court side enum constant to LUT key
	public static string KeyFromSide( Side side )
	{
		return (side == Side.SideA) ? RecordCourt.SideAKey : RecordCourt.SideBKey;
	}

	// Returns opposite side of court from specified side
	public static Side SwitchSide( Side side )
	{
		return (side == Side.SideA) ? Side.SideB : Side.SideA;
	}
}

//
