using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Valg.EVA.Skanning.Verify.Startup.VerifyBallotPaper.BallotNumber
{
    public static class FocusAdvancement
    {
        public static bool GetAdvancesByEnterKey(DependencyObject obj)
        {
            return (bool)obj.GetValue(AdvancesByEnterKeyProperty);
        }

        public static void SetAdvancesByEnterKey(DependencyObject obj, bool value)
        {
            obj.SetValue(AdvancesByEnterKeyProperty, value);
        }

        public static FocusNavigationDirection GetNavigationDirection(DependencyObject obj)
        {
            return (FocusNavigationDirection)obj.GetValue(NavigationDirectionProperty);
        }

        public static void SetNavigationDirection(DependencyObject obj, FocusNavigationDirection value)
        {
            obj.SetValue(NavigationDirectionProperty, value);
        }

        public static readonly DependencyProperty AdvancesByEnterKeyProperty =
            DependencyProperty.RegisterAttached("AdvancesByEnterKey", typeof(bool), typeof(FocusAdvancement),
                new UIPropertyMetadata(OnAdvancesByEnterKeyPropertyChanged));

        public static readonly DependencyProperty NavigationDirectionProperty =
            DependencyProperty.RegisterAttached("NavigationDirection", typeof(FocusNavigationDirection), typeof(FocusAdvancement), new PropertyMetadata(FocusNavigationDirection.Next));

        static void OnAdvancesByEnterKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = d as UIElement;
            if (element == null) return;

            if ((bool) e.NewValue)
            {
                element.KeyDown += Keydown;
                element.PreviewKeyDown += PreviewKeydown;
            }
            else
            {
                element.KeyDown -= Keydown;
                element.PreviewKeyDown -= PreviewKeydown;
            }
        }

        static void PreviewKeydown(object sender, KeyEventArgs e)
        {
            if (!e.Key.Equals(Key.Enter)) return;
            
            var comboBox = sender as ComboBox;
            if (comboBox != null && comboBox.IsDropDownOpen) comboBox.RaiseEvent(new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key){RoutedEvent = UIElement.KeyDownEvent});
        }

        static void Keydown(object sender, KeyEventArgs e)
        {
            if (!e.Key.Equals(Key.Enter)) return;
            
            var element = sender as UIElement;
            if (element != null) element.MoveFocus(new TraversalRequest(GetNavigationDirection(element)));
        }
        
        public static bool GetMovesByEnterKey(DependencyObject obj)
        {
            return (bool)obj.GetValue(MovesByEnterKeyProperty);
        }

        public static void SetMovesByEnterKey(DependencyObject obj, bool value)
        {
            obj.SetValue(MovesByEnterKeyProperty, value);
        }

        public static readonly DependencyProperty MovesByEnterKeyProperty =
            DependencyProperty.RegisterAttached("MovesByEnterKey", typeof(UIElement), typeof(FocusAdvancement),
                new UIPropertyMetadata(OnMovesByEnterKeyPropertyChanged));

        private static void OnMovesByEnterKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var handler = new FocusMover(d);
            var uiElement = e.OldValue as UIElement;
            if (uiElement != null)
                uiElement.KeyDown -= handler.KeyDown;

            var element = d as UIElement;
            if (element == null)
                return;
            element.KeyDown += handler.KeyDown;
        }

        public static bool GetMovesByMouseClick(DependencyObject obj)
        {
            return (bool)obj.GetValue(MovesByMouseClickProperty);
        }

        public static void SetMovesByMouseClick(DependencyObject obj, bool value)
        {
            obj.SetValue(MovesByMouseClickProperty, value);
        }

        public static readonly DependencyProperty MovesByMouseClickProperty =
            DependencyProperty.RegisterAttached("MovesByMouseClick", typeof(UIElement), typeof(FocusAdvancement),
                new UIPropertyMetadata(OnMovesByMouseClickPropertyChanged));

        private static void OnMovesByMouseClickPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var handler = new FocusMover(d);
            var uiElement = e.OldValue as UIElement;
            if (uiElement != null)
                uiElement.PreviewMouseUp -= handler.MouseUp;

            var element = d as UIElement;
            if (element == null)
                return;
            element.PreviewMouseUp += handler.MouseUp;
        }

        private class FocusMover
        {
            private readonly DependencyObject dependency;

            public FocusMover(DependencyObject dependency)
            {
                this.dependency = dependency;
            }

            public void KeyDown(object sender, KeyEventArgs e)
            {
                if (!e.Key.Equals(Key.Enter))
                    return;

                var radio = sender as RadioButton;
                if (radio != null)
                    radio.IsChecked = true;

                var checkBox = sender as CheckBox;
                if (checkBox != null)
                    checkBox.IsChecked = true;
                
                var element = dependency.GetValue(MovesByEnterKeyProperty) as UIElement;
                if (element != null)
                    element.Focus();
            }

            public void MouseUp(object sender, MouseButtonEventArgs e)
            {
                var radio = sender as RadioButton;
                if (radio != null)
                    radio.IsChecked = true;

                var element = dependency.GetValue(MovesByEnterKeyProperty) as UIElement;
                if (element != null)
                    element.Focus();
            }
        }
    }
}
