using System;

using Ghul.Observables;


namespace Ghul.Input
{
	/// <summary>
	/// A binder for the most important observable inputs.
	/// </summary>
	public class InputBinder : IInputBinder
	{
		/// <summary>
		/// Informs about changes to button bindings.
		/// </summary>
		public IObservable<BindingValueChange<bool>> ButtonChanges => buttonBinder;

		/// <summary>
		/// Informs about changes to axis bindings.
		/// </summary>
		public IObservable<BindingValueChange<float>> AxisChanges => axisBinder;


		/// <summary>
		/// The button binder to use.
		/// </summary>
		private IBindingObservable<bool> buttonBinder;

		/// <summary>
		/// The axis binder to use.
		/// </summary>
		private IBindingObservable<float> axisBinder;


		/// <summary>
		/// Creates a new binder for the most important observable inputs.
		/// </summary>
		/// <param name="buttonBinder">The button binder to use.</param>
		/// <param name="axisBinder">The axis binder to use.</param>
		/// <exception cref="ArgumentNullException">If buttonBinder is null.</exception>
		/// <exception cref="ArgumentNullException">If axisBinder is null.</exception>
		public InputBinder(IBindingObservable<bool> buttonBinder, IBindingObservable<float> axisBinder)
		{
			Ensure.IsNotNull(buttonBinder, nameof(buttonBinder));
			Ensure.IsNotNull(axisBinder, nameof(axisBinder));

			this.buttonBinder = buttonBinder;
			this.axisBinder = axisBinder;
		}


		/// <summary>
		/// Binds an observable button to a binding, replacing any existing binding. This causes an
		/// unsubscribe and resubscribe for all other bound button observables.
		/// </summary>
		/// <param name="binding">The binding.</param>
		/// <param name="button">The observable button to bind (null if none).</param>
		/// <exception cref="ArgumentNullException">If binding is null.</exception>
		public void BindButton(string binding, IObservable<bool> button)
		{
			buttonBinder.Bind(binding, button);
		}

		/// <summary>
		/// Binds an observable axis to a binding, replacing any existing binding. This causes an
		/// unsubscribe and resubscribe for all other bound axis observables.
		/// </summary>
		/// <param name="binding">The binding.</param>
		/// <param name="axis">The observable axis to bind (null if none).</param>
		/// <exception cref="ArgumentNullException">If binding is null.</exception>
		public void BindAxis(string binding, IObservable<float> axis)
		{
			axisBinder.Bind(binding, axis);
		}
	}
}
