using System;
using Xamarin.Forms;

namespace Aurora.Design.Components.MediaPlayer
{
    public partial class Player : ContentView
    {
        public Player()
        {

            InitializeComponent();
        }

        #region SongTitle Bindable
        public static readonly BindableProperty SongTitleProperty =
            BindableProperty.Create(propertyName: "SongTitle",
            returnType: typeof(string),
            declaringType: typeof(Player),
            propertyChanged: OnSongTitlePropertyChanged);

        public string SongTitle
        {
            get
            {
                return (string)GetValue(SongTitleProperty);
            }
            set
            {
                SetValue(SongTitleProperty, value);
            }
        }

        private static void OnSongTitlePropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            Player component = bindable as Player;
            component.SongTitleLabel.Text = (string)newValue;
        }

        #endregion SongTitle Bindable

        #region ArtistName Bindable
        public static readonly BindableProperty ArtistNameProperty =
            BindableProperty.Create(propertyName: "ArtistName",
            returnType: typeof(string),
            declaringType: typeof(Player),
            propertyChanged: OnArtistNamePropertyChanged);

        public string ArtistName
        {
            get
            {
                return (string)GetValue(ArtistNameProperty);
            }
            set
            {
                SetValue(ArtistNameProperty, value);
            }
        }

        private static void OnArtistNamePropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            Player component = bindable as Player;
            component.ArtistNameLabel.Text = (string)newValue;
        }

        #endregion ArtistName Bindable

        #region PreviousButton
        public static readonly BindableProperty PreviousButtonCommandProperty =
            BindableProperty.Create(propertyName: "PreviousButtonCommand",
            returnType: typeof(Command),
            propertyChanged: OnPreviousButtonPropertyChanged,
            declaringType: typeof(Player));

        public Command PreviousButtonCommand
        {
            get
            {
                return (Command)GetValue(PreviousButtonCommandProperty);
            }
            set
            {
                SetValue(PreviousButtonCommandProperty, value);
            }
        }

        private void OnPreviousButtonClicked(object sender, EventArgs args)
        {
            if (PreviousButtonCommand.CanExecute(null))
            {
                PreviousButtonCommand.Execute(null);
                PreviousButtonCommand.ChangeCanExecute();
                PlayButtonCommand.ChangeCanExecute();
                NextButtonCommand.ChangeCanExecute();
            }
        }

        /// <summary>
        /// Event handler to hook up can execute events on property changed
        /// </summary>
        /// <param name="bindable"></param>
        /// <param name="newValue"></param>
        /// <param name="oldValue"></param>
        private static void OnPreviousButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            Player component = bindable as Player;
            if (newValue is Command)
            {
                Command cmd = newValue as Command;
                component.PreviousButton.Clicked += component.OnPreviousButtonClicked;
                cmd.CanExecuteChanged += (sender, e) => OnPreviousButtonCanExecuteChanged(sender, e, component, cmd);
            }

            if (oldValue is Command && oldValue != null)
            {
                Command cmd = newValue as Command;
                component.PreviousButton.Clicked -= component.OnPreviousButtonClicked;
                cmd.CanExecuteChanged -= (sender, e) => OnPreviousButtonCanExecuteChanged(sender, e, component, cmd);
            }
        }

        /// <summary>
        /// Can execute changed event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        /// <param name="component"></param>
        /// <param name="cmd"></param>
        private static void OnPreviousButtonCanExecuteChanged(object sender,
            EventArgs eventArgs,
            Player component,
            Command cmd)
        {
            component.NextButton.IsEnabled = cmd.CanExecute(null);
        }
        #endregion PreviousButton

        #region PlayButton
        public static readonly BindableProperty PlayButtonCommandProperty =
            BindableProperty.Create(propertyName: "PlayButtonCommand",
            returnType: typeof(Command),
            propertyChanged: OnPlayButtonPropertyChanged,
            declaringType: typeof(Player));

        public Command PlayButtonCommand
        {
            get
            {
                return (Command)GetValue(PlayButtonCommandProperty);
            }
            set
            {
                SetValue(PlayButtonCommandProperty, value);
            }
        }

        private void OnPlayButtonClicked(object sender, EventArgs args)
        {
            if (PlayButtonCommand.CanExecute(null))
            {
                PlayButtonCommand.Execute(null);
                PreviousButtonCommand.ChangeCanExecute();
                PlayButtonCommand.ChangeCanExecute();
                NextButtonCommand.ChangeCanExecute();
            }
        }

        /// <summary>
        /// Event handler to hook up can execute events on property changed
        /// </summary>
        /// <param name="bindable"></param>
        /// <param name="newValue"></param>
        /// <param name="oldValue"></param>
        private static void OnPlayButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            Player component = bindable as Player;
            if (newValue is Command)
            {
                Command cmd = newValue as Command;
                component.PlayButton.Clicked += component.OnPlayButtonClicked;
                cmd.CanExecuteChanged += (sender, e) => OnPlayButtonCanExecuteChanged(sender, e, component, cmd);
            }

            if (oldValue is Command && oldValue != null)
            {
                Command cmd = newValue as Command;
                component.PlayButton.Clicked -= component.OnPlayButtonClicked;
                cmd.CanExecuteChanged -= (sender, e) => OnPlayButtonCanExecuteChanged(sender, e, component, cmd);
            }
        }

        /// <summary>
        /// Can execute changed event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        /// <param name="component"></param>
        /// <param name="cmd"></param>
        private static void OnPlayButtonCanExecuteChanged(object sender,
            EventArgs eventArgs,
            Player component,
            Command cmd)
        {
            component.NextButton.IsEnabled = cmd.CanExecute(null);
        }
        #endregion PlayButton

        #region NextButton
        public static readonly BindableProperty NextButtonCommandProperty =
            BindableProperty.Create(propertyName: "NextButtonCommand",
            returnType: typeof(Command),
            declaringType: typeof(Player),
            propertyChanged: OnNextButtonPropertyChanged);

        public Command NextButtonCommand
        {
            get
            {
                return (Command)GetValue(NextButtonCommandProperty);
            }
            set
            {
                SetValue(NextButtonCommandProperty, value);
            }
        }

        private void OnNextButtonClicked(object sender, EventArgs args)
        {
            if (NextButtonCommand.CanExecute(null))
            {
                NextButtonCommand.Execute(null);
                PreviousButtonCommand.ChangeCanExecute();
                PlayButtonCommand.ChangeCanExecute();
                NextButtonCommand.ChangeCanExecute();
            }
        }

        /// <summary>
        /// Event handler to hook up can execute events on property changed
        /// </summary>
        /// <param name="bindable"></param>
        /// <param name="newValue"></param>
        /// <param name="oldValue"></param>
        private static void OnNextButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            Player component = bindable as Player;
            if (newValue is Command)
            {
                Command cmd = newValue as Command;
                component.NextButton.Clicked += component.OnNextButtonClicked;
                cmd.CanExecuteChanged += (sender, e) => OnNextButtonCanExecuteChanged(sender, e, component, cmd);
            }

            if (oldValue is Command && oldValue != null)
            {
                Command cmd = oldValue as Command;
                component.NextButton.Clicked -= component.OnNextButtonClicked;
                cmd.CanExecuteChanged -= (sender, e) => OnNextButtonCanExecuteChanged(sender, e, component, cmd);
            }
        }

        /// <summary>
        /// Can execute changed event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        /// <param name="component"></param>
        /// <param name="cmd"></param>
        private static void OnNextButtonCanExecuteChanged(object sender,
            EventArgs eventArgs,
            Player component,
            Command cmd)
        {

            component.NextButton.IsEnabled = cmd.CanExecute(null);
        }
        #endregion PlayButton
    }
}
