using System.Windows;
using System.Windows.Media;

namespace Valg.EVA.Skanning.Verify.Startup.VerifyBallotPaper
{
    public class ActiveMainControlManager : DependencyObject
    {
        public static readonly DependencyProperty IsMainControlProperty = DependencyProperty.RegisterAttached
            ("IsMainControl",
            typeof(bool),
            typeof(ActiveMainControlManager),
            new UIPropertyMetadata(false, OnIsMainControlChanged));

        private enum SelectionCriteria { LastItem, FirstItem }

        private static UIElement ActiveControl { get; set; }

        public static bool GetIsMainControl(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsMainControlProperty);
        }

        public static void SetIsMainControl(DependencyObject obj, bool value)
        {
            obj.SetValue(IsMainControlProperty, value);
        }

        public static void SetLastElementActive()
        {
            SetElementActive(SelectionCriteria.LastItem);
        }

        public static void SetFirstElementActive()
        {
            SetElementActive(SelectionCriteria.FirstItem);
        }

        private static void OnIsMainControlChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var element = obj as UIElement;
            if (element != null)
            {
                ActiveControl = element;
            }
        }

        private static void SetElementActive(SelectionCriteria selectionCriteria)
        {
            if (ActiveControl != null)
            {
                var itemsControl = ActiveControl as System.Windows.Controls.ItemsControl;

                if (itemsControl != null)
                {
                    var itemToGiveFocus = GetItemToGiveFocus(itemsControl, selectionCriteria);

                    var frameworkElement = itemToGiveFocus as FrameworkElement;

                    if (frameworkElement != null && HasCorrectTagName("FocusElement", frameworkElement))
                    {                        
                        frameworkElement.Focus();
                    }
                    else
                    {
                        SetFocusOnChildElement(itemsControl, itemToGiveFocus);
                    }
                }
            }
        }

        private static object GetItemToGiveFocus(System.Windows.Controls.ItemsControl itemsControl, SelectionCriteria selectionCriteria)
        {
            object item;
            switch (selectionCriteria)
            {
                case SelectionCriteria.FirstItem:
                    item = itemsControl.Items.GetItemAt(0);
                    break;

                case SelectionCriteria.LastItem:
                    item = itemsControl.Items.GetItemAt(itemsControl.Items.Count - 1);
                    break;

                default:
                    item = null;
                    break;
            }
            return item;
        }

        private static void SetFocusOnChildElement(System.Windows.Controls.ItemsControl itemsControl, object itemToGiveFocus)
        {
            var container = itemsControl.ItemContainerGenerator.ContainerFromItem(itemToGiveFocus) as FrameworkElement;
            if (container != null)
            {
                var focusElement = FindChild<UIElement>(container, "FocusElement");
                if (focusElement != null)
                {                    
                    focusElement.Focus();
                }
            }
        }

        private static T FindChild<T>(DependencyObject parent, string tagName)
           where T : DependencyObject
        {
            
            if (parent == null) return null;

            T foundChild = null;

            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                
                T childType = child as T;
                if (childType == null)
                {
                    
                    foundChild = FindChild<T>(child, tagName);

                    
                    if (foundChild != null) break;
                }
                else if (!string.IsNullOrEmpty(tagName))
                {
                    var frameworkElement = child as FrameworkElement;
                    
                    if (HasCorrectTagName(tagName, frameworkElement))
                    {
                        
                        foundChild = (T)child;
                        break;
                    }
                    else
                    {
                        foundChild = FindChild<T>(child, tagName);
                    }
                }
                else
                {
                    
                    foundChild = (T)child;
                    break;
                }
            }

            return foundChild;
        }

        private static bool HasCorrectTagName(string tagName, FrameworkElement frameworkElement)
        {
            return frameworkElement != null && frameworkElement.Tag != null && frameworkElement.Tag.ToString() == tagName;
        }
    }
}
