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

using DXLib.UI.Control;
using DXLib.UI.Gestures;
using DXLib.UI.Container;

namespace DXLib.UI.Form.Control;

/*
 * A form control used to select a color value from a spectrum of colors. The colors will be displayed in a popup
 * anchored to the control field. A swatch of the currently selected color will be shown.
 */
public class DXColorPickerField : DXFormControl
{
	/* Constants */

	// Swatch config
	private const double SwatchWd = 65;
	private const double SwatchHt = 28;

	private const double SwatchBorder = 1;
	private static readonly Color SwatchBorderColor = DXColors.Dark1;

	// Picker config
	private const double PickerWd = 400;
	private const double PickerHt = 300;
	
	/* Properties */

	// Currently selected color
	public Color PickedColor { get; set; }
	public long? PickedValue
	{
		get => GetColorValue();
		set => SetColorValue( value );
	}

	// Revert to default when no selection
	public Color DefaultColor { get; set; }
	
	// Include white in palette?
	public bool AllowWhite { set => picker.AllowWhite = value; }

	/* Fields */
	private readonly DXBorderGestures swatch;
	private readonly DXColorPicker picker;
	
	private DXPopup popup;

	/* Methods */
	public DXColorPickerField()
	{
		HasClear = true;
		
		const double borderSize = (SwatchBorder * 2);

		// Color swatch (1px border)
		swatch = new DXBorderGestures
		{
			Margin = new Thickness( 1, 2, 0, 0 ),
			CornerRadius = 5,
			
			BorderWidth = SwatchBorder,
			BorderColor = SwatchBorderColor,

			WidthRequest = (SwatchWd + borderSize),
			HeightRequest = (SwatchHt + borderSize),

			Horizontal = LayoutOptions.Start,
			Vertical = LayoutOptions.Start
		};

		swatch.Init();
		
		swatch.Tapped += OnSwatchTapped;

		// Popup color picker
		picker = new DXColorPicker
		{
			WidthRequest = PickerWd,
			HeightRequest = PickerHt,
			
			ColorPicked = OnColorPicked
		};
		
		// Default
		SetPickedColor( null );
	}

	// Returns currently selected color value, or default if none
	private long GetColorValue()
	{
		Color color = PickedColor ?? DefaultColor;

		return (color == null) ? -1 : color.ToUint();
	}
	
	// Sets underlying color
	private void SetColorValue( long? value )
	{
		PickedColor = (value == null) ? null : Color.FromUint( (uint)value );		
	}
	
	// Updates picker watch with specified color
	private void SetPickedColor( Color color )
	{
		PickedColor = color;

		bool empty = (color == null);
		
		// Update swatch
		swatch.Color = empty ? DefaultColor : color;
		swatch.BorderWidth = empty ? 0 : SwatchBorder;
		
		// Clear button only available if custom color selected
		if ( clearBtn != null )
		{
			bool picked = (PickedColor != null) && !PickedColor.Equals( DefaultColor );
			
			clearBtn.IsVisible = HasValue() && !IsDisabled && picked;
		}
	}
	
	/* Abstracts */

	// Insert in parent layout
	public override void Init()
	{
		// Update swatch
		SetPickedColor( PickedColor );

		AddControl( swatch );
	}

	// Returns underlying color as integer
	public override object GetObject()
	{
		return PickedValue;
	}

	// Placeholder NA
	public override void SetPlaceholder( bool focused )
	{}

	// Always has value
	public override bool HasValue()
	{
		return true;
	}

	// Always valid
	public override bool IsValid()
	{
		return true;
	}

	/* Event Callbacks */

	// User tapped anywhere on entry field
	private void OnSwatchTapped( object sender, MR.Gestures.TapEventArgs args )
	{
		OnFocus();

		// Show tap state
		swatch.Opacity = 0.5;

		// Init picker
		picker.SetColor( PickedColor );
		
		// Display popup
		popup = new DXPopup( "form.color", picker )
		{
			ViewWidth = PickerWd,
			ViewHeight = PickerHt,
			
			PopupClosed = OnPopupClosed
		};

		popup.ShowFromView( swatch );
	}

	// User selected color
	private void OnColorPicked( Color color )
	{
		OnChange();

		// Update
		SetPickedColor( color );
		
		popup.Hide();
			
		// Must occur last
		OnDone();
	}

	// User clearing previous selection
	protected override void OnClearTapped()
	{
		base.OnClearTapped();

		// Update swatch
		SetPickedColor( DefaultColor );
		
		OnChange();
	}

	// User cancelled selection
	private void OnPopupClosed()
	{
		swatch.Opacity = 1.0;
	}
}

//
