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

/*
 * Represents a full horizontal stack of flyouts including selectors, ratings, and modifiers. Each flyout bar is drawn
 * vertically and is added to the end of the stack to either the left or right of the Action Menu.
 */
public class FlyoutStack
{
	/* Events */
	public Action<FlyoutBar.FlyoutType,int> Selected { get; set; }

	/* Fields */

	// Each flyout in stack
	private readonly List<FlyoutBar> flyouts;

	private readonly FlyoutBar ratings;
	private readonly FlyoutBar modifiers;
	private readonly FlyoutBar modifiers2;
	private readonly FlyoutBar selectors;

	// Flyouts can be independently turned on/off
	private bool hasRatings;
	private bool hasModifiers;
	private bool hasSelectors;

	// Current flyout direction
	private bool isRightFacing;

	// External ref
	private readonly DXAbsoluteGestures layout;

	/* Methods */
	public FlyoutStack( DXAbsoluteGestures layout, ActionMenuHandler handler, ActionMenu.MenuSize size )
	{
		this.layout = layout;

		// Allocate container
		flyouts = new List<FlyoutBar>();

		// Pass/set ratings
		ratings = new FlyoutBar
		{
			Type = FlyoutBar.FlyoutType.Rating,

			HasTitle = true,
			MaxCount = 3,
			Color = DXColors.Accent4,

			Selected = OnSelected
		};

		ratings.Init( layout, handler, size );
		flyouts.Add( ratings );

		// Action modifiers corresponding to first selector
		modifiers = new FlyoutBar
		{
			Type = FlyoutBar.FlyoutType.Modifier,

			MaxCount = 5,
			Color = DXColors.Positive,

			Selected = OnSelected
		};

		modifiers.Init( layout, handler, size );
		flyouts.Add( modifiers );

		// Action modifiers corresponding to second selector
		modifiers2 = new FlyoutBar
		{
			Type = FlyoutBar.FlyoutType.Modifier,

			MaxCount = 5,
			Color = DXColors.Positive,

			Selected = OnSelected
		};

		modifiers2.Init( layout, handler, size );
		flyouts.Add( modifiers2 );

		// Action/error selectors
		selectors = new FlyoutBar
		{
			Type = FlyoutBar.FlyoutType.Selector,

			MaxCount = 3,
			Color = DXColors.Action,

			Selected = OnSelected
		};

		selectors.Init( layout, handler, size );
		flyouts.Add( selectors );
	}

	/* Getters */

	// Returns total number of active flyouts
	public int GetCount()
	{
		int count = 0;

		if ( hasSelectors ) count++;
		if ( hasRatings ) count++;
		if ( hasModifiers ) count++;

		return count;
	}

	// Returns total width of all flyouts
	public double GetTotalWd()
	{
		double totalWd = 0;

		if ( hasRatings ) totalWd += ratings.BarWd;
		if ( hasModifiers ) totalWd += modifiers.BarWd;
		if ( hasSelectors ) totalWd += selectors.BarWd;

		return totalWd;
	}

	// Returns currently selected Rating, or default
	public int? GetRating()
	{
		return DXUtils.ConvertToInt( ratings.SelectedKey() );
	}

	// Returns currently selected Modifier, or default
	public string GetModifier()
	{
		// Could be two modifier lists
		if ( hasSelectors )
		{
			int index = selectors.SelectedIndex();

			return (index == 0) ? modifiers.SelectedKey() : modifiers2.SelectedKey();
		}

		return modifiers.SelectedKey();
	}

	// Returns currently selected Selector, if any
	public string GetSelector()
	{
		return hasSelectors ? selectors.SelectedKey() : null;
	}

	/* Setters */

	// Populates buttons on the Ratings flyout
	public void SetRatings( string title, List<DXItem> items, string key )
	{
		hasRatings = (items != null);

		if ( hasRatings )
		{
			ratings.SetTitle( title );
			ratings.SetItems( items );
		}

		ratings.SetDefault( key );
	}

	// Populates buttons on the first Modifier flyout
	public void SetModifiers( List<DXItem> items, string key )
	{
		hasModifiers = (items != null);

		if ( hasModifiers )
		{
			modifiers.SetItems( items );
		}

		modifiers.SetDefault( key );
	}

	// Populates buttons on the second Modifier flyout
	public void SetModifiers2( List<DXItem> items, string key )
	{
		if ( items != null )
		{
			modifiers2.SetItems( items );
		}

		modifiers2.SetDefault( key );
	}

	// Populates buttons on the Selector flyout
	public void SetSelectors( List<DXItem> items, string key )
	{
		// Menu does not have selectors
		if ( items == null )
		{
			hasSelectors = false;

			selectors.ClearItems();
		}
		// Has valid selectors
		else
		{
			hasSelectors = true;

			selectors.SetItems( items );
			selectors.SetDefault( key );
		}
	}

	// Determines whether menu has multiple selectors (other than error)
	public bool IsMultiSelector()
	{
		return (selectors.ButtonCount > 1);
	}

	/* Draw */

	// Draws all child flyouts
	public void Draw( bool rightFacing, double x, double y )
	{
		isRightFacing = rightFacing;

		double border = FlyoutBar.BorderSize;
		double totalWd = 0;

		// Add in correct order depending on left/right
		AddFlyouts();

		// Draw ratings, accumulate total width
		if ( hasRatings )
		{
			double barWd = (ratings.BarWd - border);
			double drawX = x + (rightFacing ? -border : -barWd);

			totalWd += barWd;

			ratings.Draw( drawX, y );
		}

		// Draw modifiers, accumulate total width
		if ( hasModifiers )
		{
			double barWd = (modifiers.BarWd - border);
			double drawX = x + (rightFacing ? (totalWd - border) : -(totalWd + barWd));

			totalWd += barWd;

			// Modifier flyouts may be different heights
			Point anchor = new( drawX, y );

			modifiers.AnchorPt = anchor;
			modifiers2.AnchorPt = anchor;

			// Draw modifiers corresponding to current selector
			if ( ShowModifiers2() )
			{
				modifiers2.Draw( drawX, y );
			}
			else
			{
				modifiers.Draw( drawX, y );
			}
		}

		// Draw selectors
		if ( hasSelectors )
		{
			double barWd = (selectors.BarWd - border);
			double drawX = x + (rightFacing ? (totalWd - border) : -(totalWd + barWd));

			selectors.Draw( drawX, y );
		}
	}

	// Adds flyouts based on left/right facing
	private void AddFlyouts()
	{
		// Must clear then add in correct shadow z-order
		RemoveFlyouts();

		// To right of menu
		if ( isRightFacing )
		{
			// Ratings
			if ( hasRatings )
			{
				ratings.Add();
			}

			// Modifiers
			if ( hasModifiers )
			{
				if ( ShowModifiers2() )
				{
					modifiers2.Add();
				}
				else
				{
					modifiers.Add();
				}
			}

			// Selectors
			if ( hasSelectors )
			{
				selectors.Add();
			}
		}
		// To left of menu
		else
		{
			int count = 0;

			// Ratings
			if ( hasRatings )
			{
				count++;
				int index = (layout.Count - count);

				ratings.Insert( index );
			}

			// Modifiers
			if ( hasModifiers )
			{
				count++;
				int index = (layout.Count - count);

				if ( ShowModifiers2() )
				{
					modifiers2.Insert( index );
				}
				else
				{
					modifiers.Insert( index );
				}
			}

			// Selectors
			if ( hasSelectors )
			{
				count++;
				int index = (layout.Count - count);

				selectors.Insert( index );
			}
		}
	}

	// Removes all flyouts from parent layout
	private void RemoveFlyouts()
	{
		foreach ( FlyoutBar flyout in flyouts )
		{
			flyout.Remove();
		}
	}

	/* Show/Hide */

	// Prepares flyouts for display (rendered but not yet shown)
	public void PreShow()
	{
		// Ratings
		if ( hasRatings )
		{
			ratings.PreShow();
		}

		// Modifiers
		if ( hasModifiers )
		{
			if ( ShowModifiers2() )
			{
				modifiers2.PreShow();
			}
			else
			{
				modifiers.PreShow();
			}
		}

		// Selectors
		if ( hasSelectors )
		{
			selectors.PreShow();
		}
	}

	// Shows all child flyouts
	public void Show()
	{
		// Ratings
		if ( hasRatings )
		{
			ratings.Show();
		}

		// Modifiers
		if ( hasModifiers )
		{
			if ( ShowModifiers2() )
			{
				modifiers2.Show();
			}
			else
			{
				modifiers.Show();
			}
		}

		// Selectors
		if ( hasSelectors )
		{
			selectors.Show();
		}
	}

	// Determines if modifiers 1 or 2 should be drawn
	private bool ShowModifiers2()
	{
		return (hasSelectors && (selectors.SelectedIndex() > 0));
	}

	// Hides all child flyouts
	public void Hide()
	{
		foreach ( FlyoutBar flyout in flyouts )
		{
			flyout.Hide();
		}
	}

	/* Event Handling */

	// Determines if touch location is anywhere on a child flyout
	public bool Contains( Point pt )
	{
		return flyouts.Any( flyout => flyout.Contains( pt ) );
	}

	// Forwards down event to child flyouts
	public void OnDown( Point pt )
	{
		foreach ( FlyoutBar flyout in flyouts )
		{
			// Only handle if in bounds
			if ( flyout.Contains( pt ) )
			{
				flyout.OnDown( pt );
				return;
			}
		}
	}

	// Forwards up event to child flyouts
	public void OnUp( Point pt )
	{
		foreach ( FlyoutBar flyout in flyouts )
		{
			// Only handle if in bounds
			if ( flyout.Contains( pt ) )
			{
				flyout.OnUp( pt );
				return;
			}
		}
	}

	// Called back when selection has changed in any child flyout
	private void OnSelected( FlyoutBar flyout, int index )
	{
		// Changing selectors changes corresponding modifier flyout
		if ( flyout == selectors )
		{
			if ( hasModifiers )
			{
				// Switch to first modifiers flyout
				if ( index == 0 )
				{
					modifiers2.Hide();

					Point pt = modifiers.AnchorPt;
					modifiers.Draw( pt.X, pt.Y );

					modifiers.PreShow();
					modifiers.Show();
				}
				// Switch to second modifiers flyout
				else if ( index == 1 )
				{
					modifiers.Remove();
					modifiers.Hide();

					Point pt = modifiers2.AnchorPt;
					modifiers2.Draw( pt.X, pt.Y );

					modifiers2.PreShow();
					modifiers2.Show();
				}
			}

			// Re-add for correct z-order
			AddFlyouts();
		}

		// Notify listener
		Selected?.Invoke( flyout.Type, index );
	}
}

//
