using System;
using Chernobyl.StateMachine;

namespace Chernobyl
{
    /// <summary>
    /// Used to represent a type whose functionality can be enabled/disabled.
    /// </summary>
    public interface IEnableable
    {
        /// <summary>
        /// Active if the functionality of the object is enabled, inactive if 
        /// otherwise.
        /// </summary>
        IState Enabled { get; }
    }

    /// <summary>
    /// A class that holds extension methods for <see cref="IEnableable"/> types.
    /// </summary>
    public static class EnableableExtensions
    {
        /// <summary>
        /// When invoked this method will enable the <see cref="IEnableable"/> 
        /// instance.
        /// </summary>
        /// <param name="enableable">The instance that is to be enabled.</param>
        public static void Enable(this IEnableable enableable)
        {
            enableable.Enabled.ParentState = new State();
        }

        /// <summary>
        /// An event handler that can be added to an event.  This method performs
        /// the same operation as <see cref="Enable(IEnableable)"/> when invoked.
        /// </summary>
        /// <param name="enableable">The instance that is to be enabled.</param>
        /// <param name="sender">The instance that generated the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the 
        /// event data.</param>
        public static void Enable(this IEnableable enableable, object sender, EventArgs e)
        {
            enableable.Enable();
        }

        /// <summary>
        /// When invoked this method will disable the <see cref="IEnableable"/> 
        /// instance.
        /// </summary>
        /// <param name="enableable">The instance that is to be disabled.</param>
        public static void Disable(this IEnableable enableable)
        {
            enableable.Enabled.ParentState = null;
        }

        /// <summary>
        /// An event handler that can be added to an event. This method performs
        /// the same operation as <see cref="Disable(IEnableable)"/> when invoked.
        /// </summary>
        /// <param name="enableable">The instance that is to be disabled.</param>
        /// <param name="sender">The instance that generated the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the 
        /// event data.</param>
        public static void Disable(this IEnableable enableable, object sender, EventArgs e)
        {
            enableable.Disable();
        }

        /// <summary>
        /// When invoked this method will disable the <see cref="IEnableable"/> 
        /// instance if it is enabled and enable it if it is disabled.
        /// </summary>
        /// <param name="enableable">The instance that is to be disabled or
        /// enabled.</param>
        public static void Toggle(this IEnableable enableable)
        {
            if (enableable.Enabled.IsActive())
                enableable.Disable();
            else
                enableable.Enable();
        }

        /// <summary>
        /// An event handler that can be added to an event. This method performs
        /// the same operation as <see cref="Toggle(IEnableable)"/> when invoked.
        /// </summary>
        /// <param name="enableable">The instance that is to be disabled or
        /// enabled.</param>
        /// <param name="sender">The instance that generated the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the 
        /// event data.</param>
        public static void Toggle(this IEnableable enableable, object sender, EventArgs e)
        {
            enableable.Toggle();
        }
    }
}