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

using DXLib.Utils;

namespace DXLib.UI.Form.Control;

/*
 * A form control used to input positive numbers. Numbers are entered via a phone-style numeric keypad. The keypad can
 * be a drop-in replacement for DXNumericField with the exception that leading zeroes are not supported.
 */
public class DXKeypadField : DXFormControl
{
	/* Events */
	public Action NumberChanged { get; set; }

	/* Properties */

	// Internal text representation of number
	private string Text { get => entryBtn.Text; set => entryBtn.Text = value; }

	// Current numeric value
	public int? Number { get => DXUtils.ConvertToInt( Text ); set => Text = value?.ToString(); }

	// Config options
	public int MinValue { get; set; }
	public int MaxValue { get; set; }

	// Internal use only
	private Color Color { set => entryBtn.TextColor = value; }

	/* Fields */
	private readonly DXTextButton entryBtn;
	private readonly DXKeypad keypad;

	/* Methods */
	public DXKeypadField()
	{
		// Form field
		entryBtn = new DXTextButton
		{
			TextColor = DXColors.Dark1,
			Font = DXFonts.Roboto,
			FontSize = 17,

			HeightRequest = 36,
			Horizontal = LayoutOptions.Fill,
			
			IsSticky = true,
			ButtonTapped = OnEntryTapped
		};

		// Popup numeric keypad
		keypad = new DXKeypad
		{
			Completed = OnCompleted
		};
	}

	// Configures keypad specific error hint text
	protected override void SetHintType( HintType type )
	{
		base.SetHintType( type );

		// Parent did not set
		if ( string.IsNullOrEmpty( hintLbl.Text ) )
		{
			string text = type switch
			{
				// 'Foo must be greater than X'
				HintType.RequiredMin => DXString.Get( "form.hint.int.minimum", Title, MinValue ),
				
				// 'Foo must be between X and Y'
				HintType.RequiredRange => DXString.Get( "form.hint.int.range", Title, MinValue, MaxValue ),
				
				_ => null
			};

			hintLbl.Text = text!;
		}
	}

	// Disables control specific components
	public override void SetDisabled( bool disabled )
	{
		base.SetDisabled( disabled );

		entryBtn.IsDisabled = disabled;
		entryBtn.Opacity = 0.3;
	}

	// Determines if current value is valid and within min-max range
	private bool IsInRange()
	{
		return DXUtils.IsValidNumber( Text ) && (Number >= MinValue) && (Number <= MaxValue);
	}

	/* Abstracts */

	// Insert in parent layout
	public override void Init()
	{
		keypad.MinValue = MinValue;
		keypad.MaxValue = MaxValue;

		AddControl( entryBtn );
	}

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

	// Placeholder only visible when not focused with no value
	public override void SetPlaceholder( bool focused )
	{
		bool hasValue = HasValue();

		// Focused never shows placeholder
		if ( focused )
		{
			Text = hasValue ? Text : null;
			Color = DXColors.Dark1;
		}
		// Unfocused shows placeholder if no value
		else if ( !hasValue )
		{
			Text = Title;
			Color = DXColors.Dark4;
		}
	}

	// Has value if number has been entered
	public override bool HasValue()
	{
		return (Number != null);
	}

	// Only valid if integer in range or optional and empty
	public override bool IsValid()
	{
		return (!IsRequired && !HasValue()) || IsInRange();
	}

	/* Event Callbacks */

	// User tapped anywhere on entry field
	private void OnEntryTapped( object data )
	{
		OnFocus();

		// Display popup
		keypad.NumberText = Text;
		keypad.Show( entryBtn, (Width * 0.40), 0 );
	}

	// Editing done
	private void OnCompleted()
	{
		bool changed = (Number != keypad.Number);
		
		// Update control
		Number = keypad.Number;

		// Callback optional listener
		if ( changed )
		{
			OnChange();
			
			NumberChanged?.Invoke();
		}

		entryBtn.Reset();
		
		// Must occur last
		OnDone();
	}
}

//
