// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.  

#if RIBBON_IN_FRAMEWORK
namespace System.Windows.Controls.Ribbon
#else
namespace Microsoft.Windows.Controls.Ribbon
#endif
{
    using System;
    using System.Windows;
    using System.Windows.Automation.Peers;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;
    using System.Windows.Threading;
#if RIBBON_IN_FRAMEWORK
    using System.Windows.Controls.Ribbon.Primitives;
#else
    using Microsoft.Windows.Automation.Peers;
    using Microsoft.Windows.Controls.Ribbon.Primitives;
#endif

    /// <summary>
    ///     The ItemsControl which hosts TabHeaders in Ribbon.
    /// </summary>
    public class RibbonTabHeaderItemsControl : ItemsControl
    {
        #region Constructors

        static RibbonTabHeaderItemsControl()
        {
            Type ownerType = typeof(RibbonTabHeaderItemsControl);
            ItemsPanelProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(new ItemsPanelTemplate(new FrameworkElementFactory(typeof(RibbonTabHeadersPanel)))));
            DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(typeof(RibbonTabHeaderItemsControl)));
            FocusableProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(false));
            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(KeyboardNavigationMode.Once));
            KeyboardNavigation.ControlTabNavigationProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(KeyboardNavigationMode.Once));
        }

        #endregion

        #region Properties

#if RIBBON_IN_FRAMEWORK
        protected internal override bool HandlesScrolling
#else
        protected override bool HandlesScrolling
#endif
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        ///     Items panel instance of this ItemsControl
        /// </summary>
        internal Panel InternalItemsHost
        {
            get
            {
                return _itemsHost;
            }
            set
            {
                _itemsHost = value;
            }
        }

        #endregion

        #region Protected Methods

        public override void OnApplyTemplate()
        {
            // If a new template has just been generated then 
            // be sure to clear any stale ItemsHost references
            if (InternalItemsHost != null && !this.IsAncestorOf(InternalItemsHost))
            {
                InternalItemsHost = null;
            }

            base.OnApplyTemplate();
        }
        
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new RibbonTabHeaderItemsControlAutomationPeer(this);
        }

        /// <summary>
        ///     Returns a new instance of RibbonTabHeader as the item container
        /// </summary>
        /// <returns></returns>
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new RibbonTabHeader();
        }

        /// <summary>
        ///     Prepares an item container before its use.
        /// </summary>
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            RibbonTabHeader header = element as RibbonTabHeader;
            if (header != null)
            {
                header.PrepareRibbonTabHeader();
            }
        }

        /// <summary>
        ///     An item is its own container if it is a RibbonTabHeader
        /// </summary>
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return (item is RibbonTabHeader);
        }

        #endregion
        
        #region Internal Methods

        /// <summary>
        ///     Helper method which scrolls item at given index into view.
        /// </summary>
        /// <param name="index"></param>
        internal void ScrollIntoView(int index)
        {
            ArgumentOutOfRangeException.ThrowIfNegative(index);
            ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Items.Count);

            if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            {
                ScrollContainerIntoView(index);
            }
            else
            {
                // The items aren't generated, try at a later time
                Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(ScrollContainerIntoView), index);
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        ///     Helper method which scrolls item at given index into view.
        ///     Can be used as a dispatcher operation.
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        private object ScrollContainerIntoView(object arg)
        {
            int index = (int)arg;
            FrameworkElement element = ItemContainerGenerator.ContainerFromIndex(index) as FrameworkElement;
            if (element != null)
            {
                element.BringIntoView();

                // If there is a margin on TabHeader on the end, BringIntoView call
                // may not scroll to the end. Explicitly scroll to end in such cases.
                IScrollInfo scrollInfo = InternalItemsHost as IScrollInfo;
                if (scrollInfo != null)
                {
                    ScrollViewer scrollViewer = scrollInfo.ScrollOwner;
                    if (scrollViewer != null)
                    {
                        Ribbon ribbon = RibbonControlService.GetRibbon(this);
                        if (ribbon != null)
                        {
                            int displayIndex = ribbon.GetTabDisplayIndexForIndex(index);
                            if (displayIndex == 0)
                            {
                                // If this tab header is the first tab header displayed
                                // then scroll to the left end.
                                scrollViewer.ScrollToLeftEnd();
                            }
                            else if (ribbon.GetTabIndexForDisplayIndex(displayIndex + 1) < 0)
                            {
                                // If this tab header is the last tab header displayed
                                // then scroll to the right end.
                                scrollViewer.ScrollToRightEnd();
                            }
                        }
                    }
                }
            }
            return null;
        }

        #endregion

        #region Private Data

        private Panel _itemsHost; // ItemsPanel instance for this ItemsControl

        #endregion
    }
}
