﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace MaterialDesignThemes.Wpf
{
    internal static class TreeHelper
    {
        public static double GetVisibleWidth(FrameworkElement element, UIElement parent)
        {
            if (element == null) throw new ArgumentNullException(nameof(element));
            if (parent == null) throw new ArgumentNullException(nameof(parent));

            var location = element.TransformToAncestor(parent).Transform(new Point(0, 0));

            int width = (int) Math.Floor(element.ActualWidth);
            var hitTest = parent.InputHitTest(new Point(location.X + width, location.Y));

            if (IsAncestorTill(hitTest as FrameworkElement, element, parent))
            {
                return width;
            }

            //BinarySearch here
            int end = (int) Math.Floor(element.ActualWidth);
            int start = 0;

            while (start < end)
            {
                width = (end + start)/2;
                hitTest = parent.InputHitTest(new Point(location.X + width, location.Y));

                if (IsAncestorTill(hitTest as FrameworkElement, element, parent))
                {
                    //Speed tweak
                    hitTest = parent.InputHitTest(new Point(location.X + width + 1, location.Y));

                    if (IsAncestorTill(hitTest as FrameworkElement, element, parent))
                    {
                        start = width;
                    }
                    else
                    {
                        return width;
                    }
                }
                else
                {
                    end = width;
                }
            }


            //for (int width = (int) Math.Floor(element.ActualWidth); width >= 0; width--)
            //{
            //    var hitTest = parent.InputHitTest(new Point(location.X + width, location.Y));
            //
            //    if (hitTest == null) continue;
            //    
            //    if (IsAncestorTill(hitTest as FrameworkElement, element, parent))
            //    {
            //        return width;
            //    }
            //}

            return element.ActualWidth;
        }

        private static bool IsAncestorTill(FrameworkElement element, object ancestor, object container)
        {
            if (element == null) return false;

            FrameworkElement parent = element;

            do
            {
                if (ReferenceEquals(parent, ancestor)) return true;
                if (ReferenceEquals(parent, container)) return false;
            } while ((parent = (parent.Parent ?? VisualTreeHelper.GetParent(parent)) as FrameworkElement) != null);

            return false;
        }

        public static Visual FindMainTreeVisual(Visual visual)
        {
            DependencyObject root = null;
            DependencyObject dependencyObject = visual;

            while (dependencyObject != null)
            {
                root = dependencyObject;
                dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
            }

            return root as Visual;
        }
    }
}
