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

namespace iStatVball3;

/*
 * Special component of the WHP algorithm used to seed the score list when WHP prediction confidence is low. Seeding is
 * based on action, rotation, court zone, and player position.
 */
public class WHPSeed
{
	/* Constants */

	// Maps player to front/backrow court position
	public enum Position
	{
		Unknown,

		FrontOH,
		FrontMB,
		FrontOPP,
		FrontS,

		BackOH,
		BackMB,
		BackOPP,
		BackS,

		Libero,
		DefSpec
	};

	/* Fields */

	// Singleton instance
	private static WHPSeed instance;

	/* Methods */
	private WHPSeed()
	{}

	// Returns singleton instance
	public static WHPSeed GetInstance()
	{
		// Lazily create
		return instance ??= new WHPSeed();
	}

	// Maps player to front/backrow court position
	public static Position GetPosition( LineupEntry entry )
	{
		// Libero (always backrow)
		if ( entry.IsLibero )
		{
			return Position.Libero;
		}
			
		// Defensive Specialist
		if ( entry.Position == Lineup.SpecialistKey )
		{
			return Position.DefSpec;
		}
			
		// Frontrow OH/MB/OPP/S
		if ( entry.IsFrontRow )
		{
			switch ( entry.Position )
			{
				case Lineup.OutsideKey: return Position.FrontOH;
				case Lineup.MiddleKey: return Position.FrontMB;
				case Lineup.OppositeKey: return Position.FrontOPP;
				case Lineup.SetterKey: return Position.FrontS;
			}
		}
		// Backrow OH/MB/OPP/S
		else
		{
			switch ( entry.Position )
			{
				case Lineup.OutsideKey: return Position.BackOH;
				case Lineup.MiddleKey: return Position.BackMB;
				case Lineup.OppositeKey: return Position.BackOPP;
				case Lineup.SetterKey: return Position.BackS;
			}
		}

		return Position.Unknown;
	}

	/* LUT */

	// Looks-up static seed value for given configuration
	public static double GetSeed( string action, int zone, Position position, bool libLB )
	{
		switch ( action )
		{
			// Serve receive
			case Stats.ReceiveKey:
			{
				switch ( zone )
				{
					// Right-back
					case 1:
					{
						return position switch
						{
							Position.Libero => 1.00,
							Position.BackOH => 0.90,
							Position.DefSpec => 0.90,
							Position.BackOPP => 0.70,
							Position.FrontOH => 0.60,
							Position.FrontOPP => 0.40,
							Position.BackMB => 0.30,
							Position.FrontMB => 0.20,
							Position.FrontS => 0.10,
							Position.BackS => 0.10,
							Position.Unknown => 0.0,
							
							_ => 0.0
						};
					}
					// Right-front
					case 2:
					{
						return position switch
						{
							Position.FrontS => 1.00,
							Position.Libero => 0.80,
							Position.DefSpec => 0.80,
							Position.FrontOH => 0.70,
							Position.BackOH => 0.70,
							Position.FrontOPP => 0.60,
							Position.BackOPP => 0.60,
							Position.FrontMB => 0.30,
							Position.BackMB => 0.30,
							Position.BackS => 0.10,
							Position.Unknown => 0.0,
							
							_ => 0.0
						};
					}
					// Middle-front
					case 3:
					{
						return position switch
						{
							Position.FrontMB => 0.90,
							Position.Libero => 0.80,
							Position.DefSpec => 0.80,
							Position.BackOH => 0.80,
							Position.FrontOH => 0.60,
							Position.FrontOPP => 0.60,
							Position.BackOPP => 0.60,
							Position.BackMB => 0.20,
							Position.FrontS => 0.10,
							Position.BackS => 0.10,
							Position.Unknown => 0.0,
							
							_ => 0.0
						};
					}
					// Left-front
					case 4:
					{
						return position switch
						{
							Position.FrontOH => 0.90,
							Position.Libero => 0.80,
							Position.DefSpec => 0.80,
							Position.BackOH => 0.70,
							Position.BackOPP => 0.70,
							Position.FrontOPP => 0.50,
							Position.FrontMB => 0.30,
							Position.BackMB => 0.20,
							Position.FrontS => 0.10,
							Position.BackS => 0.10,
							Position.Unknown => 0.0,
							
							_ => 0.0
						};
					}
					// Left-back
					case 5:
					{
						return position switch
						{
							Position.Libero => 1.00,
							Position.DefSpec => 0.90,
							Position.FrontOH => 0.90,
							Position.BackOH => 0.80,
							Position.BackOPP => 0.70,
							Position.FrontOPP => 0.60,
							Position.BackMB => 0.30,
							Position.FrontMB => 0.20,
							Position.FrontS => 0.10,
							Position.BackS => 0.10,
							Position.Unknown => 0.0,
							
							_ => 0.0
						};
					}
					// Middle-back
					case 6:
					{
						return position switch
						{
							Position.Libero => 1.00,
							Position.DefSpec => 0.90,
							Position.BackOH => 0.90,
							Position.FrontOH => 0.80,
							Position.BackOPP => 0.60,
							Position.FrontOPP => 0.50,
							Position.BackMB => 0.20,
							Position.FrontMB => 0.20,
							Position.FrontS => 0.10,
							Position.BackS => 0.10,
							Position.Unknown => 0.0,
							
							_ => 0.0,
						};
					}
				}

				break;
			}
			// Second ball (set/attack)
			case Stats.SecondKey:
			{
				switch ( zone )
				{
					// Right-back
					case 1:
					{
						return position switch
						{
							Position.BackS => 1.00,
							Position.FrontS => 0.90,
							Position.BackOPP => 0.60,
							Position.FrontOPP => 0.60,
							Position.Libero => 0.50,
							Position.DefSpec => 0.50,
							Position.BackOH => 0.20,
							Position.BackMB => 0.20,
							Position.FrontMB => 0.10,
							Position.FrontOH => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Right-front
					case 2:
					{
						return position switch
						{
							Position.FrontS => 1.00,
							Position.BackS => 1.00,
							Position.FrontOPP => 0.50,
							Position.BackOPP => 0.50,
							Position.DefSpec => 0.40,
							Position.FrontMB => 0.40,
							Position.BackOH => 0.30,
							Position.BackMB => 0.20,
							Position.FrontOH => 0.20,
							Position.Libero => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Middle-front
					case 3:
					{
						return position switch
						{
							Position.FrontS => 1.00,
							Position.BackS => 1.00,
							Position.FrontOPP => 0.50,
							Position.BackOPP => 0.50,
							Position.DefSpec => 0.40,
							Position.Libero => 0.40,
							Position.FrontMB => 0.30,
							Position.FrontOH => 0.30,
							Position.BackOH => 0.20,
							Position.BackMB => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Left-front
					case 4:
					{
						return position switch
						{
							Position.FrontOH => 0.90,
							Position.FrontS => 0.80,
							Position.BackS => 0.80,
							Position.Libero => 0.50,
							Position.FrontOPP => 0.40,
							Position.DefSpec => 0.40,
							Position.BackOPP => 0.30,
							Position.FrontMB => 0.30,
							Position.BackOH => 0.30,
							Position.BackMB => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Left-back
					case 5:
					{
						return position switch
						{
							Position.Libero => 0.90,
							Position.BackS => 0.80,
							Position.FrontS => 0.80,
							Position.DefSpec => 0.50,
							Position.BackOH => 0.50,
							Position.FrontOH => 0.30,
							Position.BackMB => 0.30,
							Position.FrontMB => 0.20,
							Position.BackOPP => 0.10,
							Position.FrontOPP => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Middle-back
					case 6:
					{
						return position switch
						{
							Position.BackS => 0.90,
							Position.FrontS => 0.90,
							Position.Libero => 0.60,
							Position.DefSpec => 0.60,
							Position.BackOH => 0.50,
							Position.BackOPP => 0.40,
							Position.FrontOPP => 0.30,
							Position.BackMB => 0.20,
							Position.FrontMB => 0.10,
							Position.FrontOH => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
				}

				break;
			}
			// Third ball (attack/free), Block/Over
			case Stats.ThirdKey:
			case Stats.BlockKey:
			case Stats.OverpassKey:
			{
				switch ( zone )
				{
					// Right-back
					case 1:
					{
						return position switch
						{
							Position.BackOPP => 1.00,
							Position.BackOH => 0.75,
							Position.BackMB => 0.50,
							Position.BackS => 0.40,
							Position.FrontOPP => 0.30,
							Position.FrontS => 0.25,
							Position.FrontMB => 0.20,
							Position.FrontOH => 0.10,
							Position.DefSpec => 0.10,
							Position.Libero => 0.05,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Right-front
					case 2:
					{
						return position switch
						{
							Position.FrontOPP => 0.90,
							Position.FrontS => 0.80,
							Position.FrontOH => 0.50,
							Position.FrontMB => 0.40,
							Position.BackOPP => 0.20,
							Position.BackS => 0.10,
							Position.BackOH => 0.10,
							Position.BackMB => 0.05,
							Position.DefSpec => 0.05,
							Position.Libero => 0.00,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Middle-front
					case 3:
					{
						return position switch
						{
							Position.FrontMB => 1.00,
							Position.FrontOPP => 0.30,
							Position.FrontOH => 0.25,
							Position.FrontS => 0.20,
							Position.BackOH => 0.10,
							Position.BackMB => 0.05,
							Position.BackOPP => 0.05,
							Position.BackS => 0.05,
							Position.DefSpec => 0.05,
							Position.Libero => 0.00,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Left-front
					case 4:
					{
						return position switch
						{
							Position.FrontOH => 0.90,
							Position.FrontOPP => 0.50,
							Position.FrontMB => 0.40,
							Position.FrontS => 0.10,
							Position.BackOH => 0.05,
							Position.BackMB => 0.05,
							Position.DefSpec => 0.05,
							Position.BackOPP => 0.05,
							Position.BackS => 0.05,
							Position.Libero => 0.00,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}	
					// Left-back
					case 5:
					{
						return position switch
						{
							Position.BackMB => 0.70,
							Position.BackOH => 0.70,
							Position.Libero => 0.60,
							Position.FrontOH => 0.50,
							Position.FrontOPP => 0.50,
							Position.FrontMB => 0.30,
							Position.FrontS => 0.10,
							Position.DefSpec => 0.10,
							Position.BackOPP => 0.05,
							Position.BackS => 0.05,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Middle-back
					case 6:
					{
						return position switch
						{
							Position.BackOH => 0.90,
							Position.BackMB => 0.75,
							Position.BackOPP => 0.50,
							Position.FrontMB => 0.40,
							Position.Libero => 0.40,
							Position.BackS => 0.30,
							Position.DefSpec => 0.20,
							Position.FrontOH => 0.10,
							Position.FrontOPP => 0.10,
							Position.FrontS => 0.05,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
				}

				break;
			}
			// Defense/Putback
			case Stats.DefenseKey:
			case Stats.PutbackKey:
			{
				switch ( zone )
				{
					// Right-back
					case 1:
					{
						return position switch
						{
							Position.BackS => 1.00,
							Position.BackOPP => 1.00,
							Position.DefSpec => 0.80,
							Position.FrontOPP => 0.60,
							Position.BackOH => 0.40,
							Position.BackMB => 0.40,
							Position.Libero => 0.40,
							Position.FrontS => 0.30,
							Position.FrontMB => 0.20,
							Position.FrontOH => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Right-front
					case 2:
					{
						return position switch
						{
							Position.FrontOPP => 0.80,
							Position.FrontS => 0.80,
							Position.FrontMB => 0.40,
							Position.FrontOH => 0.30,
							Position.BackOPP => 0.30,
							Position.BackS => 0.30,
							Position.DefSpec => 0.30,
							Position.BackOH => 0.20,
							Position.Libero => 0.10,
							Position.BackMB => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Middle-front
					case 3:
					{
						return position switch
						{
							Position.FrontMB => 1.00,
							Position.FrontOH => 0.60,
							Position.FrontOPP => 0.60,
							Position.FrontS => 0.50,
							Position.BackOH => 0.40,
							Position.Libero => 0.30,
							Position.BackMB => 0.30,
							Position.BackS => 0.20,
							Position.BackOPP => 0.20,
							Position.DefSpec => 0.20,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Left-front
					case 4:
					{
						return position switch
						{
							Position.FrontOH => 0.80,
							Position.FrontMB => 0.40,
							Position.Libero => 0.40,
							Position.BackMB => 0.40,
							Position.FrontOPP => 0.30,
							Position.FrontS => 0.30,
							Position.BackOH => 0.20,
							Position.DefSpec => 0.20,
							Position.BackS => 0.10,
							Position.BackOPP => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Left-back
					case 5:
					{
						return position switch
						{
							Position.Libero => libLB ? 1.00 : 0.70,
							Position.BackMB => libLB ? 1.00 : 0.70,
							Position.BackOH => libLB ? 0.70 : 1.00,
							Position.DefSpec => libLB ? 0.70 : 1.00,
							Position.FrontOH => 0.40,
							Position.FrontMB => 0.30,
							Position.FrontOPP => 0.20,
							Position.FrontS => 0.10,
							Position.BackS => 0.10,
							Position.BackOPP => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Middle-back
					case 6:
					{
						return position switch
						{
							Position.BackOH => libLB ? 1.00 : 0.70,
							Position.DefSpec => libLB ? 1.00 : 0.70,
							Position.Libero => libLB ? 0.70 : 1.00,
							Position.BackMB => libLB ? 0.70 : 1.00,
							Position.BackS => 0.50,
							Position.BackOPP => 0.50,
							Position.FrontMB => 0.40,
							Position.FrontOPP => 0.20,
							Position.FrontS => 0.20,
							Position.FrontOH => 0.20,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
				}

				break;
			}
			// First/Free
			case Stats.FirstKey:
			case Stats.FreeballKey:
			{
				switch ( zone )
				{
					// Right-back
					case 1:
					{
						return position switch
						{
							Position.BackOPP => 1.00,
							Position.BackOH => 0.75,
							Position.DefSpec => 0.75,
							Position.BackS => 0.60,
							Position.BackMB => 0.50,
							Position.Libero => 0.50,
							Position.FrontOPP => 0.40,
							Position.FrontS => 0.20,
							Position.FrontMB => 0.10,
							Position.FrontOH => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Right-front
					case 2:
					{
						return position switch
						{
							Position.FrontOPP => 1.00,
							Position.FrontOH => 0.60,
							Position.FrontS => 0.60,
							Position.FrontMB => 0.50,
							Position.BackOPP => 0.40,
							Position.BackOH => 0.40,
							Position.Libero => 0.30,
							Position.DefSpec => 0.30,
							Position.BackS => 0.20,
							Position.BackMB => 0.20,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Middle-front
					case 3:
					{
						return position switch
						{
							Position.FrontMB => 1.00,
							Position.FrontOPP => 0.90,
							Position.FrontOH => 0.75,
							Position.FrontS => 0.75,
							Position.Libero => 0.50,
							Position.DefSpec => 0.50,
							Position.BackOH => 0.40,
							Position.BackOPP => 0.30,
							Position.BackMB => 0.30,
							Position.BackS => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Left-front
					case 4:
					{
						return position switch
						{
							Position.FrontOH => 1.00,
							Position.Libero => 0.90,
							Position.FrontMB => 0.60,
							Position.FrontOPP => 0.50,
							Position.DefSpec => 0.40,
							Position.BackMB => 0.30,
							Position.BackOH => 0.30,
							Position.FrontS => 0.20,
							Position.BackOPP => 0.10,
							Position.BackS => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Left-back
					case 5:
					{
						return position switch
						{
							Position.Libero => libLB ? 1.00 : 0.70,
							Position.BackMB => libLB ? 1.00 : 0.70,
							Position.BackOH => libLB ? 0.70 : 1.00,
							Position.DefSpec => libLB ? 0.70 : 1.00,
							Position.FrontOH => 0.50,
							Position.FrontOPP => 0.40,
							Position.BackOPP => 0.30,
							Position.FrontMB => 0.20,
							Position.FrontS => 0.10,
							Position.BackS => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
					// Middle-back
					case 6:
					{
						return position switch
						{
							Position.BackOH => libLB ? 1.00 : 0.70,
							Position.DefSpec => libLB ? 1.00 : 0.70,
							Position.Libero => libLB ? 0.70 : 1.00,
							Position.BackMB => libLB ? 0.70 : 1.00,
							Position.BackOPP => 0.50,
							Position.FrontMB => 0.30,
							Position.FrontOPP => 0.20,
							Position.FrontOH => 0.20,
							Position.BackS => 0.10,
							Position.FrontS => 0.10,
							Position.Unknown => 0.00,
							
							_ => 0.00
						};
					}
				}

				break;
			}
		}

		return 0.00;
	}

	// Returns static seed based on rotation rather than position
	public static double GetRotationSeed( int zone, int rotZone )
	{
		switch ( rotZone )
		{
			// Right-back
			case 1:
			{
				switch ( zone )
				{
					case 1: return 1.00;
					case 2: return 0.75;
					case 3: return 0.50;
					case 4: return 0.30;
					case 5: return 0.30;
					case 6: return 0.75;
				}

				break;
			}
			// Right-front
			case 2:
			{
				switch ( zone )
				{
					case 1: return 0.75;
					case 2: return 1.00;
					case 3: return 0.50;
					case 4: return 0.30;
					case 5: return 0.30;
					case 6: return 0.50;
				}

				break;
			}
			// Middle-front
			case 3:
			{
				switch ( zone )
				{
					case 1: return 0.30;
					case 2: return 0.50;
					case 3: return 1.00;
					case 4: return 0.50;
					case 5: return 0.30;
					case 6: return 0.50;
				}

				break;
			}
			// Left-front
			case 4:
			{
				switch ( zone )
				{
					case 1: return 0.20;
					case 2: return 0.20;
					case 3: return 0.30;
					case 4: return 1.00;
					case 5: return 0.75;
					case 6: return 0.50;
				}

				break;
			}
			// Left-back
			case 5:
			{
				switch ( zone )
				{
					case 1: return 0.30;
					case 2: return 0.30;
					case 3: return 0.50;
					case 4: return 0.75;
					case 5: return 1.00;
					case 6: return 0.75;
				}

				break;
			}
			// Middle-back
			case 6:
			{
				switch ( zone )
				{
					case 1: return 0.75;
					case 2: return 0.50;
					case 3: return 0.75;
					case 4: return 0.50;
					case 5: return 0.75;
					case 6: return 1.00;
				}

				break;
			}
		}

		return 0.00;
	}
}

//
