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

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

namespace DXLib.UI.Card;

/*
 * A Material card representing a data object in a list of cards managed by a parent DXCardPage.
 */
public abstract class DXCard : DXBorder
{
	/* Constants */
	private const int TapDelay = 250;
	
	// Material defaults
	public const double DefaultRadius = 10;
	public const double DefaultElevation = 4;
	
	/* Events */
	public Action<DXCard> CardTapped { get; set; }

	/* Properties */

	// Are all cards and associated forms currently locked? Typically used to make sample org and all children read-only
	public static bool GlobalLock { get; set; }

	// Optionally attach data to card
	public object Data { get; set; }

	// Is this 'Add New' card?
	public bool IsNew { get; set; }

	// Should this card respond to tap events?
	public bool IsTappable { get => tappable; set => SetTappable( value ); }

	// Show progress spinner when tapped?
	public bool ShowSpinner { get; set; }

	// Tap state opacity settings
	protected virtual double DefaultOpacity => 1.0;
	protected virtual double TapOpacity => 0.4;

	/* Inherited */
	
	// BorderColor
	// CornerRadius
	// Elevation
	// HasShadow
	
	/* Fields */
	protected readonly DXGridGestures layout;

	// State
	protected bool tappable;

	/* Methods */
	protected DXCard()
	{
		BackgroundColor = DXColors.Light4;

		// Full bleed to corners
		Padding = 0;
		Margin = 0;

		Horizontal = LayoutOptions.Fill;
		Vertical = LayoutOptions.Fill;
		
		// Simulate Material design
		CornerRadius = DefaultRadius;
		Elevation = DefaultElevation;

		BorderWidth = 1;						// Required for full bleed
		BorderColor = DXColors.Dark1;
		
        // Underlying layout
        layout = new DXGridGestures
        {
	        Padding = 0,
	        Margin = 0,
	        
            RowSpacing = 0,
            ColumnSpacing = 0,

            Horizontal = LayoutOptions.Fill,
            Vertical = LayoutOptions.Fill,
            
            // Required for full bleed images
            IsClippedToBounds = true
        };

        // Register for events
        layout.Tapped += OnLayoutTapped;

		Content = layout;

		// Defaults
		tappable = true;
		ShowSpinner = true;
	}
	
	// Child classes must define width
	public virtual double GetViewWd()
	{
		return -1;
	}

	// Child classes must define height
	public virtual double GetViewHt()
	{
		return -1;
	}

	// Can be overidden to test hit detection on child elements
	protected virtual bool IsChildBounds( Point point )
	{
		return false;
	}

	// Can be overridden to customize tappable display
	protected virtual void SetTappable( bool value )
	{
		tappable = value;
	}

	// Resets card tap state
	public virtual void Reset()
	{
		Opacity = DefaultOpacity;
		Elevation = DefaultElevation;
	}

	// Updates only child card without refreshing entire page
	public virtual void Update( DXModel model )
	{}

	// Handles tap anywhere on card (internally or can be called directly)
	public void HandleTap( Point point )
	{
		// Exclude taps on child elements
		if ( tappable && !IsChildBounds( point ) )
		{
			// Show tap via opacity/shadow change
			Opacity = TapOpacity;
			Elevation = 0;

			// Universal for all cards (unless overidden)
			if ( ShowSpinner )
			{
				DXSpinner.Start();
			}

			// Callback listener after short delay
			DXTimer.Delay( TapDelay, () =>
			{
				// Callback listener
				CardTapped?.Invoke( this );

				// Do NOT reset here
			});
		}
	}

	/* Event Callbacks */

	// Calls back registered listener after tap anywhere on card
	private void OnLayoutTapped( object sender, MR.Gestures.TapEventArgs args )
	{
		HandleTap( args.Center );
	}
}

//
