using System.Windows.Input;

namespace CommunityToolkit.Maui.Behaviors;

/// <summary>
/// 
/// </summary>
public partial class TouchBehavior : PlatformBehavior<VisualElement>
{
	/// <summary>
	/// The visual state for when the touch is unpressed.
	/// </summary>
	public const string UnpressedVisualState = "Unpressed";

	/// <summary>
	/// The visual state for when the touch is pressed.
	/// </summary>
	public const string PressedVisualState = "Pressed";

	/// <summary>
	/// The visual state for when the touch is hovered.
	/// </summary>
	public const string HoveredVisualState = "Hovered";

	readonly GestureManager gestureManager = new();

	VisualElement? element;

	internal VisualElement? Element
	{
		get => element;
		set
		{
			if (element != null)
			{
				IsUsed = false;
				gestureManager.Reset();
				SetChildrenInputTransparent(false);
			}
			gestureManager.AbortAnimations(this);
			element = value;
			if (value != null)
			{
				SetChildrenInputTransparent(ShouldMakeChildrenInputTransparent);
				IsUsed = true;
				ForceUpdateState();
			}
		}
	}

	readonly WeakEventManager weakEventManager = new();

	internal bool IsDisabled { get; set; }

	internal bool IsUsed { get; set; }

	internal bool IsAutoGenerated { get; set; }


	/// <summary>
	/// Occurs when the touch status changes.
	/// </summary>
	public event EventHandler<TouchStatusChangedEventArgs> StatusChanged
	{
		add => weakEventManager.AddEventHandler(value);
		remove => weakEventManager.RemoveEventHandler(value);
	}

	/// <summary>
	/// Occurs when the touch state changes.
	/// </summary>
	public event EventHandler<TouchStateChangedEventArgs> StateChanged
	{
		add => weakEventManager.AddEventHandler(value);
		remove => weakEventManager.RemoveEventHandler(value);
	}

	/// <summary>
	/// Occurs when the touch interaction status changes.
	/// </summary>
	public event EventHandler<TouchInteractionStatusChangedEventArgs> InteractionStatusChanged
	{
		add => weakEventManager.AddEventHandler(value);
		remove => weakEventManager.RemoveEventHandler(value);
	}

	/// <summary>
	/// Occurs when the hover status changes.
	/// </summary>
	public event EventHandler<HoverStatusChangedEventArgs> HoverStatusChanged
	{
		add => weakEventManager.AddEventHandler(value);
		remove => weakEventManager.RemoveEventHandler(value);
	}

	/// <summary>
	/// Occurs when the hover state changes.
	/// </summary>
	public event EventHandler<HoverStateChangedEventArgs> HoverStateChanged
	{
		add => weakEventManager.AddEventHandler(value);
		remove => weakEventManager.RemoveEventHandler(value);
	}

	/// <summary>
	/// Occurs when a touch gesture is completed.
	/// </summary>
	public event EventHandler<TouchCompletedEventArgs> Completed
	{
		add => weakEventManager.AddEventHandler(value);
		remove => weakEventManager.RemoveEventHandler(value);
	}

	/// <summary>
	/// Occurs when a long press gesture is completed.
	/// </summary>
	public event EventHandler<LongPressCompletedEventArgs> LongPressCompleted
	{
		add => weakEventManager.AddEventHandler(value);
		remove => weakEventManager.RemoveEventHandler(value);
	}

	/// <summary>
	/// Bindable property for <see cref="IsAvailable"/>
	/// </summary>
	public static readonly BindableProperty IsAvailableProperty = BindableProperty.Create(
		nameof(IsAvailable),
		typeof(bool),
		typeof(TouchBehavior),
		true);

	/// <summary>
	/// Gets or sets a value indicating whether the touch is available.
	/// </summary>
	public bool IsAvailable
	{
		get => (bool)GetValue(IsAvailableProperty);
		set => SetValue(IsAvailableProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="ShouldMakeChildrenInputTransparent"/>
	/// </summary>
	public static readonly BindableProperty ShouldMakeChildrenInputTransparentProperty = BindableProperty.Create(
		nameof(ShouldMakeChildrenInputTransparent),
		typeof(bool),
		typeof(TouchBehavior),
		true);

	/// <summary>
	/// Gets or sets a value indicating whether the children of the element should be made input transparent.
	/// </summary>
	public bool ShouldMakeChildrenInputTransparent
	{
		get => (bool)GetValue(ShouldMakeChildrenInputTransparentProperty);
		set => SetValue(ShouldMakeChildrenInputTransparentProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="Command"/>
	/// </summary>
	public static readonly BindableProperty CommandProperty = BindableProperty.Create(
		nameof(Command),
		typeof(ICommand),
		typeof(TouchBehavior),
		default(ICommand));

	/// <summary>
	/// Gets or sets the command to invoke when the user has completed a touch gesture.
	/// </summary>
	public ICommand Command
	{
		get => (ICommand)GetValue(CommandProperty);
		set => SetValue(CommandProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="LongPressCommand"/>
	/// </summary>
	public static readonly BindableProperty LongPressCommandProperty = BindableProperty.Create(
		nameof(LongPressCommand),
		typeof(ICommand),
		typeof(TouchBehavior),
		default(ICommand));

	/// <summary>
	/// Gets or sets the command to invoke when the user has completed a long press.
	/// </summary>
	public ICommand LongPressCommand
	{
		get => (ICommand)GetValue(LongPressCommandProperty);
		set => SetValue(LongPressCommandProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="CommandParameter"/>
	/// </summary>
	public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(
		nameof(CommandParameter),
		typeof(object),
		typeof(TouchBehavior),
		default);

	/// <summary>
	/// Gets or sets the parameter to pass to the <see cref="Command"/> property.
	/// </summary>
	public object CommandParameter
	{
		get => GetValue(CommandParameterProperty);
		set => SetValue(CommandParameterProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="LongPressCommandParameter"/>
	/// </summary>
	public static readonly BindableProperty LongPressCommandParameterProperty = BindableProperty.Create(
		nameof(LongPressCommandParameter),
		typeof(object),
		typeof(TouchBehavior),
		default);

	/// <summary>
	/// Gets or sets the parameter to pass to the <see cref="LongPressCommand"/> property.
	/// </summary>
	public object LongPressCommandParameter
	{
		get => GetValue(LongPressCommandParameterProperty);
		set => SetValue(LongPressCommandParameterProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="LongPressDuration"/>
	/// </summary>
	public static readonly BindableProperty LongPressDurationProperty = BindableProperty.Create(
		nameof(LongPressDuration),
		typeof(int),
		typeof(TouchBehavior),
		500);

	/// <summary>
	/// Gets or sets the duration of the long press in milliseconds.
	/// </summary>
	public int LongPressDuration
	{
		get => (int)GetValue(LongPressDurationProperty);
		set => SetValue(LongPressDurationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="Status"/>
	/// </summary>
	public static readonly BindableProperty StatusProperty = BindableProperty.Create(
		nameof(Status),
		typeof(TouchStatus),
		typeof(TouchBehavior),
		TouchStatus.Completed,
		BindingMode.OneWayToSource);

	/// <summary>
	/// Gets the current status of the touch.
	/// </summary>
	public TouchStatus Status
	{
		get => (TouchStatus)GetValue(StatusProperty);
		set => SetValue(StatusProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="State"/>
	/// </summary>
	public static readonly BindableProperty StateProperty = BindableProperty.Create(
		nameof(State),
		typeof(TouchState),
		typeof(TouchBehavior),
		TouchState.Normal,
		BindingMode.OneWayToSource);

	/// <summary>
	/// Gets the current state of the touch.
	/// </summary>
	public TouchState State
	{
		get => (TouchState)GetValue(StateProperty);
		set => SetValue(StateProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="InteractionStatus"/>
	/// </summary>
	public static readonly BindableProperty InteractionStatusProperty = BindableProperty.Create(
		nameof(InteractionStatus),
		typeof(TouchInteractionStatus),
		typeof(TouchBehavior),
		TouchInteractionStatus.Completed,
		BindingMode.OneWayToSource);

	/// <summary>
	/// Gets the current interaction status of the touch.
	/// </summary>
	public TouchInteractionStatus InteractionStatus
	{
		get => (TouchInteractionStatus)GetValue(InteractionStatusProperty);
		set => SetValue(InteractionStatusProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoverStatus"/>
	/// </summary>
	public static readonly BindableProperty HoverStatusProperty = BindableProperty.Create(
		nameof(Behaviors.HoverStatus),
		typeof(HoverStatus),
		typeof(TouchBehavior),
		HoverStatus.Exited,
		BindingMode.OneWayToSource);

	/// <summary>
	/// Gets the current hover status of the touch.
	/// </summary>
	public HoverStatus HoverStatus
	{
		get => (HoverStatus)GetValue(HoverStatusProperty);
		set => SetValue(HoverStatusProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoverState"/>
	/// </summary>
	public static readonly BindableProperty HoverStateProperty = BindableProperty.Create(
		nameof(Behaviors.HoverState),
		typeof(HoverState),
		typeof(TouchBehavior),
		HoverState.Normal,
		BindingMode.OneWayToSource);

	/// <summary>
	/// Gets the current hover state of the touch.
	/// </summary>
	public HoverState HoverState
	{
		get => (HoverState)GetValue(HoverStateProperty);
		set => SetValue(HoverStateProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalBackgroundColor"/>
	/// </summary>
	public static readonly BindableProperty NormalBackgroundColorProperty = BindableProperty.Create(
	nameof(NormalBackgroundColor),
	typeof(Color),
	typeof(TouchBehavior),
	null);

	/// <summary>
	/// Gets or sets the background color of the element when the touch is in the normal state.
	/// </summary>
	public Color NormalBackgroundColor
	{
		get => (Color)GetValue(NormalBackgroundColorProperty);
		set => SetValue(NormalBackgroundColorProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredBackgroundColor"/>
	/// </summary>
	public static readonly BindableProperty HoveredBackgroundColorProperty = BindableProperty.Create(
		nameof(HoveredBackgroundColor),
		typeof(Color),
		typeof(TouchBehavior),
		null);

	/// <summary>
	/// Gets or sets the background color of the element when the touch is in the hovered state.
	/// </summary>
	public Color HoveredBackgroundColor
	{
		get => (Color)GetValue(HoveredBackgroundColorProperty);
		set => SetValue(HoveredBackgroundColorProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedBackgroundColor"/>
	/// </summary>
	public static readonly BindableProperty PressedBackgroundColorProperty = BindableProperty.Create(
		nameof(PressedBackgroundColor),
		typeof(Color),
		typeof(TouchBehavior),
		null);

	/// <summary>
	/// Gets or sets the background color of the element when the touch is in the pressed state.
	/// </summary>
	public Color PressedBackgroundColor
	{
		get => (Color)GetValue(PressedBackgroundColorProperty);
		set => SetValue(PressedBackgroundColorProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalOpacity"/>
	/// </summary>
	public static readonly BindableProperty NormalOpacityProperty = BindableProperty.Create(
		nameof(NormalOpacity),
		typeof(double),
		typeof(TouchBehavior),
		1.0);


	/// <summary>
	/// Gets or sets the opacity of the element when the touch is in the normal state.
	/// </summary>
	public double NormalOpacity
	{
		get => (double)GetValue(NormalOpacityProperty);
		set => SetValue(NormalOpacityProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredOpacity"/>
	/// </summary>
	public static readonly BindableProperty HoveredOpacityProperty = BindableProperty.Create(
		nameof(HoveredOpacity),
		typeof(double),
		typeof(TouchBehavior),
		1.0);

	/// <summary>
	/// Gets or sets the opacity of the element when the touch is in the hovered state.
	/// </summary>
	public double HoveredOpacity
	{
		get => (double)GetValue(HoveredOpacityProperty);
		set => SetValue(HoveredOpacityProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedOpacity"/>
	/// </summary>
	public static readonly BindableProperty PressedOpacityProperty = BindableProperty.Create(
		nameof(PressedOpacity),
		typeof(double),
		typeof(TouchBehavior),
		1.0);

	/// <summary>
	/// Gets or sets the opacity of the element when the touch is in the pressed state.
	/// </summary>
	public double PressedOpacity
	{
		get => (double)GetValue(PressedOpacityProperty);
		set => SetValue(PressedOpacityProperty, value);
	}

	internal bool CanExecute => IsAvailable
			&& (element?.IsEnabled ?? false)
			&& (Command?.CanExecute(CommandParameter) ?? true);

	/// <summary>
	/// Bindable property for <see cref="NormalScale"/>
	/// </summary>
	public static readonly BindableProperty NormalScaleProperty = BindableProperty.Create(
		nameof(NormalScale),
		typeof(double),
		typeof(TouchBehavior),
		1.0);

	/// <summary>
	/// Gets or sets the scale of the element when the touch is in the normal state.
	/// </summary>
	public double NormalScale
	{
		get => (double)GetValue(NormalScaleProperty);
		set => SetValue(NormalScaleProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredScale"/>
	/// </summary>
	public static readonly BindableProperty HoveredScaleProperty = BindableProperty.Create(
		nameof(HoveredScale),
		typeof(double),
		typeof(TouchBehavior),
		1.0);

	/// <summary>
	/// Gets or sets the scale of the element when the touch is in the hovered state.
	/// </summary>
	public double HoveredScale
	{
		get => (double)GetValue(HoveredScaleProperty);
		set => SetValue(HoveredScaleProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedScale"/>
	/// </summary>
	public static readonly BindableProperty PressedScaleProperty = BindableProperty.Create(
		nameof(PressedScale),
		typeof(double),
		typeof(TouchBehavior),
		1.0);

	/// <summary>
	/// Gets or sets the scale of the element when the touch is in the pressed state.
	/// </summary>
	public double PressedScale
	{
		get => (double)GetValue(PressedScaleProperty);
		set => SetValue(PressedScaleProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalTranslationX"/>
	/// </summary>
	public static readonly BindableProperty NormalTranslationXProperty = BindableProperty.Create(
		nameof(NormalTranslationX),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the translation X of the element when the touch is in the normal state.
	/// </summary>
	public double NormalTranslationX
	{
		get => (double)GetValue(NormalTranslationXProperty);
		set => SetValue(NormalTranslationXProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredTranslationX"/>
	/// </summary>
	public static readonly BindableProperty HoveredTranslationXProperty = BindableProperty.Create(
		nameof(HoveredTranslationX),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the translation X of the element when the touch is in the hovered state.
	/// </summary>
	public double HoveredTranslationX
	{
		get => (double)GetValue(HoveredTranslationXProperty); set => SetValue(HoveredTranslationXProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedTranslationX"/>
	/// </summary>
	public static readonly BindableProperty PressedTranslationXProperty = BindableProperty.Create(
		nameof(PressedTranslationX),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the translation X of the element when the touch is in the pressed state.
	/// </summary>
	public double PressedTranslationX
	{
		get => (double)GetValue(PressedTranslationXProperty);
		set => SetValue(PressedTranslationXProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalTranslationY"/>
	/// </summary>
	public static readonly BindableProperty NormalTranslationYProperty = BindableProperty.Create(
		nameof(NormalTranslationY),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the translation Y of the element when the touch is in the normal state.
	/// </summary>
	public double NormalTranslationY
	{
		get => (double)GetValue(NormalTranslationYProperty); set => SetValue(NormalTranslationYProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredTranslationY"/>
	/// </summary>
	public static readonly BindableProperty HoveredTranslationYProperty = BindableProperty.Create(
		nameof(HoveredTranslationY),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the translation Y of the element when the touch is in the hovered state.
	/// </summary>
	public double HoveredTranslationY
	{
		get => (double)GetValue(HoveredTranslationYProperty); set => SetValue(HoveredTranslationYProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedTranslationY"/>
	/// </summary>
	public static readonly BindableProperty PressedTranslationYProperty = BindableProperty.Create(
		nameof(PressedTranslationY),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the translation Y of the element when the touch is in the pressed state.
	/// </summary>
	public double PressedTranslationY
	{
		get => (double)GetValue(PressedTranslationYProperty);
		set => SetValue(PressedTranslationYProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalRotation"/>
	/// </summary>
	public static readonly BindableProperty NormalRotationProperty = BindableProperty.Create(
		nameof(NormalRotation),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation of the element when the touch is in the normal state.
	/// </summary>
	public double NormalRotation
	{
		get => (double)GetValue(NormalRotationProperty);
		set => SetValue(NormalRotationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredRotation"/>
	/// </summary>
	public static readonly BindableProperty HoveredRotationProperty = BindableProperty.Create(
		nameof(HoveredRotation),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation of the element when the touch is in the hovered state.
	/// </summary>
	public double HoveredRotation
	{
		get => (double)GetValue(HoveredRotationProperty);
		set => SetValue(HoveredRotationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedRotation"/>
	/// </summary>
	public static readonly BindableProperty PressedRotationProperty = BindableProperty.Create(
		nameof(PressedRotation),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation of the element when the touch is in the pressed state.
	/// </summary>
	public double PressedRotation
	{
		get => (double)GetValue(PressedRotationProperty); set => SetValue(PressedRotationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalRotationX"/>
	/// </summary>
	public static readonly BindableProperty NormalRotationXProperty = BindableProperty.Create(
		nameof(NormalRotationX),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation X of the element when the touch is in the normal state.
	/// </summary>
	public double NormalRotationX
	{
		get => (double)GetValue(NormalRotationXProperty);
		set => SetValue(NormalRotationXProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredRotationX"/>
	/// </summary>
	public static readonly BindableProperty HoveredRotationXProperty = BindableProperty.Create(
		nameof(HoveredRotationX),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation X of the element when the touch is in the hovered state.
	/// </summary>
	public double HoveredRotationX
	{
		get => (double)GetValue(HoveredRotationXProperty);
		set => SetValue(HoveredRotationXProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedRotationX"/>
	/// </summary>
	public static readonly BindableProperty PressedRotationXProperty = BindableProperty.Create(
		nameof(PressedRotationX),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation X of the element when the touch is in the pressed state.
	/// </summary>
	public double PressedRotationX
	{
		get => (double)GetValue(PressedRotationXProperty); set => SetValue(PressedRotationXProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalRotationY"/>
	/// </summary>
	public static readonly BindableProperty NormalRotationYProperty = BindableProperty.Create(
		nameof(NormalRotationY),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation Y of the element when the touch is in the normal state.
	/// </summary>
	public double NormalRotationY
	{
		get => (double)GetValue(NormalRotationYProperty);
		set => SetValue(NormalRotationYProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredRotationY"/>
	/// </summary>
	public static readonly BindableProperty HoveredRotationYProperty = BindableProperty.Create(
		nameof(HoveredRotationY),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation Y of the element when the touch is in the hovered state.
	/// </summary>
	public double HoveredRotationY
	{
		get => (double)GetValue(HoveredRotationYProperty);
		set => SetValue(HoveredRotationYProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedRotationY"/>
	/// </summary>
	public static readonly BindableProperty PressedRotationYProperty = BindableProperty.Create(
		nameof(PressedRotationY),
		typeof(double),
		typeof(TouchBehavior),
		0.0);

	/// <summary>
	/// Gets or sets the rotation Y of the element when the touch is in the pressed state.
	/// </summary>
	public double PressedRotationY
	{
		get => (double)GetValue(PressedRotationYProperty);
		set => SetValue(PressedRotationYProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="AnimationDuration"/>
	/// </summary>
	public static readonly BindableProperty AnimationDurationProperty = BindableProperty.Create(
		nameof(AnimationDuration),
		typeof(int),
		typeof(TouchBehavior),
		default(int));

	/// <summary>
	/// Gets or sets the duration of the animation.
	/// </summary>
	public int AnimationDuration
	{
		get => (int)GetValue(AnimationDurationProperty);
		set => SetValue(AnimationDurationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="AnimationEasing"/>
	/// </summary>
	public static readonly BindableProperty AnimationEasingProperty = BindableProperty.Create(
		nameof(AnimationEasing),
		typeof(Easing),
		typeof(TouchBehavior),
		null);

	/// <summary>
	/// Gets or sets the easing of the animation.
	/// </summary>
	public Easing AnimationEasing
	{
		get => (Easing)GetValue(AnimationEasingProperty);
		set => SetValue(AnimationEasingProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedAnimationDuration"/>
	/// </summary>
	public static readonly BindableProperty PressedAnimationDurationProperty = BindableProperty.Create(
		nameof(PressedAnimationDuration),
		typeof(int),
		typeof(TouchBehavior),
		default(int));

	/// <summary>
	/// Gets or sets the duration of the pressed animation.
	/// </summary>
	public int PressedAnimationDuration
	{
		get => (int)GetValue(PressedAnimationDurationProperty);
		set => SetValue(PressedAnimationDurationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedAnimationEasing"/>
	/// </summary>
	public static readonly BindableProperty PressedAnimationEasingProperty = BindableProperty.Create(
		nameof(PressedAnimationEasing),
		typeof(Easing),
		typeof(TouchBehavior),
		null);

	/// <summary>
	/// Gets or sets the easing of the pressed animation.
	/// </summary>
	public Easing PressedAnimationEasing
	{
		get => (Easing)GetValue(PressedAnimationEasingProperty);
		set => SetValue(PressedAnimationEasingProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalAnimationDuration"/>
	/// </summary>
	public static readonly BindableProperty NormalAnimationDurationProperty = BindableProperty.Create(
		nameof(NormalAnimationDuration),
		typeof(int),
		typeof(TouchBehavior),
		default(int));

	/// <summary>
	/// Gets or sets the duration of the normal animation.
	/// </summary>
	public int NormalAnimationDuration
	{
		get => (int)GetValue(NormalAnimationDurationProperty);
		set => SetValue(NormalAnimationDurationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalAnimationEasing"/>
	/// </summary>
	public static readonly BindableProperty NormalAnimationEasingProperty = BindableProperty.Create(
		nameof(NormalAnimationEasing),
		typeof(Easing),
		typeof(TouchBehavior),
		null);

	/// <summary>
	/// Gets or sets the easing of the normal animation.
	/// </summary>
	public Easing NormalAnimationEasing
	{
		get => (Easing)GetValue(NormalAnimationEasingProperty);
		set => SetValue(NormalAnimationEasingProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredAnimationDuration"/>
	/// </summary>
	public static readonly BindableProperty HoveredAnimationDurationProperty = BindableProperty.Create(
		nameof(HoveredAnimationDuration),
		typeof(int),
		typeof(TouchBehavior),
		default(int));

	/// <summary>
	/// Gets or sets the duration of the hovered animation.
	/// </summary>
	public int HoveredAnimationDuration
	{
		get => (int)GetValue(HoveredAnimationDurationProperty);
		set => SetValue(HoveredAnimationDurationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredAnimationEasing"/>
	/// </summary>
	public static readonly BindableProperty HoveredAnimationEasingProperty = BindableProperty.Create(
		nameof(HoveredAnimationEasing),
		typeof(Easing),
		typeof(TouchBehavior),
		null);

	/// <summary>
	/// Gets or sets the easing of the hovered animation.
	/// </summary>
	public Easing HoveredAnimationEasing
	{
		get => (Easing)GetValue(HoveredAnimationEasingProperty);
		set => SetValue(HoveredAnimationEasingProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PulseCount"/>
	/// </summary>
	public static readonly BindableProperty PulseCountProperty = BindableProperty.Create(
		nameof(PulseCount),
		typeof(int),
		typeof(TouchBehavior),
		default(int));

	/// <summary>
	/// Gets or sets the number of times the element should pulse.
	/// </summary>
	public int PulseCount
	{
		get => (int)GetValue(PulseCountProperty);
		set => SetValue(PulseCountProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="IsToggled"/>
	/// </summary>
	public static readonly BindableProperty IsToggledProperty = BindableProperty.Create(
		nameof(IsToggled),
		typeof(bool?),
		typeof(TouchBehavior),
		default(bool?),
		BindingMode.TwoWay);

	/// <summary>
	/// Gets or sets a value indicating whether the element is toggled.
	/// </summary>
	public bool? IsToggled
	{
		get => (bool?)GetValue(IsToggledProperty);
		set => SetValue(IsToggledProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="DisallowTouchThreshold"/>
	/// </summary>
	public static readonly BindableProperty DisallowTouchThresholdProperty = BindableProperty.Create(
		nameof(DisallowTouchThreshold),
		typeof(int),
		typeof(TouchBehavior),
		default(int));

	/// <summary>
	/// Gets or sets the threshold for disallowing touch.
	/// </summary>
	public int DisallowTouchThreshold
	{
		get => (int)GetValue(DisallowTouchThresholdProperty);
		set => SetValue(DisallowTouchThresholdProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NativeAnimation"/>
	/// </summary>
	public static readonly BindableProperty NativeAnimationProperty = BindableProperty.Create(
		nameof(NativeAnimation),
		typeof(bool),
		typeof(TouchBehavior),
		false);

	/// <summary>
	/// Gets or sets a value indicating whether the animation should be native.
	/// </summary>
	public bool NativeAnimation
	{
		get => (bool)GetValue(NativeAnimationProperty);
		set => SetValue(NativeAnimationProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NativeAnimationColor"/>
	/// </summary>
	public static readonly BindableProperty NativeAnimationColorProperty = BindableProperty.Create(
		nameof(NativeAnimationColor),
		typeof(Color),
		typeof(TouchBehavior),
		null);

	/// <summary>
	/// Gets or sets the color of the native animation.
	/// </summary>
	public Color NativeAnimationColor
	{
		get => (Color)GetValue(NativeAnimationColorProperty);
		set => SetValue(NativeAnimationColorProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NativeAnimationRadius"/>
	/// </summary>
	public static readonly BindableProperty NativeAnimationRadiusProperty = BindableProperty.Create(
		nameof(NativeAnimationRadius),
		typeof(int),
		typeof(TouchBehavior),
		-1);

	/// <summary>
	/// Gets or sets the radius of the native animation.
	/// </summary>
	public int NativeAnimationRadius
	{
		get => (int)GetValue(NativeAnimationRadiusProperty);
		set => SetValue(NativeAnimationRadiusProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NativeAnimationShadowRadius"/>
	/// </summary>
	public static readonly BindableProperty NativeAnimationShadowRadiusProperty = BindableProperty.Create(
		nameof(NativeAnimationShadowRadius),
		typeof(int),
		typeof(TouchBehavior),
		-1);

	/// <summary>
	/// Gets or sets the shadow radius of the native animation.
	/// </summary>
	public int NativeAnimationShadowRadius
	{
		get => (int)GetValue(NativeAnimationShadowRadiusProperty);
		set => SetValue(NativeAnimationShadowRadiusProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NativeAnimationBorderless"/>
	/// </summary>
	public static readonly BindableProperty NativeAnimationBorderlessProperty = BindableProperty.Create(
		nameof(NativeAnimationBorderless),
		typeof(bool),
		typeof(TouchBehavior),
		false);

	/// <summary>
	/// Gets or sets a value indicating whether the native animation should be borderless.
	/// </summary>
	public bool NativeAnimationBorderless
	{
		get => (bool)GetValue(NativeAnimationBorderlessProperty);
		set => SetValue(NativeAnimationBorderlessProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalBackgroundImageSource"/>
	/// </summary>
	public static readonly BindableProperty NormalBackgroundImageSourceProperty = BindableProperty.Create(
		nameof(NormalBackgroundImageSource),
		typeof(ImageSource),
		typeof(TouchBehavior),
		default(ImageSource));

	/// <summary>
	/// Gets or sets the normal background image source.
	/// </summary>
	public ImageSource NormalBackgroundImageSource
	{
		get => (ImageSource)GetValue(NormalBackgroundImageSourceProperty);
		set => SetValue(NormalBackgroundImageSourceProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredBackgroundImageSource"/>
	/// </summary>
	public static readonly BindableProperty HoveredBackgroundImageSourceProperty = BindableProperty.Create(
		nameof(HoveredBackgroundImageSource),
		typeof(ImageSource),
		typeof(TouchBehavior),
		default(ImageSource));

	/// <summary>
	/// Gets or sets the hovered background image source.
	/// </summary>
	public ImageSource HoveredBackgroundImageSource
	{
		get => (ImageSource)GetValue(HoveredBackgroundImageSourceProperty);
		set => SetValue(HoveredBackgroundImageSourceProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedBackgroundImageSource"/>
	/// </summary>
	public static readonly BindableProperty PressedBackgroundImageSourceProperty = BindableProperty.Create(
		nameof(PressedBackgroundImageSource),
		typeof(ImageSource),
		typeof(TouchBehavior),
		default(ImageSource));

	/// <summary>
	/// Gets or sets the pressed background image source.
	/// </summary>
	public ImageSource PressedBackgroundImageSource
	{
		get => (ImageSource)GetValue(PressedBackgroundImageSourceProperty);
		set => SetValue(PressedBackgroundImageSourceProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="BackgroundImageAspect"/>
	/// </summary>
	public static readonly BindableProperty BackgroundImageAspectProperty = BindableProperty.Create(
		nameof(BackgroundImageAspect),
		typeof(Aspect),
		typeof(TouchBehavior),
		default(Aspect));

	/// <summary>
	/// Gets or sets the background image aspect.
	/// </summary>
	public Aspect BackgroundImageAspect
	{
		get => (Aspect)GetValue(BackgroundImageAspectProperty);
		set => SetValue(BackgroundImageAspectProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="NormalBackgroundImageAspect"/>
	/// </summary>
	public static readonly BindableProperty NormalBackgroundImageAspectProperty = BindableProperty.Create(
		nameof(NormalBackgroundImageAspect),
		typeof(Aspect),
		typeof(TouchBehavior),
		default(Aspect));

	/// <summary>
	/// Gets or sets the normal background image aspect.
	/// </summary>
	public Aspect NormalBackgroundImageAspect
	{
		get => (Aspect)GetValue(NormalBackgroundImageAspectProperty);
		set => SetValue(NormalBackgroundImageAspectProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="HoveredBackgroundImageAspect"/>
	/// </summary>
	public static readonly BindableProperty HoveredBackgroundImageAspectProperty = BindableProperty.Create(
		nameof(HoveredBackgroundImageAspect),
		typeof(Aspect),
		typeof(TouchBehavior),
		default(Aspect));

	/// <summary>
	/// Gets or sets the hovered background image aspect.
	/// </summary>
	public Aspect HoveredBackgroundImageAspect
	{
		get => (Aspect)GetValue(HoveredBackgroundImageAspectProperty);
		set => SetValue(HoveredBackgroundImageAspectProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="PressedBackgroundImageAspect"/>
	/// </summary>
	public static readonly BindableProperty PressedBackgroundImageAspectProperty = BindableProperty.Create(
		nameof(PressedBackgroundImageAspect),
		typeof(Aspect),
		typeof(TouchBehavior),
		default(Aspect));

	/// <summary>
	/// Gets or sets the pressed background image aspect.
	/// </summary>
	public Aspect PressedBackgroundImageAspect
	{
		get => (Aspect)GetValue(PressedBackgroundImageAspectProperty);
		set => SetValue(PressedBackgroundImageAspectProperty, value);
	}

	/// <summary>
	/// Bindable property for <see cref="ShouldSetImageOnAnimationEnd"/>
	/// </summary>
	public static readonly BindableProperty ShouldSetImageOnAnimationEndProperty = BindableProperty.Create(
		nameof(ShouldSetImageOnAnimationEnd),
		typeof(bool),
		typeof(TouchBehavior),
		default(bool));

	/// <summary>
	/// Gets or sets a value indicating whether the image should be set on animation end.
	/// </summary>
	public bool ShouldSetImageOnAnimationEnd
	{
		get => (bool)GetValue(ShouldSetImageOnAnimationEndProperty);
		set => SetValue(ShouldSetImageOnAnimationEndProperty, value);
	}
}
