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

using DXLib.Data;
using DXLib.Utils;

namespace iStatVball3;

/*
 * Implements flyout area for the EditLogView. Includes flyouts for modifying ratings, modifiers, selectors, and faults
 * for a selected Stats.
 */
public class EditLogFlyouts : DXAbsoluteGestures, ActionMenuHandler
{
	/* Events */
	public Action<FlyoutBar.FlyoutType,int> Selected { set => flyouts.Selected = value; }
	public Action FaultSelected { get; set; }

	// Access flyout values
	public int? Rating => flyouts.GetRating();
	public string Modifier => flyouts.GetModifier();
	public string Selector => flyouts.GetSelector();

	public string Fault => faultFlyout.SelectedKey();

	/* Fields */
	private readonly ActionOverlay overlay;

	private readonly FlyoutStack flyouts;
	private readonly FlyoutBar faultFlyout;

	/* Methods */
	public EditLogFlyouts()
	{
		BackgroundColor = DXColors.Dark4;
		Padding = new Thickness( 0, 5 );

		// Used for LUTs (not displayed)
		overlay = new ActionOverlay( null, null );

		const ActionMenu.MenuSize size = ActionMenu.MenuSize.Large;

		// Rating/modifier/selector
		flyouts = new FlyoutStack( this, this, size );

		// Fault
		faultFlyout = new FlyoutBar
		{
			Type = FlyoutBar.FlyoutType.FaultExt,

			MaxCount = 8,
			Color = DXColors.Warn,

			Selected = OnFaultSelected
		};

		faultFlyout.Init( this, this, size );
		faultFlyout.Add();

		// Register for events
		Down += OnDown;
		Up += OnUp;
	}

	/* Show/Hide */

	// Displays child flyout stack
	public void Show( bool fault )
	{
		Hide();

		bool tablet = DXDevice.IsTablet;
		bool portrait = DXDevice.IsPortrait();

		double x = tablet ? 40 : (portrait ? 10 : 15);
		double y = tablet ? 50 : (portrait ? 5 : 10);

		double pad = tablet ? 10 : 5;

		// Selector/modifier/rating (right facing)
		flyouts.Draw( true, x, y );
		flyouts.Show();

		// Fault
		if ( fault )
		{
			double wd = flyouts.GetTotalWd();

			faultFlyout.Draw( (x + wd + pad), y );
			faultFlyout.Show();
		}
	}

	// Removes all child flyouts
	public void Hide()
	{
		flyouts.Hide();
		faultFlyout.Hide();
	}

	/* Flyouts */

	// Populates flyout stack with specified stat
	public void SetStat( Stat stat )
	{
		// Rating/modifier/selector
		SetRatings( stat );
		SetModifiers( stat, stat.IsMultiBlock );
		SetSelectors( stat );

		// Fault
		if ( stat.IsFault )
		{
			SetFaults( stat );
		}
	}

	// Adds flyout for ratings, if applicable
	private void SetRatings( Stat stat )
	{
		int? rating = stat.Rating;

		// Check if rating applicable
		string key = GetTitleKey( stat );

		// No ratings
		if ( key == null )
		{
			flyouts.SetRatings( null, null, null );
		}
		else
		{
			// Convert 0-4 to key
			string ratingKey = rating.HasValue ? rating.ToString() : null;

			// Lookup title and list, set default
			flyouts.SetRatings( overlay.Titles[ key ], overlay.Ratings[ key ], ratingKey );
		}
	}

	// Determines rating flyout title for specified action, if any
	private static string GetTitleKey( Stat stat )
	{
		int? rating = stat.Rating;

		switch ( stat.Action )
		{
			// Serves can edit 1,2,3 ratings
			case Stats.ServeKey:
			{
				return (rating is null or > 0 and < 4) ? Stats.ServeKey : null;
			}
			// Sets can edit 2,3,4 ratings
			case Stats.SecondKey:
			{
				return ((stat.Selector == Stats.SetKey) && rating is null or > 1) ? Stats.SetKey : null;
			}
			// All pass actions can edit ratings
			case Stats.ReceiveKey:
			case Stats.DefenseKey:
			case Stats.FirstKey:
			case Stats.FreeballKey:
			case Stats.PutbackKey:
			{
				bool valid = rating is null or > 1;
				bool pass03 = Shell.Settings.IsPass03;

				// 1,2,3 or 2,3,4
				return valid ? (pass03 ? Settings.Pass03Key : Settings.Pass04Key) : null;
			}
		}

		// Nothing else has ratings
		return null;
	}

	// Adds flyout(s) for modifiers
	public void SetModifiers( Stat stat, bool multiBlock )
	{
		List<DXItem> modifiers;
		List<DXItem> modifiers2;

		string action = stat.Action;

		switch ( action )
		{
			// 2nd Ball has set/attack modifiers
			case Stats.SecondKey:
			{
				modifiers = overlay.Modifiers[ Stats.SetKey ];
				modifiers2 = overlay.Modifiers[ Stats.Attack2Key ];
				break;
			}
			// 3rd Ball has attack/free modifiers
			case Stats.ThirdKey:
			{
				modifiers = overlay.Modifiers[ Stats.Attack3Key ];
				modifiers2 = overlay.Modifiers[ Stats.FreeKey ];
				break;
			}
			// All others have only 1 modifier list
			default:
			{
				string key = RecordHistory.GetModifierKey( action, stat.Selector );

				// No modifiers for multi-block
				modifiers = multiBlock ? null : overlay.Modifiers[ key ];
				modifiers2 = null;
				break;
			}
		}

		string modifier = stat.Modifier;

		// First flyout
		flyouts.SetModifiers( modifiers, modifier );

		// Second flyout
		if ( modifiers2 != null )
		{
			flyouts.SetModifiers2( modifiers2, modifier );
		}
	}

	// Adds flyout for selectors, if applicable
	private void SetSelectors( Stat stat )
	{
		// Only 2nd/3rd ball have selectors
		if ( HasSelectors( stat ) )
		{
			flyouts.SetSelectors( overlay.Selectors[ stat.Action ], stat.Selector );
		}
		else
		{
			flyouts.SetSelectors( null, null );
		}
	}

	// Determines if specified action has selector flyout
	private static bool HasSelectors( Stat stat )
	{
		string action = stat.Action;

		switch ( action )
		{
			// 2nd ball only on error or ball to other side
			case Stats.SecondKey:
			{
				bool otherSide = ((stat.StartX < 0.5) && (stat.EndX > 0.5)) || ((stat.StartX > 0.5) && (stat.EndX < 0.5));

				return (stat.IsError || otherSide);
			}
			// 3rd ball always OK
			case Stats.ThirdKey:
			{
				return true;
			}
			// Nothing else does
			default:
			{
				return false;
			}
		}
	}

	// Adds flyout for faults
	private void SetFaults( Stat stat )
	{
		string key = RecordHistory.GetFaultKey( stat.Action, stat.Selector );

		List<DXItem> faults = overlay.Faults[ key ];

		// Populate flyout
		faultFlyout.SetItems( faults );
		faultFlyout.SetDefault( stat.Fault );
		faultFlyout.SetError( 0 );
	}

	/* Interface */

	// Unused
	public bool CanAutoSelect()
	{
		return false;
	}

	// Unused
	public void HandleSelected( bool auto )
	{}

	/* Event Callbacks */

	// Forward tap event to flyout stack
	private void OnDown( object sender, MR.Gestures.DownUpEventArgs args )
	{
		Point pt = args.Touches[0];

		flyouts.OnDown( pt );
		faultFlyout.OnDown( pt );
	}

	// Forward tap event to flyout stack
	private void OnUp( object sender, MR.Gestures.DownUpEventArgs args )
	{
		Point pt = args.Touches[0];

		flyouts.OnUp( pt );
		faultFlyout.OnUp( pt );
	}

	// User selected fault from fault flyout
	private void OnFaultSelected( FlyoutBar flyout, int index )
	{
		FaultSelected?.Invoke();
	}
}

//
