using BPA.UIControl.Commons;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace BPA.UIControl
{
    /// <summary>
    /// FrameworkElement 扩展
    /// </summary>
    public static class FrameworkElementExtension
    {
        /// <summary>
        /// 获取 root 元素
        /// </summary>
        /// <param name="dependencyObject">依赖对象</param>
        /// <returns>root 元素</returns>
        public static DependencyObject GetRoot(this DependencyObject dependencyObject)
        {
            DependencyObject result = dependencyObject;
            while ((dependencyObject = VisualTreeHelper.GetParent(dependencyObject)) != null)
            {
                result = dependencyObject;
            }
            return result;
        }

        /// <summary>
        /// 查找父元素
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="element">元素</param>
        /// <returns>父元素</returns>
        public static T FindParent<T>(this FrameworkElement element) where T : FrameworkElement
        {
            T t = default;
            while (element != null)
            {
                t = element as T;
                if (t != null)
                {
                    break;
                }
                element = element.Parent as FrameworkElement;
            }
            return t;
        }

        /// <summary>
        /// 获取最顶层父元素
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="dependencyObject">依赖对象</param>
        /// <returns>父元素</returns>
        public static T GetOldestParent<T>(this DependencyObject dependencyObject) where T : DependencyObject
        {
            T t;
            while ((t = VisualTreeHelper.GetParent(dependencyObject) as T) != null)
            {
                dependencyObject = t;
            }
            return dependencyObject.AssertCast<T>();
        }

        /// <summary>
        /// 尝试查找资源
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="root">元素</param>
        /// <param name="resourceKey">资源 key</param>
        /// <returns>资源</returns>
        internal static T TryFindResourceUp<T>(this FrameworkElement root, object resourceKey)
        {
            if (root != null && root.Resources.Contains(resourceKey))
            {
                object obj = root.Resources[resourceKey];
                if (!(obj is T))
                {
                    return default;
                }
                return (T)obj;
            }
            else
            {
                if (root.Parent is FrameworkElement)
                {
                    return ((FrameworkElement)root.Parent).TryFindResourceUp<T>(resourceKey);
                }
                return default;
            }
        }

        /// <summary>
        /// 获取子元素
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="parent">父元素</param>
        /// <returns>子元素</returns>
        public static T TryGetChildPartFromVisualTree<T>(this FrameworkElement parent) where T : FrameworkElement
        {
            return parent.TryGetChildFromVisualTree<T>(null);
        }

        /// <summary>
        /// 根据 Name 获取子元素
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="parent">父元素</param>
        /// <param name="partName">名称</param>
        /// <returns>子元素</returns>
        public static T TryGetChildPartFromVisualTree<T>(this FrameworkElement parent, string partName) where T : FrameworkElement
        {
            ValidateArgument.NotNullOrEmpty(partName, "partName");
            return parent.TryGetChildFromVisualTree<T>((FrameworkElement childControl) => childControl.Name == partName);
        }

        /// <summary>
        /// 根据 AutomationId 获取子元素
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="parent">父元素</param>
        /// <param name="automationId">自动 ID</param>
        /// <returns>子元素</returns>
        internal static T TryGetChildWithAutomationIdFromVisualTree<T>(this FrameworkElement parent, string automationId) where T : FrameworkElement
        {
            ValidateArgument.NotNullOrEmpty(automationId, "automationId");
            return parent.TryGetChildFromVisualTree<T>((FrameworkElement childControl) => AutomationProperties.GetAutomationId(childControl) == automationId);
        }

        /// <summary>
        /// VisualTree 获取子元素
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="parent">父元素</param>
        /// <param name="evaluateChild">子元素表达式</param>
        /// <returns>子元素</returns>
        internal static T TryGetChildFromVisualTree<T>(this FrameworkElement parent, Func<FrameworkElement, bool> evaluateChild) where T : FrameworkElement
        {
            ValidateArgument.NotNull(parent, "parent");
            FrameworkElement frameworkElement = null;
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                frameworkElement = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
                if (frameworkElement != null && (frameworkElement is T && (evaluateChild == null || evaluateChild.Invoke(frameworkElement)) || (frameworkElement = frameworkElement.TryGetChildFromVisualTree<T>(evaluateChild)) != null))
                {
                    break;
                }
            }

            return frameworkElement as T;
        }

        /// <summary>
        /// 获取父元素
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="child">子元素</param>
        /// <returns>父元素</returns>
        public static T TryGetParentFromVisualTree<T>(this FrameworkElement child) where T : FrameworkElement
        {
            if (child != null && !(child is T))
            {
                return (VisualTreeHelper.GetParent(child) as FrameworkElement).TryGetParentFromVisualTree<T>();
            }

            return (T)(object)child;
        }

        /// <summary>
        /// 获取父元素
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="child">子元素</param>
        /// <returns>父元素</returns>
        public static T TryGetParentFromVisualTree<T>(this DependencyObject child) where T : DependencyObject
        {
            if (child != null && !(child is T))
            {
                return VisualTreeHelper.GetParent(child).TryGetParentFromVisualTree<T>();
            }

            return (T)(object)child;
        }

        /// <summary>
        /// 遍历子元素
        /// </summary>
        /// <param name="dependencyObj">依赖对象</param>
        /// <param name="childAction">变量方法</param>
        internal static void ForEachVisualChild(this DependencyObject dependencyObj, Action<DependencyObject> childAction)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(dependencyObj, i);
                child.ForEachVisualChild(childAction);
                childAction.Invoke(child);
            }
        }

        /// <summary>
        /// 是否包含子对象
        /// </summary>
        /// <param name="parent">父元素</param>
        /// <param name="dependencyObj">依赖对象</param>
        /// <returns>结果</returns>
        public static bool ContainsChild(this DependencyObject parent, DependencyObject dependencyObj)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(parent, i);
                if (child == dependencyObj || child.ContainsChild(dependencyObj))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 获取依赖属性的值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="reference">对象</param>
        /// <param name="property">属性</param>
        /// <returns>属性的值</returns>
        public static T GetAncestorValue<T>(this DependencyObject reference, DependencyProperty property)
        {
            T result = default;
            while (reference != null && (result = ObjectExtension.AssertCast<T>(reference.GetValue(property))) == null)
            {
                DependencyObject parent = VisualTreeHelper.GetParent(reference);
                if (parent == null)
                {
                    FrameworkElement frameworkElement = reference as FrameworkElement;
                    if (frameworkElement != null)
                    {
                        parent = frameworkElement.Parent;
                    }
                }

                reference = parent;
            }

            return result;
        }
    }
}
