/* 
 * 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.Utils;

namespace iStatVball3;

/*
 * Implementation of the scoreboard area for the Legacy engine.
 */
public class LegacyScore : RecordScore
{
	/* Fields */

	// UI controls
	private readonly LegacyLibero libero;

	private readonly DrawerButton rotBtn;
	private readonly DrawerButton subsBtn;

	private readonly DrawerIcon lineupBtn;
	private readonly DrawerIcon autoBtn;

	// Engine specific ref
	private Legacy engine;

	/* Methods */

	// Creates all controls, dynamic layout occurs later
	public LegacyScore( RecordEngine parent ) : base( parent )
	{
		/* Controls */

		// Libero
		libero = new LegacyLibero( this );
		libero.Init();
		
		Add( libero );

		// Rotation
		rotBtn = new DrawerButton( this )
		{
			Title = "teambar.rotation",
			Color = DXColors.Light4,
			NumberColor = DXColors.Dark2,
			
			HasShadow = false,
			IsSticky = true,
			
			ButtonPressed = OnRotationPressed
		};
		
		rotBtn.Init();
		
		// Logo
		logoBar.Legacy = true;

		// Subs
		subsBtn = new DrawerButton( this )
		{
			Title = "teambar.subs",
			Color = DXColors.Light4,
			NumberColor = DXColors.Dark2,

			HasShadow = false,
			IsSticky = true,
			
			ButtonPressed = OnSubsPressed
		};

		subsBtn.Init();
		
		// Lineup
		lineupBtn = new DrawerIcon( this )
		{
			Resource = "player",
			Color = DXColors.Action,

			Title = "teambar.lineup",
			IsCircle = true,

			ButtonTapped = OnLineupTapped,
			ButtonPressed = OnLineupPressed
		};

		lineupBtn.Init();
		
		// Undo Auto
		autoBtn = new DrawerIcon( this )
		{
			Resource = "auto",
			Color = DXColors.Negative,

			Title = "score.auto",
			IsCircle = true,
			IsSticky = false,

			ButtonTapped = OnAutoTapped
		};

		// Initially disabled
		UpdateUndoAuto( false );

		bool legacyMobile = (Shell.IsLegacy && DXDevice.IsMobile);

		// Undo
		UndoStack.History.ShowTeams = !legacyMobile;
	}

	// Post construction initialization
	public async Task Init( LegacyState state, Legacy legacy )
	{
		engine = legacy;

		StateMachine = state;

		await Init( state.Set );

		// Init children
		libero.Init( engine );
	}

	/* Libero */

	// Returns player(s) currently in libero area
	public List<Player> GetLiberos()
	{
		return libero.GetPlayers();
	}

	// Returns lineup entry for specified libero
	public LineupEntry GetLiberoEntry( int number )
	{
		return libero.GetEntry( number );
	}

	// Sets lineup entry for specified libero
	public void SetLiberoEntry( int number, LineupEntry entry )
	{
		libero.SetEntry( number, entry );
	}

	// Sets lineup entry for both liberos
	public void SetLiberoEntries( List<LineupEntry> entries )
	{
		libero.SetEntries( entries );
	}

	/* Update */

	// Updates players currently in libero zone(s)
	public void UpdateLibero()
	{
		libero.SetEntries( sm.Lineup1.Entries );
	}

	// Updates current primary team rotation
	public void UpdateRotation( int rotation )
	{
		rotBtn.Number = rotation;
	}

	// Updates substitutions remaining for primary team
	public void UpdateSubs( int subs )
	{
		// NA for unlimited subs
		if ( Shell.Settings.IsUnlimitedSubs )
		{
			subsBtn.Text = DXString.Get( "teambar.na" );
			subsBtn.IsDisabled = true;
		}
		// Update
		else
		{
			subsBtn.Number = subs;
			subsBtn.IsDisabled |= (subs == 0);
		}
	}

	// Updates visibility of Undo Auto Assist button
	public void UpdateUndoAuto( bool enabled )
	{
		autoBtn.IsVisible = enabled;

		// Undo Auto toggles with logo
		logoBar.IsVisible = !enabled;
	}

	// Updates state based on editing mode
	public void UpdateEditMode()
	{
		// Turning ON
		if ( engine.IsEditOn )
		{
			lineupBtn.Resource = "close";
			lineupBtn.Color = DXColors.Negative;
		}
		// Turning OFF
		else
		{
			lineupBtn.Resource = "player";
			lineupBtn.Color = DXColors.Action;

			// MUST update here (manual award point after start blank lineup)
			DisableScore( false );
		}

		// Update children
		libero.UpdateEditMode();
	}

	/* Disable */

	// Enables/disables Legacy specific buttons
	public override void DisableButtons( bool disabled )
	{
		switch ( sm.State )
		{
			// Enabled between rallies
			case Legacy.StartState:
			case Legacy.ServeState:
			case Legacy.ReceiveState:
			{
				Disable( false );
				break;
			}
			// Disabled during rallies
			default:
			{
				Disable( true );
				break;
			}
		}
	}

	// Legacy only disables score during edit mode
	public override void DisableScore( bool disabled )
	{
		base.DisableScore( engine.IsEditOn );
	}

	// Used internally to enable/disable buttons
	private void Disable( bool disable )
	{
		base.DisableButtons( disable );

		rotBtn.IsDisabled = disable;
		subsBtn.IsDisabled = disable || Shell.Settings.IsUnlimitedSubs;
		lineupBtn.IsDisabled = disable;

		libero.Disable( disable );
	}

	/* Event Callbacks */

	// POSSESSION

	// User confirmed manual change of possession
	protected override void OnPossConfirmed()
	{
		string prevState = sm.State;
		sm.State = "start";

		base.OnPossConfirmed();

		// Legacy specific handling here
		sm.InitRally( true, false );
		sm.State = (prevState == Legacy.ServeState) ? Legacy.ReceiveState : Legacy.ServeState;
	}

	// END

	// User ending set
	protected override async void OnEndConfirmed()
	{
		// Persist all set end data
		await parent.End( Score1, Score2 );

		base.OnEndConfirmed();
	}

	// ROTATION

	// User long pressed to edit rotation
	private void OnRotationPressed( object sender )
	{
		DXNumericEditor editor = new()
		{
			MinValue = 1,
			MaxValue = 6,
			ShouldWrap = true,

			Number = sm.RotationForTeam( 1 ),

			Selected = OnRotationSelected,
			Cancelled = OnRotationCancelled
		};

		editor.Show( rotBtn.View );
	}

	// Rotation changed
	private void OnRotationSelected( int rotation )
	{
		LegacyState legacySm = (LegacyState)sm;

		// Persist event
		legacySm.ChangeRotation( sm.Team1OnSideA, (byte)rotation );
		legacySm.UpdatePlayers();

		// Update UI			
		rotBtn.Reset();

		// Check for libero auto swap
		if ( legacySm.IsLiberoIn() && !legacySm.IsLiberoBack() )
		{
			legacySm.SwapLiberoOut( true );
		}
	}

	// Rotation cancelled, no change
	private void OnRotationCancelled()
	{
		rotBtn.Reset();
	}

	// SUBS

	// User long pressed to edit subs remaining
	private void OnSubsPressed( object sender )
	{
		int max = Shell.Settings.SubsMax;

		if ( max > 0 )
		{
			DXNumericEditor editor = new()
			{
				MinValue = 0,
				MaxValue = max,
				ShouldWrap = false,

				Number = sm.Subs1,

				Selected = OnSubsSelected,
				Cancelled = OnSubsCancelled
			};

			editor.Show( subsBtn.View );
		}
	}

	// Subs remaining changed
	private void OnSubsSelected( int subs )
	{
		// Persist event
		sm.ChangeSubs( sm.Team1OnSideA, (byte)subs );

		// Update UI
		UpdateSubs( sm.Subs1 );
		subsBtn.Reset();
	}

	// Subs remaining cancelled, no change
	private void OnSubsCancelled()
	{
		subsBtn.Reset();
	}

	// LINEUP

	// User toggling lineup edit mode
	private void OnLineupTapped()
	{
		Legacy.EditMode mode = engine.IsEditOn ? Legacy.EditMode.Off : Legacy.EditMode.Sub;

		// Toggling between sub or not, blank lineup never started here
		engine.SetEditMode( mode, false, OnLineupDone );

		undoBtn.IsDisabled = engine.IsEditOn;
	}

	// User dynamically creating new lineup
	private void OnLineupPressed()
	{
		if ( engine.IsEditOn )
		{
			List<LineupEntry> entries = engine.GetCourtEntries();

			// Prompt user, persist
			parent.SaveLineup( entries, OnLineupDone );
		}
		else
		{
			lineupBtn.Reset();
		}
	}

	// User ended lineup editing mode
	private void OnLineupDone()
	{
		lineupBtn.Reset();
	}

	// UNDO AUTO

	// User tapped Undo Auto Assist
	private async void OnAutoTapped()
	{
		// Delete assist stat
		await engine.UndoAutoAssist();

		// Update UI
		UpdateUndoAuto( false );
		UndoStack.Update();
	}

	/* Layout */

	// Special handling for rotate
	public override void Rotate()
	{
		base.Rotate();

		UpdateUndoAuto( autoBtn.IsVisible );
	}

	// Redraws entire Legacy scoreboard
	public override void UpdateLayout( LayoutType type )
	{
		base.UpdateLayout( type );

		// Update children
		libero.UpdateLayout( type );
	}

	// Landscape (4:3) [dynamic]
	protected override void Landscape()
	{
		bool ios = DXDevice.IsIOS;
		bool large = DXDevice.IsLargeTablet();

		Padding = 0;

		// Layout constants
		double wd = DXDevice.GetScreenWd();			
		double pad = (wd * (large ? 0.005 : 0.010));

		double btnWd = (wd * 0.040);
		double btnHt = (wd * 0.056);

		double x0 = (wd * 0.010);

		double y0 = (wd * 0.005);
		double y1 = (y0 + btnHt + pad);

		double spaceWd = (wd * 0.016);
		double halfSpaceWd = (spaceWd / 2);
		double colWd = (btnWd + spaceWd);

		double scoreWd = (wd * 0.076);
		double scoreHt = (scoreWd + (wd * 0.010));

		double numberSize = (wd * 0.029);
		double titleSize = (wd * 0.012);

		/* Controls */

		double liberoWd = (btnWd * 4) + (wd * 0.020);
		double liberoHt = (RecordEngine.ScoreboardHt - (pad * 3));

		// Libero
		SetBounds( libero, x0, y0, liberoWd, liberoHt );

		double pauseX = (x0 + liberoWd + spaceWd);

		// Pause
		pauseBtn.TitleSize = titleSize;
		pauseBtn.Layout( pauseX, y0, btnWd );

		// Switch
		switchBtn.TitleSize = titleSize;
		switchBtn.Resource = "switch_horiz";

		switchBtn.Layout( pauseX, y1, btnWd );

		double rotX = (pauseX + colWd);

		// Rotation
		rotBtn.TitleSize = titleSize;
		rotBtn.NumberSize = numberSize;
		rotBtn.AdjustX = -5;
		rotBtn.NumberAdjustY = -1;

		rotBtn.Layout( rotX, y0, btnWd );

		// Timeout A
		timeoutsABtn.TitleSize = titleSize;
		timeoutsABtn.NumberSize = numberSize;
		timeoutsABtn.NumberAdjustY = -1;
		timeoutsABtn.AdjustX = ios ? -2 : -3;

		timeoutsABtn.Layout( rotX, y1, btnWd );

		double scoreXa = (rotX + colWd);
		double scoreY = (y0 + (wd * (large ? 0.012 : 0.017)));

		double teamFont = (wd * 0.018);
		double scoreFont = (wd * 0.055);

		// Score A
		scoreABtn.TeamSize = teamFont;
		scoreABtn.ScoreSize = scoreFont;

		scoreABtn.Layout( scoreXa, scoreY, scoreWd, scoreHt );

		double setsXa = (scoreXa + scoreWd + spaceWd);

		// Sets A
		setsABtn.TitleSize = titleSize;
		setsABtn.NumberSize = numberSize;
		setsABtn.NumberAdjustY = -1;

		setsABtn.Layout( setsXa, y1, btnWd );

		double possXa = (setsXa + colWd);

		double setY = (wd * 0.026);
		double setSize = (wd * 0.034);

		double arrowSize = (setSize - (wd * 0.010));
		double arrowY = (setY + ((setSize - arrowSize) / 2) - 1);

		// Possession A
		possABtn.Resource = "arrow_left";
		possABtn.Size = arrowSize;

		SetBounds( possABtn, (possXa - spaceWd - arrowSize), arrowY, arrowSize, arrowSize );

		// Set Number
		double setX = (possXa + ((btnWd - setSize) / 2));
		double setMid = (setX + (setSize / 2));

		setBtn.NumberSize = (wd * 0.020);
		setBtn.NumberAdjustY = -1;
		setBtn.AdjustX = -2;
		setBtn.Layout( setX, setY, setSize );

		// Logo
		double logoWd = (btnWd + spaceWd);
		double logoHt = (logoWd / 2.1);

		double logoX = (setMid - (logoWd / 2));
		double logoY = (y1 + (btnHt / 2) - (logoHt / 2));

		logoBar.SetSize( logoWd, logoHt );

		SetBounds( logoBar, logoX, logoY, logoWd, logoHt );

		// Undo Auto
		double autoX = (setMid - (btnWd / 2) + 5);

		autoBtn.TitleSize = titleSize;
		autoBtn.AdjustX = -5;

		autoBtn.Layout( autoX, y1, btnWd );

		// Possession B
		double possXb = (setX + colWd);

		possBBtn.Resource = "arrow_right";
		possBBtn.Size = arrowSize;

		SetBounds( possBBtn, possXb, arrowY, arrowSize, arrowSize );

		// Sets B
		setsBBtn.TitleSize = titleSize;
		setsBBtn.NumberSize = numberSize;
		setsBBtn.NumberAdjustY = -1;

		setsBBtn.Layout( possXb, y1, btnWd );

		double scoreXb = (possXb + colWd);

		// Score B
		scoreBBtn.TeamSize = teamFont;
		scoreBBtn.ScoreSize = scoreFont;

		scoreBBtn.Layout( scoreXb, scoreY, scoreWd, scoreHt );

		double subsX = (scoreXb + scoreWd + spaceWd);

		// Subs
		subsBtn.TitleSize = titleSize;
		subsBtn.NumberSize = numberSize;
		subsBtn.NumberAdjustY = -1;

		subsBtn.Layout( subsX, y0, btnWd );

		// Timeout B
		timeoutsBBtn.TitleSize = titleSize;
		timeoutsBBtn.NumberSize = numberSize;
		timeoutsBBtn.AdjustX = ios ? -2 : -3;
		timeoutsBBtn.NumberAdjustY = -1;

		timeoutsBBtn.Layout( subsX, y1, btnWd );

		double endX = (subsX + colWd);

		// End
		endBtn.TitleSize = titleSize;
		endBtn.Layout( endX, y0, btnWd );

		// Undo
		undoBtn.TitleSize = titleSize;
		undoBtn.Layout( endX, y1, btnWd );

		double undoX = (endX + btnWd + halfSpaceWd);
		double undoWd = (liberoWd - (spaceWd * 2));

		// Undo Stack
		UndoStack.FontSize = (wd * 0.011);
		UndoStack.Spacing = (wd * (ios ? 0.002 : 0.000));
		UndoStack.Margin = DXUtils.Top( ios ? -1 : -3 );

		UndoStack.History.MaxNameLength = 19;
		UndoStack.History.ShowRatings = true;

		SetBounds( UndoStack, undoX, (y1 + 1), undoWd, btnHt );

		double lineupX = (endX + colWd);

		// Lineup
		lineupBtn.TitleSize = titleSize;
		lineupBtn.Layout( lineupX, y0, btnWd );

		// Toolbar
		toolBar.Mode = ToolBar.DisplayMode.TwoLine;
		toolBar.Spacing = 10;
		toolBar.SetMargin( 0, 0, pad, 0 );

		double toolbarWd = toolBar.GetWidth();
		double toolbarHt = toolBar.GetHeight();

		double toolbarX = (wd - toolbarWd);

		SetBounds( toolBar, toolbarX, y0, toolbarWd, toolbarHt );
	}

	// Widescreen Landscape (16:10)
	protected override void WideLandscape()
	{
		bool ios = DXDevice.IsIOS;

		Padding = DXDevice.SafeArea();

		// Layout constants
		double wd = (DXDevice.GetScreenWd() - Padding.HorizontalThickness);

		const double btnWd = 45;
		const double btnHt = 60;

		double x0 = 10;

		double y0 = 0;
		double y1 = (y0 + 2);
		double y2 = (y0 + 48);

		double spaceWd = 14;
		double halfSpaceWd = (spaceWd / 2);
		double colWd = (btnWd + spaceWd);

		const double scoreWd = 78;
		const double scoreHt = (scoreWd + 10);

		const double titleSize = 12;
		const double numberSize = 30;

		/* Controls */

		const double liberoWd = (btnWd * 4) + 20;
		const double liberoHt = (scoreHt + 18);

		// Libero
		SetBounds( libero, x0, y1, liberoWd, liberoHt );

		double pauseX = (x0 + liberoWd + spaceWd);

		// Pause
		pauseBtn.TitleSize = titleSize;
		pauseBtn.Layout( pauseX, y2, btnWd );

		double switchX = (pauseX + colWd);

		// Switch
		switchBtn.Resource = "switch_horiz";
		switchBtn.TitleSize = titleSize;

		switchBtn.Layout( switchX, y2, btnWd );

		double rotX = (switchX + colWd);

		// Rotation
		rotBtn.TitleSize = titleSize;
		rotBtn.NumberSize = numberSize;
		rotBtn.AdjustX = -5;

		rotBtn.Layout( rotX, y2, btnWd );

		double timeXa = (rotX + colWd);

		// Timeout A
		timeoutsABtn.TitleSize = titleSize;
		timeoutsABtn.NumberSize = numberSize;
		timeoutsABtn.AdjustX = ios ? -2 : -4;

		timeoutsABtn.Layout( timeXa, y2, btnWd );

		double scoreXa = (timeXa + colWd);

		const double teamFont = 18;
		const double scoreFont = 56;

		// Score A
		scoreABtn.TeamSize = teamFont;
		scoreABtn.ScoreSize = scoreFont;

		scoreABtn.Layout( scoreXa, y0, scoreWd, scoreHt );

		double setsXa = (scoreXa + scoreWd + spaceWd);

		// Sets A
		setsABtn.TitleSize = titleSize;
		setsABtn.NumberSize = numberSize;

		setsABtn.Layout( setsXa, y2, btnWd );

		double possXa = (setsXa + colWd);

		const double setSize = 35;
		const double arrowSize = (setSize - 10);

		double arrowY = (y1 + ((setSize - arrowSize) / 2) - 1);

		// Possession A
		possABtn.Resource = "arrow_left";
		possABtn.Size = arrowSize;

		SetBounds( possABtn, (possXa - spaceWd - arrowSize), arrowY, arrowSize, arrowSize );

		// Set Number
		double setX = (possXa + ((btnWd - setSize) / 2));
		double setMid = (setX + (setSize / 2));

		setBtn.NumberSize = 20;
		setBtn.Layout( setX, y1, setSize );

		// Logo
		double logoWd = (btnWd + spaceWd);
		double logoHt = (logoWd / 2.1);

		double logoX = (setMid - (logoWd / 2));
		double logoY = (y2 + (btnHt / 2) - (logoHt / 2));

		logoBar.SetSize( logoWd, logoHt );

		SetBounds( logoBar, logoX, logoY, logoWd, logoHt );

		// Undo Auto Assist
		double autoX = (setMid - (btnWd / 2));

		autoBtn.TitleSize = titleSize;
		autoBtn.AdjustX = -5;

		autoBtn.Layout( autoX, y2, btnWd );

		// Possession B
		double possXb = (setX + colWd);

		possBBtn.Resource = "arrow_right";
		possBBtn.Size = arrowSize;

		SetBounds( possBBtn, possXb, arrowY, arrowSize, arrowSize );

		// Sets B
		setsBBtn.TitleSize = titleSize;
		setsBBtn.NumberSize = numberSize;

		setsBBtn.Layout( possXb, y2, btnWd );

		double scoreXb = (possXb + colWd);

		// Score B
		scoreBBtn.TeamSize = teamFont;
		scoreBBtn.ScoreSize = scoreFont;

		scoreBBtn.Layout( scoreXb, y0, scoreWd, scoreHt );

		double timeXb = (scoreXb + scoreWd + spaceWd);

		// Timeout B
		timeoutsBBtn.TitleSize = titleSize;
		timeoutsBBtn.NumberSize = numberSize;
		timeoutsBBtn.AdjustX = ios ? -2 : -4;

		timeoutsBBtn.Layout( timeXb, y2, btnWd );

		double subsX = (timeXb + colWd);

		// Subs
		subsBtn.TitleSize = titleSize;
		subsBtn.NumberSize = numberSize;

		subsBtn.Layout( subsX, y2, btnWd );

		double lineupX = (subsX + colWd);

		// Lineup
		lineupBtn.TitleSize = titleSize;
		lineupBtn.Layout( lineupX, y2, btnWd );

		double endX = (lineupX + colWd);

		// End
		endBtn.TitleSize = titleSize;
		endBtn.Layout( endX, y2, btnWd );

		double undoX = (endX + colWd);

		// Undo
		undoBtn.TitleSize = titleSize;
		undoBtn.Layout( undoX, y2, btnWd );

		double stackX = (undoX + btnWd + halfSpaceWd);
		const double stackWd = (liberoWd + 5);

		// Undo Stack
		UndoStack.FontSize = 11;
		UndoStack.RowSpacing = 0;
		UndoStack.Margin = DXUtils.Top( -5 );

		UndoStack.History.MaxNameLength = 19;
		UndoStack.History.ShowRatings = true;

		SetBounds( UndoStack, stackX, y2, stackWd, btnHt );

		// Toolbar
		toolBar.Mode = ToolBar.DisplayMode.OneLine;
		toolBar.Spacing = 2;

		double toolbarWd = toolBar.GetWidth();
		double toolbarHt = toolBar.GetHeight();

		double toolbarX = (wd - toolbarWd - x0);

		SetBounds( toolBar, toolbarX, y1, toolbarWd, toolbarHt );
	}

	// Portrait (3:4) [dynamic]
	protected override void Portrait()
	{
		bool ios = DXDevice.IsIOS;
		bool wide = DXDevice.IsTabletWide;
		bool large = DXDevice.IsLargeTablet();

		Padding = 0;

		// Layout constants
		double wd = DXDevice.GetScreenWd();
		double ht = DXDevice.GetScreenHt();

		double btnWd = (ht * 0.044);
		double btnHt = (ht * 0.059);

		double spaceWd = (ht * 0.009);
		double colWd = (btnWd + spaceWd);

		double scoreWd = (ht * 0.076);
		double scoreHt = (ht * 0.086);

		double numberSize = (ht * 0.029);
		double titleSize = (ht * (wide ? 0.011 : 0.012));

		double teamFont = (ht * 0.018);
		double scoreFont = (ht * 0.055);

		double pad = (ht * 0.005);
		double x0 = (pad * 2);

		double scoreY2 = (pad + teamFont + scoreHt);

		double y1 = (scoreY2 - btnHt - pad + 2);
		double y2 = (y1 + btnHt + pad + 3);

		/* Controls */

		double liberoWd = (wd * (large ? 0.237 : (wide ? 0.220 : 0.245)));
		double liberoHt = (scoreHt + teamFont - (pad / 2.0));

		// Libero
		SetBounds( libero, x0, pad, liberoWd, liberoHt );

		double scoreXa = (x0 + liberoWd + spaceWd + 7);
		double scoreY = (ht * 0.001);

		// Score A
		scoreABtn.TeamSize = teamFont;
		scoreABtn.ScoreSize = scoreFont;

		scoreABtn.Layout( scoreXa, scoreY, scoreWd, scoreHt );

		double setsXa = (scoreXa + scoreWd + spaceWd);

		// Sets A
		setsABtn.TitleSize = titleSize;
		setsABtn.NumberSize = numberSize;

		setsABtn.Layout( setsXa, y1, btnWd );

		double possXa = (setsXa + colWd);

		double setY = (scoreY * 3);
		double setSize = (ht * 0.034);

		double arrowSize = (ht * 0.024);
		double arrowY = (setY + ((setSize - arrowSize) / 2));

		// Possession A
		possABtn.Resource = "arrow_left";
		possABtn.Size = arrowSize;

		SetBounds( possABtn, (possXa - spaceWd - arrowSize), arrowY, arrowSize, arrowSize );

		// Set Number
		double setX = (possXa + ((btnWd - setSize) / 2));
		double setMid = (setX + (setSize / 2));

		setBtn.NumberSize = (ht * 0.020);
		setBtn.NumberAdjustY = -1;
		
		setBtn.Layout( setX, setY, setSize );

		// Logo
		double logoWd = (btnWd + spaceWd);
		double logoHt = (logoWd / 2.1);

		double logoX = (setMid - (logoWd / 2));
		double logoY = (y1 + (btnHt / 2) - (logoHt / 2));

		logoBar.SetSize( logoWd, logoHt );

		SetBounds( logoBar, logoX, logoY, logoWd, logoHt );

		// Undo Auto Assist
		double autoX = (setMid - (btnWd / 2) + 5);

		autoBtn.TitleSize = titleSize;
		autoBtn.AdjustX = -5;

		autoBtn.Layout( autoX, y1, btnWd );

		// Possession B
		double possXb = (setX + colWd);

		possBBtn.Resource = "arrow_right";
		possBBtn.Size = arrowSize;

		SetBounds( possBBtn, possXb, arrowY, arrowSize, arrowSize );

		double setsXb = possXb;

		// Sets B
		setsBBtn.TitleSize = titleSize;
		setsBBtn.NumberSize = numberSize;
		setsBBtn.NumberAdjustY = -1;

		setsBBtn.Layout( setsXb, y1, btnWd );

		double scoreXb = (setsXb + colWd);

		// Score B
		scoreBBtn.TeamSize = teamFont;
		scoreBBtn.ScoreSize = scoreFont;

		scoreBBtn.Layout( scoreXb, scoreY, scoreWd, scoreHt );

		// Toolbar
		toolBar.Mode = ToolBar.DisplayMode.OneLine;
		toolBar.Spacing = 5;

		double toolbarWd = toolBar.GetWidth();
		double toolbarHt = toolBar.GetHeight();

		double toolbarX = (wd - toolbarWd - pad);
		double toolbarY = pad;

		SetBounds( toolBar, toolbarX, toolbarY, toolbarWd, toolbarHt );

		double undoX = (scoreXb + scoreWd + spaceWd);
		double undoY = (y1 + (wide ? 0 : 5));

		double undoWd = (liberoWd + 5);
		double undoHt = (btnHt + 2);

		// Undo Stack
		UndoStack.FontSize = (wd * 0.015);
		UndoStack.Spacing = (wd * 0.003);
		UndoStack.Margin = new Thickness( 0, 0, 0, 0 );

		UndoStack.History.MaxNameLength = 19;
		UndoStack.History.ShowRatings = true;
		
		SetBounds( UndoStack, undoX, (undoY - (ios ? 5 : 9)), undoWd, undoHt );

		double pauseX = (scoreXa - spaceWd - colWd - btnWd);

		// Pause
		pauseBtn.TitleSize = titleSize;
		pauseBtn.Layout( pauseX, y2, btnWd );

		double switchX = (pauseX + colWd);

		// Switch
		switchBtn.Resource = "switch_horiz";
		switchBtn.TitleSize = titleSize;

		switchBtn.Layout( switchX, y2, btnWd );

		double scoreWd2 = (scoreWd / 2);
		double btnWd2 = (btnWd / 2);

		double rotX = (scoreXa + scoreWd2 - btnWd2 + 1);

		// Rotation
		rotBtn.TitleSize = titleSize;
		rotBtn.NumberSize = numberSize;
		rotBtn.AdjustX = -5;

		rotBtn.Layout( rotX, y2, btnWd );

		double adjustX = ios ? -2 : (wide ? -4 : -3);

		// Timeout A
		timeoutsABtn.TitleSize = titleSize;
		timeoutsABtn.NumberSize = numberSize;
		timeoutsABtn.AdjustX = adjustX;

		timeoutsABtn.Layout( setsXa, y2, btnWd );

		// Timeout B
		timeoutsBBtn.TitleSize = titleSize;
		timeoutsBBtn.NumberSize = numberSize;
		timeoutsBBtn.AdjustX = adjustX;

		timeoutsBBtn.Layout( possXb, y2, btnWd );

		double timeXa2 = (setsXa + btnWd);
		double lineupX = (timeXa2 + ((possXb - timeXa2) / 2) - btnWd2);

		// Lineup
		lineupBtn.TitleSize = titleSize;
		lineupBtn.AdjustX = adjustX;

		lineupBtn.Layout( lineupX, y2, btnWd );

		double subsX = (scoreXb + scoreWd2 - btnWd2 + 1);

		// Subs
		subsBtn.TitleSize = titleSize;
		subsBtn.NumberSize = numberSize;
		subsBtn.AdjustX = adjustX;

		subsBtn.Layout( subsX, y2, btnWd );

		// Undo
		undoBtn.TitleSize = titleSize;
		undoBtn.AdjustX = adjustX;

		undoBtn.Layout( undoX, y2, btnWd );

		double endX = (undoX + colWd);

		// End
		endBtn.TitleSize = titleSize;
		endBtn.AdjustX = adjustX;

		endBtn.Layout( endX, y2, btnWd );
	}

	// Widescreen Portrait (10:16)
	protected override void WidePortrait()
	{
		Portrait();

		toolBar.Mode = ToolBar.DisplayMode.TwoLine;
	}

	// Mobile Landscape
	protected override void MobileLandscape()
	{
		bool ios = DXDevice.IsIOS;
		Thickness safeArea = DXDevice.SafeArea();

		// Layout constants
		double ht = RecordEngine.ScoreboardHt;
		
		// Must account for safe area(s)
		Padding = new Thickness( (safeArea.Left + (ios ? 0 : (ht * 0.10))), safeArea.Top, safeArea.Right, safeArea.Bottom );

		double btnWd = (ht * 0.32);
		double btnHt = (pauseBtn.TitleHt + btnWd);

		double padX = (ht * 0.09);
		double padY = (ht * 0.066);

		double x0 = (padX * 2.0) + (ios ? 0 : safeArea.Left);
		
		double y0 = (padY * 0.5);
		double y1 = (y0 + btnHt + padY + (ios ? 0 : padY));

		double colWd = (btnWd + padX);

		double scoreWd = (ht * 0.53);
		double scoreHt = (scoreWd + 10);

		double teamFont = (ht * 0.12);
		double scoreFont = (teamFont * 3.0);
		double numberFont = (ht * 0.22);

		/* Controls */

		double liberoWd = (btnWd * (ios ? 3.0 : 2.5));
		double liberoHt = (ht - (y0 * 2));

		// Libero
		SetBounds( libero, x0, y0, liberoWd, liberoHt );

		double pauseX = (x0 + liberoWd + (padX * 2));

		// Pause
		pauseBtn.Layout( pauseX, y0, btnWd );

		// Switch
		switchBtn.Resource = "switch_horiz";
		switchBtn.Layout( pauseX, y1, btnWd );

		double rotX = (pauseX + colWd);

		// Rotation
		rotBtn.AdjustX = -5;
		rotBtn.NumberSize = numberFont;
		rotBtn.Layout( rotX, y0, btnWd );

		// Timeout A
		timeoutsABtn.AdjustX = -4;
		timeoutsABtn.NumberSize = numberFont;

		timeoutsABtn.Layout( rotX, y1, btnWd );

		double scoreXa = (rotX + colWd);
		double scoreY = (ht - scoreHt - teamFont - padY + (ios ? 0 : 5));

		// Score A
		scoreABtn.TeamSize = teamFont;
		scoreABtn.ScoreSize = scoreFont;

		scoreABtn.Layout( scoreXa, scoreY, scoreWd, scoreHt );

		double setsXa = (scoreXa + scoreWd + padX);

		// Sets A
		setsABtn.NumberSize = numberFont;
		setsABtn.Layout( setsXa, y1, btnWd );

		double possXa = (setsXa + colWd);

		double setY = (ht * 0.10);
		double setSize = (btnWd * 0.9);

		double arrowSize = (setSize - 10);
		double arrowY = (setY + ((setSize - arrowSize) / 2) - 1);

		// Possession A
		possABtn.Resource = "arrow_left";
		possABtn.Size = arrowSize;

		SetBounds( possABtn, (possXa - padX - arrowSize), arrowY, arrowSize, arrowSize );

		// Set Number
		double setX = (possXa + ((btnWd - setSize) / 2));
		double setMid = (setX + (setSize / 2));

		setBtn.NumberSize = (numberFont * 0.7);
		setBtn.Layout( setX, setY, setSize );

		// Logo
		double logoWd = (btnWd + padX);
		double logoHt = (logoWd / 2.1);

		double logoX = (setMid - (logoWd / 2));
		double logoY = (y1 + (btnHt / 2) - (logoHt / 2));

		logoBar.SetSize( logoWd, logoHt );

		SetBounds( logoBar, logoX, logoY, logoWd, logoHt );

		// Undo Auto Assist
		double autoX = (setMid - (btnWd / 2));

		autoBtn.AdjustX = -5;

		autoBtn.Layout( autoX, y1, btnWd );

		// Possession B
		double possXb = (setX + colWd);

		possBBtn.Resource = "arrow_right";
		possBBtn.Size = arrowSize;

		SetBounds( possBBtn, possXb, arrowY, arrowSize, arrowSize );

		// Sets B
		setsBBtn.NumberSize = numberFont;
		setsBBtn.Layout( possXb, y1, btnWd );

		double scoreXb = (possXb + colWd);

		// Score B
		scoreBBtn.TeamSize = teamFont;
		scoreBBtn.ScoreSize = scoreFont;

		scoreBBtn.Layout( scoreXb, scoreY, scoreWd, scoreHt );

		double subsX = (scoreXb + scoreWd + padX);

		// Subs
		subsBtn.NumberSize = numberFont;
		subsBtn.Layout( subsX, y0, btnWd );

		// Timeout B
		timeoutsBBtn.AdjustX = -4;
		timeoutsBBtn.NumberSize = numberFont;

		timeoutsBBtn.Layout( subsX, y1, btnWd );

		double endX = (subsX + colWd);

		// End
		endBtn.Layout( endX, y0, btnWd );

		// Undo
		undoBtn.Layout( endX, y1, btnWd );

		double lineupX = (endX + colWd);

		// Lineup
		lineupBtn.Layout( lineupX, y0, btnWd );

		double stackX = (lineupX - (padX / 2));
		double stackWd = liberoWd;

		// Undo Stack
		UndoStack.History.MaxNameLength = 15;
		UndoStack.History.ShowRatings = false;

		SetBounds( UndoStack, stackX, y1, stackWd, btnHt );

		// Toolbar
		toolBar.Mode = ToolBar.DisplayMode.More;

		double toolbarSize = toolBar.GetHeight();

		double toolbarX = (lineupX + btnWd + padX);
		double toolbarY = y0;

		SetBounds( toolBar, toolbarX, toolbarY, toolbarSize, toolbarSize );
	}

	// Mobile Portrait
	protected override void MobilePortrait()
	{
		bool ios = DXDevice.IsIOS;
		Thickness safeArea = DXDevice.SafeArea();

		// MUST account for notch
		Padding = new Thickness( 0, safeArea.Top, 0, 0 );

		// Layout constants
		double wd = (DXDevice.GetScreenWd() - Padding.HorizontalThickness);

		double pad = (wd * 0.0075);
		double padY = (wd * 0.025);
		
		double spaceWd = (pad * 2);
		double spaceWd2 = (spaceWd * 2);

		double btnWd = (wd * 0.10);
		double btnHt = (btnWd + subsBtn.TitleHt);

		double colWd = (btnWd + spaceWd2);

		double x0 = pad;
		double centerX = ((wd / 2) - (btnWd / 2));

		double y0 = 0;
		double y1 = (y0 + btnHt + padY);
		double y2 = (y1 + btnHt + padY);

		double setSize = (toolBar.GetHeight() + 5);

		double numberFont = (wd * 0.07);
		double teamFont = (wd * 0.040);
		double scoreFont = (wd * 0.120);

		double scoreWd = (wd * 0.17);
		double scoreHt = (scoreWd + (wd * 0.0133));

		double scoreY = (y2 + setSize + pad);
		double scoreY2 = (scoreY + teamFont + scoreHt);

		/* Controls */

		// FIRST ROW

		double midX = (wd / 2);

		// Logo
		double logoWd = (btnWd + spaceWd);
		double logoHt = (logoWd / 2.1);

		double logoX = (midX - (logoWd / 2));
		double logoY = (padY + (btnHt / 2) - (logoHt / 2));

		logoBar.IsVisible = true;
		logoBar.SetSize( logoWd, logoHt );

		SetBounds( logoBar, logoX, logoY, logoWd, logoHt );

		// Undo Auto Assist
		double autoX = (midX - (btnWd / 2));

		autoBtn.AdjustX = -5;

		autoBtn.Layout( autoX, pad, btnWd );

		// RIGHT -->

		double subsX = (centerX + colWd);

		// Subs
		subsBtn.NumberSize = numberFont;
		subsBtn.Layout( subsX, y0, btnWd );

		double endX = (subsX + colWd);

		// End
		endBtn.Layout( endX, y0, btnWd );

		// Toolbar
		toolBar.Mode = ToolBar.DisplayMode.More;

		double toolbarSize = toolBar.GetHeight();

		double toolbarX = (wd - toolbarSize - x0);
		double toolbarY = y0;

		SetBounds( toolBar, toolbarX, toolbarY, toolbarSize, toolbarSize );

		// <-- LEFT

		double rotX = (centerX - colWd);

		// Rotation
		rotBtn.AdjustX = -5;
		rotBtn.NumberSize = numberFont;
		rotBtn.Layout( rotX, y0, btnWd );

		double pauseX = (rotX - colWd);

		// Pause
		pauseBtn.Layout( pauseX, y0, btnWd );

		// SECOND ROW

		// Lineup
		lineupBtn.Layout( centerX, y1, btnWd );

		// RIGHT -->

		double setsXb = (centerX + colWd);

		// Sets B
		setsBBtn.NumberSize = numberFont;
		setsBBtn.Layout( setsXb, y1, btnWd );

		double timeXb = (setsXb + colWd);

		// Timeout B
		timeoutsBBtn.AdjustX = ios ? -2 : -3;
		timeoutsBBtn.NumberSize = numberFont;

		timeoutsBBtn.Layout( timeXb, y1, btnWd );

		double undoX = (timeXb + colWd);

		// Undo
		undoBtn.Layout( undoX, y1, btnWd );

		// <-- LEFT 

		double setsXa = (centerX - colWd);

		// Sets A
		setsABtn.NumberSize = numberFont;
		setsABtn.Layout( setsXa, y1, btnWd );

		double timeXa = (setsXa - colWd);

		// Timeout A
		timeoutsABtn.AdjustX = ios ? -2 : -3;
		timeoutsABtn.NumberSize = numberFont;

		timeoutsABtn.Layout( timeXa, y1, btnWd );

		double switchX = (timeXa - colWd);

		// Switch
		switchBtn.Resource = "switch_horiz";
		switchBtn.Layout( switchX, y1, btnWd );

		// THIRD ROW

		double liberoX = (x0 + 5);

		double liberoWd = (wd * 0.28);
		double liberoHt = (scoreY2 - y2 + 1);

		// Libero
		SetBounds( libero, liberoX, y2, liberoWd, liberoHt );

		double setX = (wd / 2) - (setSize / 2);

		double arrowSize = (setSize * 0.70);
		double arrowY = (y2 + ((setSize - arrowSize) / 2) - 1);

		double possXa = (setX - spaceWd - arrowSize);

		// Possession A
		possABtn.Resource = "arrow_left";
		possABtn.Size = arrowSize;

		SetBounds( possABtn, possXa, arrowY, arrowSize, arrowSize );

		// Set Number
		setBtn.NumberSize = (numberFont * 0.60);
		setBtn.Layout( setX, y2, setSize );

		double possXb = (setX + setSize + spaceWd);

		// Possession B
		possBBtn.Resource = "arrow_right";
		possBBtn.Size = arrowSize;

		SetBounds( possBBtn, possXb, arrowY, arrowSize, arrowSize );

		double scoreXa = (liberoX + liberoWd + spaceWd + 5);

		// Score A
		scoreABtn.TeamSize = teamFont;
		scoreABtn.ScoreSize = scoreFont;

		scoreABtn.Layout( scoreXa, scoreY, scoreWd, scoreHt );

		double scoreXb = (scoreXa + scoreWd + spaceWd);

		// Score B
		scoreBBtn.TeamSize = teamFont;
		scoreBBtn.ScoreSize = scoreFont;

		scoreBBtn.Layout( scoreXb, scoreY, scoreWd, scoreHt );

		double stackWd = (liberoWd + 5);
		double stackHt = (liberoHt / 2);

		double stackX = (scoreXb + scoreWd + spaceWd);
		double stackY = (y2 + spaceWd);

		// Undo Stack
		UndoStack.History.MaxNameLength = 15;
		UndoStack.History.ShowRatings = false;

		SetBounds( UndoStack, stackX, stackY, stackWd, stackHt );
	}
}

//
