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

using DXLib.UI;
using DXLib.UI.Layout;

using DXLib.Utils;

namespace iStatVball3;

/*
 * Draws the 3x2 grid of players currently on the court. Each player is drawn using a PlayerCell. The arrangement of
 * players on court is strictly drawing location. Rotation order, smart locations, etc are handled externally.
 */
public class PlayerGrid : DXGridLayout
{
	/* Constants */
	public static double Pad { get; private set; }

	// 3x2 grid
	private const int NumRows = 2;
	private const int NumCols = 3;

	private const int CellCount = (NumRows * NumCols);

	/* Events */
	public Action<ButtonKey> ButtonTapped { get; set; }

	/* Fields */
	private readonly List<PlayerCell> cells;

	// Parent ref
	private Legacy engine;

	/* Methods */
	public PlayerGrid()
	{
		BackgroundColor = DXColors.Dark1;

		IgnoreSafeArea = true;
		
		// Allocate container
		cells = new List<PlayerCell>( CellCount );
	}

	// Post construction initialization
	public void Init( Legacy legacy )
	{
		engine = legacy;

		// 3x2 grid
		AddStarRows( NumRows );
		AddStarColumns( NumCols );

		// Populate each cell
		for ( int row = 0; row < NumRows; row++ )
		{
			for ( int col = 0; col < NumCols; col++ )
			{
				int index = (row * NumCols) + col;

				// Create
				PlayerCell cell = new()
				{
					Zone = IndexToZone( index ),

					ButtonTapped = ButtonTapped
				};

				cell.Init( legacy );
				cells.Add( cell );

				// Layout
				Add( cell, col, row );
			}
		}
	}

	// Disables all player area buttons while rally in-progress
	public void StartRally( bool start )
	{
		foreach ( PlayerCell cell in cells )
		{
			cell.StartRally( start );
		}
	}

	// Finds court zone (1-6) where specified player currently located
	public int ZoneForPlayer( Player player )
	{
		if ( player != null )
		{
			foreach ( PlayerCell cell in cells )
			{
				LineupEntry entry = cell.GetEntry();

				// Found match
				if ( entry.Player.Equals( player ) )
				{
					return cell.Zone;
				}
			}
		}

		return 0;
	}

	/* Get/Set */

	// Returns entry for player currently in specified zone on court
	public LineupEntry GetEntry( int zone )
	{
		int index = ZoneToIndex( zone );

		return cells[ index ].GetEntry();
	}

	// Returns entries for all players currently on court (display order)
	public List<LineupEntry> GetEntries()
	{
		List<LineupEntry> entries = new( Lineup.BaseEntries );

		// Zones 1-6
		for ( int zone = 1; zone <= Lineup.BaseEntries; zone++ )
		{
			int index = ZoneToIndex( zone );

			entries.Add( cells[ index ].GetEntry() );
		}

		return entries;
	}

	// Returns list of players currently on court (display order)
	public List<Player> GetPlayers()
	{
		List<Player> players = new( Lineup.BaseEntries );

		// Zones 1-6
		for ( int zone = 1; zone <= Lineup.BaseEntries; zone++ )
		{
			int index = ZoneToIndex( zone );
			LineupEntry entry = cells[ index ].GetEntry();

			players.Add( entry?.Player );
		}

		return players;
	}

	// Returns cell of designated setter on court
	private PlayerCell GetSetterCell()
	{
		// Zone 1
		PlayerCell cell = cells[ ZoneToIndex( 1 ) ];

		if ( cell.IsSetter )
		{
			return cell;
		}

		// Zones 6,5,4,3,2
		for ( int zone = Lineup.BaseEntries; zone > 1; zone-- )
		{
			cell = cells[ ZoneToIndex( zone ) ];

			// Might be blanks
			if ( cell.IsSetter )
			{
				return cell;
			}
		}

		// No setter found
		return null;
	}

	// Sets all player entries currently on court (zones 1-6)
	public void SetEntries( List<LineupEntry> entries )
	{
		for ( int i = 0; i < Lineup.BaseEntries; i++ )
		{
			SetEntry( (i + 1), entries[i] );
		}
	}

	// Sets individual player entry currently on court
	public void SetEntry( int zone, LineupEntry entry )
	{
		int index = ZoneToIndex( zone );

		cells[ index ].SetEntry( entry );
	}

	/* UI Control */

	// Updates state based on current editing mode
	public void UpdateEditMode()
	{
		foreach ( PlayerCell cell in cells )
		{
			cell.UpdateEditMode();
		}

		ShowButtonAreas( engine.IsEditOff );
	}

	// Shows/hides button area in all cells
	public void ShowButtonAreas( bool show )
	{
		foreach ( PlayerCell cell in cells )
		{
			cell.ShowButtonArea( show );
		}
	}

	// MOBILE: Closes stat button popup 
	public void ClosePopup( ButtonKey key )
	{
		int index = ZoneToIndex( key.Zone );

		cells[ index ].ClosePopup();
	}

	/* Enable */

	// Enables an entire category across all button areas
	public void EnableCategory( string category, bool frontrow = false  )
	{
		// Optionally enable frontrow only
		if ( frontrow )
		{
			EnableCategory( 4, category );
			EnableCategory( 3, category );
			EnableCategory( 2, category );
		}
		// Otherwise all
		else
		{
			foreach ( PlayerCell cell in cells )
			{
				cell.EnableCategory( category );
			}
		}
	}

	// Enables an entire category in specified button area
	public void EnableCategory( int zone, string category )
	{
		int index = ZoneToIndex( zone );

		cells[ index ].EnableCategory( category );
	}

	// Enables specified key within given category
	public void Enable( string category, string key, bool frontrow = false )
	{
		// Optionally enable frontrow only
		if ( frontrow )
		{
			Enable( 4, category, key );
			Enable( 3, category, key );
			Enable( 2, category, key );
		}
		// Otherwise all
		else
		{
			foreach ( PlayerCell cell in cells )
			{
				cell.Enable( category, key );
			}
		}
	}

	// Enables key within category only for specified zone
	public void Enable( int zone, string category, string key )
	{
		int index = ZoneToIndex( zone );

		cells[ index ].Enable( category, key );
	}

	// Enables setting category accounting for AutoSet
	public void EnableSetting()
	{
		// Everyone has at least error button
		EnableCategory( Legacy.Setting );

		switch ( Shell.Settings.LegacySet )
		{
			// No one has assist button with Semi-Auto
			case Legacy.AutoSetSemi:
			{
				Disable( Legacy.Setting, Stats.AssistKey );
				break;
			}
			// Setter does not have attempt with Full-Auto
			case Legacy.AutoSetFull:
			{
				Disable( Legacy.Setting, Stats.AssistKey );

				PlayerCell setter = GetSetterCell();

				setter?.Disable( Legacy.Setting, Stats.AttemptKey );
				break;
			}
		}
	}

	// Enables all '+' popup add buttons
	public void EnableAddAll()
	{
		// Mobile only
		if ( DXDevice.IsMobile )
		{
			foreach ( PlayerCell cell in cells )
			{
				cell.EnableAdd();
			}
		}
	}

	// Enables '+' popup add button for specified zone
	public void EnableAdd( int zone )
	{
		// Mobile only
		if ( DXDevice.IsMobile )
		{
			int index = ZoneToIndex( zone );

			cells[ index ].EnableAdd();
		}
	}

	/* Disable */

	// Disables all buttons, in all categories, in all button areas
	public void DisableAll()
	{
		foreach ( PlayerCell cell in cells )
		{
			cell.DisableAll();
		}
	}

	// Disables all buttons, in all categories, for specified button area
	public void DisableAll( int zone )
	{
		int index = ZoneToIndex( zone );

		cells[ index ].DisableAll();
	}

	// Disables individual button in button area
	public void Disable( string category, string key )
	{
		foreach ( PlayerCell cell in cells )
		{
			cell.Disable( category, key );
		}
	}

	// Disables an entire category across all button areas
	public void DisableCategory( string category )
	{
		foreach ( PlayerCell cell in cells )
		{
			cell.DisableCategory( category );
		}
	}

	// Disables all '+' add popup buttons
	public void DisableAddAll()
	{
		// Mobile only
		if ( DXDevice.IsMobile )
		{
			foreach ( PlayerCell cell in cells )
			{
				cell.DisableAdd();
			}
		}
	}

	/* Tap State */

	// Forces specified button into sticky tap state
	public void ShowTap( ButtonKey key )
	{
		int index = ZoneToIndex( key.Zone );

		cells[ index ].ShowTap( key );
	}

	// Resets sticky state of specified button
	public void ResetTap( ButtonKey key )
	{
		int index = ZoneToIndex( key.Zone );

		cells[ index ].ResetTap( key );
	}

	/* Utilities */

	// Maps a grid cell index (0-5) to corresponding lineup zone (1-6)
	private static int IndexToZone( int index )
	{
		return index switch
		{
			0 => 4,
			1 => 3,
			2 => 2,
			3 => 5,
			4 => 6,
			5 => 1,

			_ => 0,
		};
	}

	// Maps a lineup zone (1-6) to corresponding grid cell index (0-5)
	private static int ZoneToIndex( int zone )
	{
		return zone switch
		{
			1 => 5,
			2 => 2,
			3 => 1,
			4 => 0,
			5 => 3,
			6 => 4,

			_ => -1,
		};
	}

	/* Layout */

	// Calculates dynamic width of grid cell based on orientation
	public static double CellWd()
	{
		double wd = (DXDevice.GetScreenWd() - DXDevice.SafeArea().HorizontalThickness);
		
		return (((wd - Pad) / 3) - Pad);
	}

	// Calculates dynamic height of grid cell based on orientation
	public static double CellHt()
	{
		double gridHt = (DXDevice.GetScreenHt() - DXDevice.GetSafeTop() - RecordEngine.ScoreboardHt);

		return (((gridHt - Pad) / 2) - Pad);
	}

	// Redraws entire 3x2 grid
	public override void UpdateLayout( LayoutType type )
	{
		Thickness safeArea = DXDevice.SafeArea();
		
		// Do NOT call base here
		Pad = type switch
		{
			LayoutType.Landscape or 
			LayoutType.WideLandscape or 
			LayoutType.Portrait or 
			LayoutType.WidePortrait => 10,
			
			LayoutType.MobileLandscape or 
			LayoutType.MobilePortrait => 7,
			
			_ => Pad
		};

		double horizPad = safeArea.HorizontalThickness;
		double bottomPad = (safeArea.Bottom + Pad + (DXDevice.IsMobilePortrait() ? Pad : 0));
		
		// Orientation specific padding
		Padding = new Thickness( (horizPad + Pad), Pad, (horizPad + Pad), bottomPad );
		RowSpacing = Pad;
		ColumnSpacing = Pad;

		// Update children
		foreach ( PlayerCell cell in cells )
		{
			cell.UpdateLayout( type );
		}
	}
}

//
