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

using System.Text;

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

using DXLib.Data;
using DXLib.Data.Model;

using DXLib.Utils;

namespace DXLib.UI.Control.Checkbox;

/*
 * A vertical list of checkboxes with text labels. All checkboxes in the list can be either normal on/off or tri-state.
 * List data can come from either a static LUT of resource strings or from an internal object list. 
 */ 
public class DXCheckboxList : DXScroll
{
	/* Constants */
	private const double Spacing = 0;
	
	public const char Separator = ',';
	private const char Space = ' ';
	
	/* Events */
	public Action<DXCheckbox> ValueChanged { get; set; }
	public bool SuppressEvent { set => Suppress( value ); }

	/* Properties */
	public int Count => checkboxes.Count;

	// All/none checkboxes currently selected?
	public bool AllSelected => SelectedCount() == Count;
	public bool NoneSelected => SelectedCount() == 0;

	// Use indeterminate state?
	public bool IsTriState { get; set; }

	/* Fields */
	private readonly DXVerticalLayout layout;
	private readonly Dictionary<string, DXCheckbox> checkboxes;

	/* Methods */
	public DXCheckboxList()
	{
		BackgroundColor = DXColors.Light4;

		Padding = 0;
		Margin = 0;

		Horizontal = LayoutOptions.Fill;
		Vertical = LayoutOptions.Fill;

		// Vertical list
		layout = new DXVerticalLayout
		{
			Spacing = Spacing,
			
			Padding = 0,
			Margin = 0,
			
			Horizontal = LayoutOptions.Fill,
			Vertical = LayoutOptions.Fill
		};

		Content = layout;

		// Underlying controls
		checkboxes = new Dictionary<string,DXCheckbox>();
	}

	// Returns total height required to display checkbox list
	public double GetViewHt()
	{
		int count = checkboxes.Count;

		return (count * DXCheckbox.DefaultSize) + (Spacing * (count - 1));
	}

	// Sets color of all checkboxes in list
	public void SetColor( Color color )
	{
		foreach ( DXCheckbox checkbox in checkboxes.Values )
		{
			checkbox.SetColor( color ); 
		}
	}

	// Sets color of specified checkbox
	public void SetColor( string key, Color color )
	{
		checkboxes[ key ].SetColor( color );
	}

	// Sets text label of specified checkbox
	public void SetText( string key, string text )
	{
		checkboxes[ key ].Text = text;
	}

	/* Load */

	// Loads from static LUT for specified base key
	public void LoadItems( string key )
	{
		List<DXItem> items = DXString.GetLookupList( key );

		LoadItems( items );
	}

	// Loads from list of key,value items
	public void LoadItems( List<DXItem> items )
	{
		Clear();

		foreach ( DXItem item in items.Where( item => item != null ) )
		{
			AddCheckbox( item.Key, item.Value );
		}
	}

	// Loads from object list (objects must have 'ObjectName' field)
	public void LoadObjects( IList<object> list )
	{
		Clear();

		foreach ( object obj in list )
		{
			Type type = obj.GetType();

			// Key by GUID
			string key = type.GetProperty( "UniqueId" )?.GetValue( obj ) as string;
			string text = type.GetProperty( "ObjectName" )?.GetValue( obj ) as string;

			AddCheckbox( key, text, obj );
		}
	}

	// Loads from data model list
	public void LoadModels( List<DXModel> models )
	{
		Clear();

		foreach ( DXModel model in models )
		{
			AddCheckbox( model.UniqueId, model.ObjectName, model );
		}
	}

	/* Add/Remove */

	// Adds new checkbox control to end of list
	private void AddCheckbox( string key, string text, object data = null )
	{
		// Create control
		DXCheckbox checkbox = new()
		{
			Key = key,
			Text = text,
			Data = data,

			IsTriState = IsTriState,
			IsChecked = false,

			TextColor = DXColors.Dark1,
			SelectedColor = DXColors.Positive,
			DisabledColor = DXCheckbox.DefaultDisabledColor,

			HeightRequest = DXCheckbox.DefaultSize,
			
			ValueChanged = ValueChanged
		};

		checkboxes.Add( key, checkbox );

		// Append
		layout.Add( checkbox );
	}

	// Removes specified checkbox item from list
	public void RemoveItem( string key )
	{
		if ( checkboxes.TryGetValue( key, out DXCheckbox value ) )
		{
			layout.Remove(value);
			checkboxes.Remove( key ); 
		}
	}

	// Removes all items from checkbox list
	private void Clear()
	{
		checkboxes.Clear();
		layout.Clear();
	}

	/* Get Selected */

	// Determines if specified checkbox currently selected
	public bool IsSelected( string key )
	{
		return checkboxes[ key ].IsChecked == true;
	}

	// Counts total number of checkboxes currently selected
	public int SelectedCount()
	{
		return checkboxes.Values.Count( checkbox => checkbox.IsChecked != false );
	}

	// Returns list of keys corresponding to selected checkboxes (items only)
	public List<string> GetSelectedKeys()
	{
		List<string> keys = [];

		// Build list (checked and indeterminate)
		foreach ( DXCheckbox checkbox in checkboxes.Values )
		{
			if ( checkbox.IsChecked != false )
			{
				keys.Add( checkbox.Key );
			}
		}

		return keys;
	}

	// Returns list of item values corresponding to selected checkboxes
	public List<string> GetSelectedItems()
	{
		List<string> items = [];

		// Build list (checked and indeterminate)
		foreach ( DXCheckbox checkbox in checkboxes.Values )
		{
			if ( checkbox.IsChecked != false )
			{
				items.Add( checkbox.Text );
			}
		}

		return items;
	}

	// Returns list of data objects corresponding to selected checkboxes
	public List<object> GetSelectedObjects()
	{
		List<object> objects = [];

		// Build list (checked and indeterminate)
		foreach ( DXCheckbox checkbox in checkboxes.Values )
		{
			if ( (checkbox.IsChecked != false) && (checkbox.Data != null) )
			{
				objects.Add( checkbox.Data );
			}
		}

		return objects;
	}

	// Returns concatenated list of currently selected item keys
	public string GetKeyList()
	{
		// Get currently selected
		List<string> selected = GetSelectedKeys();
		int count = selected.Count;

		StringBuilder builder = new( string.Empty );

		// 'Key1, Key2, ...'
		for ( int i = 0; i < count; i++ )
		{ 
			builder.Append( selected[i].ToUpper() );

			if ( i < (count - 1) )
			{
				builder.Append( Separator ).Append( Space );
			}
		}

		return builder.ToString();
	}

	/* Set Selected */

	// (Un)checks all checkboxes in list
	public void SelectAll( bool selected )
	{
		foreach ( DXCheckbox checkbox in checkboxes.Values )
		{
			checkbox.IsChecked = selected;
		}
	}

	// (Un)checks list item for specified key
	public void SelectItem( string key, bool selected )
	{
		checkboxes[ key ].IsChecked = selected;
	}

	// Selects specified list items by key, null to clear
	public void SelectItems( IList<string> keys )
	{
		SelectAll( false );

		// Check all keys in list
		if ( keys != null )
		{
			foreach ( string key in keys )
			{
				string canonical = key.ToLower().Trim();
				
				// Keys always lowercase
				if ( checkboxes.TryGetValue( canonical, out var checkbox ) )
				{
					checkbox.IsChecked = true;
				}
			}
		}
	}

	// Selects specified list objects by key, null to clear
	public void SelectObjects( IList<string> keys )
	{
		SelectAll( false );

		// Check all keys in list
		if ( keys != null )
		{
			foreach ( string key in keys )
			{
				checkboxes[ key ].IsChecked = true;
			}
		}
	}

	/* Event Handling */

	// Temporarily suppresses event handling for all child checkboxes
	private void Suppress( bool suppress )
	{
		foreach ( DXCheckbox checkbox in checkboxes.Values )
		{
			checkbox.SuppressEvent = suppress;
		}
	}
}

//
