// Interfaces.cs
// Copyright (c) 2018 Bentley Systems, Incorporated. All Rights Reserved.

using Haestad.Framework.Application;
using Haestad.Support.Storage;
using Haestad.Support.Support;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using System.Windows.Input;
using Telerik.Windows;
using Telerik.Windows.Controls;

namespace Haestad.Framework.UI.Integration
{
    #region Public Interfaces

    #region IParentFormUI
    public interface IParentFormUI
    {
        Form ParentForm { get; set; }
    }
    #endregion

    #region IRibbonUICommandFactory
    /// <summary>
    /// Defines the contract for factories that are capable of creating new commands.
    /// When factories create commands, they MUST cache those commands. There should only
    /// be a single instance of any unique command.
    /// </summary>
    public interface IRibbonUICommandFactory
    {
        IRibbonUICommand GetUICommand(string commandName, params object[] context);
    }
    #endregion

    #region IRibbonServices
    /// <summary>
    /// An interface that provides access Ribbon features, but without requiring direct references to the Ribbon itself.
    /// Implemented by the direct owner of the RadRibbonView instance.
    /// At the very least encourages careful consideration of which Ribbon features need to be directly accessed.
    /// In theory an alternate ribbon implementation could sit behind this interface.
    /// Extend this interface with additional support judiciously.
    /// </summary>
    public interface IRibbonServices
    {
        /// <summary>
        /// Resets all user customized settings in the Ribbon to their default values.
        /// Does NOT apply reset values for element settings managers that are instantiated by client code (such as the QATButtonManager).
        /// In that case the client code needs to handle OnResetRibbonSettings and use the appropriate TelerikWPFRibbonBuilder method to apply the changes.
        /// </summary>
        void ResetToDefaults();

        /// <summary>
        /// And event that indicates the necessity for a client to apply updates for the element managers that it manages.
        /// </summary>
        event EventHandler<EventArgs> OnResetRibbonSettings;

        /// <summary>
        /// Enables or disables the entire ribbon.
        /// </summary>
        bool IsRibbonEnabled { get; set; }

        /// <summary>
        /// Gets or sets whether the ribbon backstage is open.
        /// </summary>
        bool IsBackstageOpen { get; set; }

        /// <summary>
        /// Gets or sets whether the backstage can be opened by the user.
        /// </summary>
        bool CanBackStageBeOpened { get; set; }

        /// <summary>
        /// Enables or disable hot keys.
        /// The mechanism used for hot keys seems to have a performance down side when the UI thread is locked up (e.g., during compute),
        /// so this property should be set to false when locking down for a compute and to true afterwards.
        /// </summary>
        /// <param name="enable">Whether or not to enable hot keys or disable them. By default they are enabled.</param>
        void EnableHotKeys(bool enable);

        /// <summary>
        /// Gets the ribbon dispatcher element.
        /// </summary>
        FrameworkElement DispatcherElement { get; }

        /// <summary>
        ///  Exposes the event for the ribbon application menu open state changing.
        /// </summary>
        event EventHandler<RadRoutedEventArgs> ApplicationMenuOpenStateChanged;

        /// <summary>
        /// Returns the well known unique name for a DropDownToggle button's default command.
        /// </summary>
        string GetDefaultCommandNameForDropDownToggleButton(string buttonName);

        /// <summary>
        /// Exposes an event that is triggered every time the ribbon tab is changed to a new tab.
        /// </summary>
        event EventHandler<TabChangeEventArgs> RibbonTabChanged;
    }
    #endregion

    #region IRibbonCallbacks
    public interface IRibbonCallbacks
    {
        /// <summary>
        /// Answers the parent form handle.
        /// </summary>
        IntPtr ParentFormHandle { get; }

        /// <summary>
        /// Answers whether the parent form is in lock down.
        /// </summary>
        bool IsParentFormInLockDown { get; }

        /// <summary>
        /// Answers the product help command.
        /// </summary>
        ICommand GetProductHelpCommand();

        /// <summary>
        /// Answers the ribbon UI command, requested by name.
        /// </summary>
        /// <param name="commandName">The well known name of the command.</param>
        /// <returns>The command if it exists, else null.</returns>
        IRibbonUICommand GetUICommand(string commandName);

        /// <summary>
        /// Answers an Icon resource for the specified standard graphic resource key.
        /// </summary>
        Icon GetIcon(string standardGraphicResourceKey);

        /// <summary>
        /// Answers Ribbon storage elements; anything that has customization settings that are expected to be user configurable.
        /// </summary>
        IList<IStorageElement> GetRibbonStorageElements();

        /// <summary>
        /// Answers the storage write context for the ribbon settings file.
        /// </summary>
        IStorageWriteContext GetStorageWriteContext();

        /// <summary>
        /// Answers the local user settings directory.
        /// </summary>
        string LocalUserSettingsDirectory { get; }

        /// <summary>
        /// Clients should implement and do everything necessary to layout the ribbon at application start up.
        /// </summary>
        void LayoutRibbon();

        ApplicationEventChannel ApplicationEventChannel { get; }
    }
    #endregion

    #region IRibbonUICommand
    /// <summary>
    /// Interface defines the contract for Ribbon UI Commands that can be used with any appropriate Ribbon UIElement.
    /// These include Quick Access Toolbar buttons, Main Ribbon buttons or Ribbon menu items.
    /// A single IRibbonUICommand can be associated with more than one Ribbon UIElement.
    /// </summary>
    public interface IRibbonUICommand : INamable, ICommand, ILabeled
    {
        string ToolTipTitle { get; }
        string ToolTipDescription { get; }
        string GraphicResourceKey { get; }
        string LargeGraphicResourceKey { get; }

        RibbonHotKey HotKey { get; }

        string GetCleanLabel();
        string GetCleanToolTipTitle();
        string GetCleanToolTipDescription();

        /// <summary>
        /// A flag used by the builder to control tooltips for the UI command.
        /// </summary>
        bool UseHotKeyInToolTip { get; set; }
    }
    #endregion

    #region IRibbonLinkedUICommand
    /// <summary>
    /// Interface defines a contract that Ribbon commands can implement if they wish to know which Ribbon UI elements are linked to the command.
    /// Allows implementation of extended behaviors for coordinating multiple UI elements linked to the same command.
    /// This interface may optionally be implemented by objects that also implement IRibbonUICommand.
    /// </summary>
    public interface IRibbonLinkedUICommand
    {
        /// <summary>
        /// Defines a method whereby a client of the command can get a list of linked Ribbon UI elements of a certain type (or types).
        /// </summary>
        /// <param name="linkedElementTypes">linkedElementTypes; a bit flag that defines which Ribbon UI element types are returned.</param>
        /// <returns>A list of the specified FrameworkElement elements.</returns>
        IList<FrameworkElement> GetLinkedElements(RibbonUICommandLinkedElementTypes linkedElementTypes);

        void AddLinkedRegularButton(RadRibbonButton button);
        void AddLinkedToggleButton(RadRibbonToggleButtonEx button);
        void AddLinkedDropDownOnlyButton(RadRibbonDropDownButton button);
        void AddLinkedDropDownButton(RadRibbonSplitButton button);
        void AddLinkedDropDownToggleButton(RadRibbonToggleSplitButton button);
        void AddLinkedMenu(RadMenuItem menuItem);
        void AddLinkedCheckedMenu(RadMenuItem menuItem);
        void AddLinkedToggleMenu(RadToggleMenuItem menuItem);
        void AddLinkedRibbonGroup(RadRibbonGroup ribbonGroup);
        void AddLinkedBackstageItem(RadRibbonBackstageItem backstageItem);

        void RemoveLinkedControl(FrameworkElement control);
    }
    #endregion

    #region IRibbonSearchLinkedUICommand
    public interface IRibbonSearchLinkedUICommand : IRibbonLinkedUICommand
    {
        /// <summary>
        /// Whether or not this command should be discoverable by search. Provided for implementations that wish to leverage base class support
        /// but for whatever reason turn off the participation in ribbon search. The other way to avoid ribbon search is to not implement this interface.
        /// </summary>
        bool HiddenFromSearch { get; set; }

        void GetLinkedElementSearchData(RibbonUICommandLinkedElementTypes linkedElementTypes, out IList<RibbonLocation> elementLocations,
            out IList<FrameworkElement> elementRibbonTabs, out IList<string> elementPaths);
    }
    #endregion

    #region IRibbonUICommandUIElement
    /// <summary>
    /// An interface that can be imnplemented by UIElements that wish to provide access to their associated IRibbonUICommand through
    /// a consistent interface.
    /// </summary>
    public interface IRibbonLinkedUIElement
    {
        IRibbonUICommand LinkedRibbonUICommand { get; }
    }
    #endregion

    #region IInvokableUICommand
    /// <summary>
    /// Implemented by a command that needs to be invokable by way of the Dispatcher.
    /// The FrameworkElement provided must have a lifetime at least as long as the command.
    /// </summary>
    public interface IInvokableUICommand
    {
        void SetDispatcherElement(FrameworkElement dispatcherElement);
    }
    #endregion

    #region IRibbonBackstageUICommand
    /// <summary>
    /// Interface that provides access to the backstage user control if the command contains one.  
    /// </summary>
    public interface IRibbonBackstageUICommand : IRibbonUICommand
    {
        /// <summary>
        /// Gets the backstage user control for this UICommand.
        /// </summary>
        /// <returns>Non-null control if this command is for the backstage.  Otherwise null.</returns>
        System.Windows.Controls.UserControl GetBackstageUserControl();

        /// <summary>
        /// Answers the list of commands that are accessible to the user via the backstage user control.
        /// If none, should return an empty list.
        /// </summary>
        IList<IRibbonUICommand> BackstageUserControlCommands { get; }
    }
    #endregion

    #region IRibbonUICommandCollection
    /// <summary>
    /// Interface defines a collection of related IRibbonUICommand objects.
    /// Concrete instances can use related commands to manage certain grouped command behaviors (e.g., enable/disable for a group, toggle behaviors etc).
    /// Does not imply a connection with or a link to ribbon layout, which is a completely independent concept.
    /// </summary>
    public interface IRibbonUICommandCollection
    {
        IList<IRibbonUICommand> RelatedCommands { get; }
    }
    #endregion

    #region ICloneableElement
    /// <summary>
    /// Interface defines the contract for manager elements (used for ribbon customization settings) that can clone themselves
    /// into their associated manager.
    /// </summary>
    public interface ICloneableElement
    {
        void AddClone();
    }
    #endregion

    // TODO 1: <whar> This IRibbonUIElement / IRibbonUIButton / IRibbonUIMenu concept is part of a higher level abstraction of the builder API.
    // If carried through further it could lead to most of the visual layout of the ribbon being defined in settings files (although the default 
    // layout (one that can be reset to, for reset to default workspace) still needs to be defined in code). Then, depending on what we wish to 
    // support, UI could be built to expose certain settings to users so that they can customize the layout. The most basic level of that is being 
    // able to turn commands on/off, which we have implemented for the Quick Access Toolbar. The next step would be other areas of the ribbon, and 
    // potentially extending it to Label customization, command order customization and so on. 

    #region IRibbonUIElement
    /// <summary>
    /// Interface defines the contract for an IRibbonUIElement that is associated with an IRibbonUICommand.
    /// Any one IRibbonUIElement can only be associated with one IRibbonUICommand, but each IRibbonUICommand
    /// can have more than one IRibbonUIElement associated with it. This interface contains information specific
    /// to the visual aspects of the UI element and can vary depending on the type of UIElement and where it is
    /// located in the Ribbon visual structure.
    /// </summary>
    public interface IRibbonUIElement
    {
        /// <summary>
        /// Whether the UIElement should be visible in the Ribbon.
        /// </summary>
        bool IsVisible { get; set; }

        /// <summary>
        /// Whether a separator appears after the UIElement.
        /// </summary>
        bool SeparatorAfter { get; set; }

        /// <summary>
        /// The unique name of the associated command that can be used with a command factory implementation to get the named command.
        /// </summary>
        string AssociatedCommandName { get; set; }

        /// <summary>
        /// The command associated with the UIElement.
        /// </summary>
        IRibbonUICommand AssociatedCommand { get; }

        /// <summary>
        /// The command factory implementation for getting commands from their unique name.
        /// </summary>
        IRibbonUICommandFactory RibbonUICommandFactory { set; }

        /// <summary>
        /// The WPF UIElement that appears in the Ribbon for this IRibbonUIElement.
        /// </summary>
        UIElement AssociatedUIElement { get; set; }
    }
    #endregion

    #region IRibbonUIButton
    public interface IRibbonUIButton : IRibbonUIElement
    {
        /// <summary>
        /// The button size associated with a button element.
        /// </summary>
        ButtonSize ButtonSize { get; set; }

        /// <summary>
        /// The button style associated with a button element.
        /// </summary>
        ButtonStyle ButtonStyle { get; set; }
    }
    #endregion

    #region IRibbonUIMenu
    public interface IRibbonUIMenu : IRibbonUIElement
    {
        // TODO 1: <whar> Menu properties for future menu customization.
        // e.g., OwnerButton (type?)
    }
    #endregion

    public interface IImageProvider
    {
        BitmapSource GetImage(bool largeImage, string standardGraphicResourceKey);
    }

    #endregion

    #region Internal Interfaces
    internal interface ITitleBarColorInformation
    {
        Color GetTitleBarButtonBackColor();
        Color GetTitleBarButtonForeColor();
        Color GetTitleBarButtonHighlightColor();
    }

    internal interface IQueryIsMaximized
    {
        bool IsMaximized { get; }
    }

    internal interface IQueryRibbonTabIndex
    {
        int GetIndexForTab(RadRibbonTab ribbonTab);
    }

    internal interface ISystemMenuOpener
    {
        void OpenSystemMenu();
        void OpenSystemMenu(System.Drawing.Point screenPosition);
    }
    #endregion
}
