// TelerikLibrary.cs
// Copyright (c) 2016 Bentley Systems, Incorporated. All Rights Reserved.

using Haestad.Support.Library;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.RibbonView;

namespace Haestad.Framework.UI.Integration
{
    /// <summary>
    /// Class provides static utility methods for working with Telerik types.
    /// </summary>
    internal sealed class TelerikLibrary
    {
        #region Internal Static Methods
        internal static void SetFrameworkElementToolTip(FrameworkElement element, string toolTipTitle, string toolTipDescription)
        {
            toolTipTitle = StringLibrary.CleanTextResource(toolTipTitle);
            toolTipDescription = StringLibrary.CleanTextResource(toolTipDescription);

            if (!StringLibrary.IsBlank(toolTipTitle))
                ScreenTip.SetTitle(element, toolTipTitle);

            if (!StringLibrary.IsBlank(toolTipDescription))
                ScreenTip.SetDescription(element, toolTipDescription);
        }

        internal static RibbonLocation GetControlLocation(Control control)
        {
            if (control == null)
                throw new ArgumentNullException("control"); // I18N. OK.

            if (control is RadRibbonGroup)
                return RibbonLocation.DialogLauncher;

            RadRibbonGroup ribbonGroup = GetOwnerGroup(control);
            if (ribbonGroup != null)
            {
                if (GetOwnerTab(ribbonGroup) != null)
                    return RibbonLocation.RibbonTab;
            }

            if (control is RadMenuItem)
                return GetMenuLocation((RadMenuItem)control);

            if (IsOnQuickAccessToolbar(control))
                return RibbonLocation.QuickAccessToolbar;

            if (IsOnBackstage(control))
                return RibbonLocation.Backstage;

            // Note: <whar> Assume that if it's not anywhere else, it must be here.
            return RibbonLocation.TopTabStrip;
        }

        private static RibbonLocation GetMenuLocation(RadMenuItem menuItem)
        {
            if (menuItem is SubMenuItem)
                return GetMenuLocation(((SubMenuItem)menuItem).ParentMenuItem);

            ContextMenuEx contextMenu = menuItem.GetVisualParent<ContextMenuEx>();
            return GetControlLocation(contextMenu.OwnerButton as Control);
            // TODO 1: Need RadMenuItemEx that knows it's owner contex menu?
        }

        private static bool IsOnQuickAccessToolbar(FrameworkElement frameworkElement)
        {
            if (frameworkElement == null)
                return false;

            QuickAccessToolBar toolbar = frameworkElement.GetVisualParent<QuickAccessToolBar>();
            return (toolbar != null);
        }

        private static bool IsOnBackstage(FrameworkElement frameworkElement)
        {
            if (frameworkElement == null)
                return false;

            RadRibbonBackstage backstage = frameworkElement.GetVisualParent<RadRibbonBackstage>();
            return (backstage != null);
        }

        internal static RadRibbonTab GetOwnerTab(FrameworkElement frameworkElement)
        {
            if (frameworkElement == null)
                return null;

            if (frameworkElement.Parent is RadRibbonTab)
                return ((RadRibbonTab)frameworkElement.Parent);
            else
                return GetOwnerTab(frameworkElement.Parent as FrameworkElement);
        }

        internal static RadRibbonGroup GetOwnerGroup(FrameworkElement frameworkElement)
        {
            if (frameworkElement == null)
                return null;

            if (frameworkElement.Parent is RadRibbonGroup)
                return ((RadRibbonGroup)frameworkElement.Parent);
            else
                return GetOwnerGroup(frameworkElement.Parent as FrameworkElement);
        }

        internal static IRibbonButton GetOwnerButton(RadMenuItem menuItem)
        {
            if (menuItem == null)
                return null;

            if (menuItem is SubMenuItem && ((SubMenuItem)menuItem).ParentMenuItem != null)
                return GetOwnerButton(((SubMenuItem)menuItem).ParentMenuItem);

            if (menuItem.Parent == null)
               return null;

            IEnumerable<DependencyObject> enumerable = menuItem.GetParents();
            IEnumerator<DependencyObject> enumerator = enumerable.GetEnumerator();
            while (enumerator.MoveNext())
            {
                // Note: <whar> This must check for the type returned by NewContextMenu() below.
                // This should not change unless we run into a Telerik brick wall.
                if (enumerator.Current is ContextMenuEx)
                {
                    IRibbonButton ribbonButton = ((ContextMenuEx)enumerator.Current).OwnerButton;
                    if (ribbonButton == null)
                        TraceLibrary.WriteLine(HmTraceLevel.Release, "TelerikLibrary::GetOwnerButton(). Button not found for: " + menuItem.Name);  // I18N. OK.
                    return ribbonButton;
                }
            }

            TraceLibrary.WriteLine(HmTraceLevel.Release, "TelerikLibrary::GetOwnerButton(). Button not found for: " + menuItem.Name);  // I18N. OK.
            return null;
        }

        /// <summary>
        /// Gets the context menu associated with the specified button and creates one if required (if closedHandler is not null).
        /// </summary>
        /// <param name="button">The button to get the context menu.</param>
        /// <param name="buttonStyleInfo">The RibbonButtonStyleInfo of the button.</param>
        /// <param name="closedHandler">An optional RoutedEventHandler for the context menu's closed handler. Only needed to work around an asinine Telerik bug. If this wasn't needed, would just have a boolean "create" flag instead.</param>
        /// <returns>The RadContextMenu instance associated with the specified button. Will return null if no context menu exists and closedHandler is null.</returns>
        internal static RadContextMenu GetContextMenu(Control button, RibbonButtonStyleInfo buttonStyleInfo, RoutedEventHandler closedHandler)
        {
            RadContextMenu contextMenu = null;

            // Note: <whar> It doesn't look like this DropDownContent guy is on any common interface or base class.
            if (buttonStyleInfo.ButtonStyle == ButtonStyle.DropDownOnly)
            {
                RadRibbonDropDownButton dropDownButton = (RadRibbonDropDownButton)button;
                if (dropDownButton.DropDownContent == null && closedHandler != null)
                    dropDownButton.DropDownContent = NewContextMenu(dropDownButton, closedHandler);
                contextMenu = dropDownButton.DropDownContent as RadContextMenu;
            }
            else
            {
                RadRibbonSplitButton dropDownButton = (RadRibbonSplitButton)button;
                if (dropDownButton.DropDownContent == null && closedHandler != null)
                    dropDownButton.DropDownContent = NewContextMenu(dropDownButton, closedHandler);
                contextMenu = dropDownButton.DropDownContent as RadContextMenu;
            }

            return contextMenu;
        }

        internal static int GetCountOfTopLevelMenuItems(RadContextMenu contextMenu)
        {
            int count = 0;
            foreach (RadMenuItem menuItem in contextMenu.Items)
            {
                if (!(menuItem is RadMenuSeparatorItem))
                    count++;
            }
            return count;
        }

        // TODO 1: <whar> Should this walk into nested menus?
        internal static int GetCountOfSubMenuItems(RadMenuItem parentMenuItem)
        {
            int count = 0;
            foreach (RadMenuItem menuItem in parentMenuItem.Items)
            {
                if (!(menuItem is RadMenuSeparatorItem))
                    count++;
            }
            return count;
        }

        internal static bool GetIsVisibleSeparator(object toolBarItem)
        {
            return GetIsVisibleElement(toolBarItem) && toolBarItem is RadMenuSeparatorItem;
        }

        internal static bool GetIsInvisibleSeparator(object toolBarItem)
        {
            return !GetIsVisibleElement(toolBarItem) && toolBarItem is RadMenuSeparatorItem;
        }

        internal static bool GetIsVisibleControl(object toolBarItem)
        {
            return GetIsVisibleElement(toolBarItem) && !(toolBarItem is RadMenuSeparatorItem);
        }

        internal static bool GetIsVisibleElement(object toolBarItem)
        {
            return ((FrameworkElement)toolBarItem).Visibility == Visibility.Visible;
        }
        #endregion

        #region Private Methods
        private static RadContextMenu NewContextMenu(IRibbonButton ownerButton, RoutedEventHandler closedHandler)
        {
            ContextMenuEx contextMenu = new ContextMenuEx();
            // TODO 3: <whar> Code to address TFS#473196.
            contextMenu.Closed += closedHandler;

            contextMenu.OwnerButton = ownerButton;

            return contextMenu;
        }
        #endregion
    }
}
