using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Input;

namespace HandyControl.Controls
{
    public static class CommandBehavior
    {

        // UI,Handler List
        private static Dictionary<UIElement, RoutedEventHandler> handlers =new Dictionary<UIElement, RoutedEventHandler>();

        #region Command Property
        public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached(
                "Command",
                typeof(ICommand),
                typeof(CommandBehavior),
                new FrameworkPropertyMetadata()
                {
                    DefaultValue = null,
                    PropertyChangedCallback = new PropertyChangedCallback(OnCommandPropertyChanged)
                }
            );
        public static ICommand GetCommand(UIElement obj)
        {
            return (ICommand)obj.GetValue(CommandProperty);
        }
        public static void SetCommand(UIElement obj, ICommand value)
        {
            obj.SetValue(CommandProperty, value);
        }

        #endregion
        #region Event Property 
        public static readonly DependencyProperty EventProperty =
    DependencyProperty.RegisterAttached(
                "Event",
                typeof(RoutedEvent),
                typeof(CommandBehavior),
                new FrameworkPropertyMetadata()
                {
                    DefaultValue = null,
                    PropertyChangedCallback = new PropertyChangedCallback(OnEventPropertyChanged)
                }
            );
        public static RoutedEvent GetEvent(DependencyObject obj)
        {
            return (RoutedEvent)obj.GetValue(EventProperty);
        }
        public static void SetEvent(DependencyObject obj, RoutedEvent value)
        {
            obj.SetValue(EventProperty, value);
        }

        #endregion
        #region CallBacks
        private static void OnCommandPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            UIElement element = obj as UIElement;
            ICommand oldCommand = args.OldValue as ICommand;
            ICommand newCommand = args.NewValue as ICommand;
            RoutedEvent routedEvent = element.GetValue(EventProperty) as RoutedEvent;

            Detach(element, routedEvent, oldCommand);
            Attach(element, routedEvent, newCommand);
        }

        private static void OnEventPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            UIElement element = obj as UIElement;
            RoutedEvent oldEvent = args.OldValue as RoutedEvent;
            RoutedEvent newEvent = args.NewValue as RoutedEvent;
            ICommand command = element.GetValue(CommandProperty) as ICommand;

            Detach(element, oldEvent, command);
            Attach(element, newEvent, command);
        }

        #endregion
        private static void Attach(UIElement element, RoutedEvent Event, ICommand command)
        {
            if (Event != null && element != null && command != null)
            {
                RoutedEventHandler InvokeCommandHandler = new RoutedEventHandler(delegate
                {
                    command.Execute(null);
                });
                handlers.Add(element, InvokeCommandHandler);
                element.AddHandler(Event, InvokeCommandHandler);
            }
        }

        private static void Detach(UIElement element, RoutedEvent Event, ICommand command)
        {
            if (Event != null && element != null && command != null)
            {
                RoutedEventHandler handler = handlers[element];
                if (handler != null)
                {
                    element.RemoveHandler(Event, handler);
                    handlers.Remove(element);
                }
            }
        }
    }
}
