// RibbonExternalConfiguration.cs
// Copyright (c) 2017 Bentley Systems, Incorporated. All Rights Reserved.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Windows.Media;
using System.Text;

// TODO 1: <whar> Things that would make the theme better.
// o Change the (Ribbon) button highlight color (when clicked) to be different to the AccentColor.

namespace Haestad.Framework.UI.Integration
{

    // Config file format for specifying Ribbon internal settings.
    /*
     <appSettings>

      <!-- User Options (pre-configured sample) -->

      <add key="Ribbon_FileTabAndBackstageColor" value="210, 210, 210"/>
      <add key="Ribbon_ControlOutlineColor" value="129, 129, 131"/>
      <add key="Ribbon_BackgroundColor" value="45, 45, 48"/>
      <add key="Ribbon_TextAndDecalColor" value="235, 235, 235"/>
      <add key="Ribbon_FileTab_ButtonHighlightColor" value="74, 74, 76"/>
      <add key="Ribbon_FileTab_HighlightColor" value="180, 180, 180"/>
      <add key="Ribbon_FileTab_SelectedColor" value="235, 235, 235"/>
      <add key="Ribbon_TextSize" value="12.0"/>

      <!-- Could be user options if we wanted -->
      <add key="Ribbon_Windows10Style_Enabled" value="false"/>

      <!-- Developer Only Options; not for customer use -->

      <add key="Ribbon_KeyTips_Enabled" value="true"/>
      <add key="Ribbon_KeyTips_Grouped" value="true"/>
      <add key="Ribbon_Debugging_Enabled" value="false"/>
      <add key="Ribbon_RibbonSearchDebugging_Enabled" value="false"/>

     </appSettings>
    */

    /// <summary>
    /// A class that contains externally configured global ribbon settings for items such as theme colors, font sizes, globally controlled behaviors.
    /// </summary>
    public class RibbonExternalConfiguration
    {
        #region Constructor
        private RibbonExternalConfiguration()
        {
            InitializeSettings();
        }
        #endregion

        #region Private Methods
        private void InitializeSettings()
        {          
            AccentColor = GetColorFromConfigFile(UserFriendlyKeyNames.Ribbon_AccentColor, DefaultAccentColor);
            BasicColor = GetColorFromConfigFile(UserFriendlyKeyNames.Ribbon_BasicColor, DefaultBasicColor);
            MainColor = GetColorFromConfigFile(UserFriendlyKeyNames.Ribbon_MainColor, DefaultMainColor);
            StrongColor = GetColorFromConfigFile(UserFriendlyKeyNames.Ribbon_StrongColor, DefaultStrongColor);
            BackstageButtonHighlightColor = GetColorFromConfigFile(UserFriendlyKeyNames.Ribbon_Backstage_ButtonHighlightColor, DefaultBackstageButtonHighlightColor);
            BackstageHighlightColor = GetColorFromConfigFile(UserFriendlyKeyNames.Ribbon_Backstage_HighlightColor, DefaultBackstageHighlightColor);
            BackstageSelectedColor = GetColorFromConfigFile(UserFriendlyKeyNames.Ribbon_Backstage_SelectedColor, DefaultBackstageSelectedColor);
            FontSize = GetDoubleFromConfigFile(UserFriendlyKeyNames.Ribbon_FontSize, DefaultFontSize);

            Windows10StyleEnabled = GetBooleanFromConfigFile(UserFriendlyKeyNames.Ribbon_Windows10Style_Enabled, DefaultRibbonWindows10StyleEnabled);

            RibbonKeyTipsEnabled = GetBooleanFromConfigFile(UserFriendlyKeyNames.Ribbon_KeyTips_Enabled, DefaultRibbonKeyTipsEnabled);
            RibbonKeyTipsGrouped = GetBooleanFromConfigFile(UserFriendlyKeyNames.Ribbon_KeyTips_Grouped, DefaultRibbonKeyTipsGrouped);
            RibbonDebuggingEnabled = GetBooleanFromConfigFile(UserFriendlyKeyNames.Ribbon_Debugging_Enabled, DefaultRibbonDebuggingEnabled);
            RibbonSearchDebuggingEnabled = GetBooleanFromConfigFile(UserFriendlyKeyNames.Ribbon_RibbonSearchDebugging_Enabled, DefaultRibbonSearchDebuggingEnabled);
        }

        private Color GetColorFromConfigFile(string keyName, Color defaultColor)
        {
            string colorString = ReadStringFromConfigFile(keyName);

            if (colorString == String.Empty)
                return defaultColor;

            byte[] argbColorValues;
            if (TryGetRgbValues(colorString, out argbColorValues))
                return FromRgbIntArray(argbColorValues);
            else
                return defaultColor;
        }

        private double GetDoubleFromConfigFile(string keyName, double defaultValue)
        {
            string doubleString = ReadStringFromConfigFile(keyName);

            if (doubleString == String.Empty)
                return defaultValue;

            double result;
            if (Double.TryParse(doubleString, out result))
                return result;
            else
                return defaultValue;
        }

        private bool GetBooleanFromConfigFile(string keyName, bool defaultValue)
        {
            string boolString = ReadStringFromConfigFile(keyName);

            if (boolString == String.Empty)
                return defaultValue;

            bool result;
            if (Boolean.TryParse(boolString, out result))
                return result;
            else
                return defaultValue;
        }

        private string ReadStringFromConfigFile(String keyName)
        {
            if (ConfigurationManager.AppSettings.Get(keyName) != null)
            {
                AppSettingsReader appSettingsReader = new AppSettingsReader();
                Object value = appSettingsReader.GetValue(keyName, typeof(String));
                return (String)value;
            }
            else
                return String.Empty;
        }

        private bool TryGetRgbValues(string colorString, out byte[] argbValues)
        {
            string[] tokens = Haestad.Support.Library.StringLibrary.TokenizeCsv(colorString);
            argbValues = new byte[tokens.Length];

            const int EXPECTED_NUMBER_OF_TOKENS = 3;
            if (tokens.Length != EXPECTED_NUMBER_OF_TOKENS)
                return false;

            int[] argbIntValues = new int[tokens.Length];
            for (int i = 0; i < tokens.Length; i++)
            {
                if (!Int32.TryParse(Haestad.Support.Library.StringLibrary.GetDigits(tokens[i]), out argbIntValues[i]))
                    return false;
            }

            for (int i = 0; i < tokens.Length; i++)
                argbValues[i] = (byte)argbIntValues[i];

            return true;
        }

        private Color FromRgbIntArray(byte[] argb)
        {
            byte red = argb[0];
            byte green = argb[1];
            byte blue = argb[2];

            const int ALPHA = 255;
            return Color.FromArgb(ALPHA, red, green, blue);
        }
        #endregion

        #region Public Static Properties
        public static RibbonExternalConfiguration Instance
        {
            get
            {
                if (m_instance == null)
                    m_instance = new RibbonExternalConfiguration();
                return m_instance;
            }
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Color used for:
        ///   File Tab, Backstage banner, parent form border, control box buttons, key tip background.
        /// </summary>
        public Color AccentColor
        {
            get;
            private set;
        }

        /// <summary>
        /// Color used for:
        ///   Control outlines (ribbon, tabs, widgets, menus), dividers.
        /// </summary>
        public Color BasicColor
        {
            get;
            private set;
        }

        /// <summary>
        /// Color used for:
        ///   Ribbon background, backstage background, backstage banner font, key tip text.
        /// </summary>
        public Color MainColor
        {
            get;
            private set;
        }

        /// <summary>
        /// Color used for:
        ///   Dropdown button decals, menu text.
        ///   (Seems like it might have been intended for decals "marker color", but that is mostly controlled by StrongColor).
        ///   Doesn't seem to be any reason to set this differently to StrongColor.
        /// </summary>
        public Color MarkerColor
        {
            get { return StrongColor; }
        }

        /// <summary>
        /// Color used for:
        ///   Text color (title bar, tabs, groups, buttons, tooltips), dialog launcher decals, QAT decal, combo decal, minimize button.
        ///   Curiously, NOT used in text for menus.
        /// </summary>
        public Color StrongColor
        {
            get;
            private set;
        }

        /// <summary>
        /// Color used for:
        ///   Mouse over (highlight) color for backstage buttons.
        /// </summary>
        public Color BackstageButtonHighlightColor
        {
            get;
            private set;
        }

        /// <summary>
        /// Color used for:
        ///   Mouse over (highlight) color for backstage items (tabs).
        /// </summary>
        public Color BackstageHighlightColor
        {
            get;
            private set;
        }

        /// <summary>
        /// Color used for:
        ///   Selected color for backstage items (tabs).
        /// </summary>
        public Color BackstageSelectedColor
        {
            get;
            private set;
        }

        /// <summary>
        /// Font used for:
        ///     Everything except the title bar.
        /// </summary>
        public double FontSize
        {
            get;
            private set;
        }
        #endregion

        #region Internal Properties
        internal bool Windows10StyleEnabled
        {
            get
            {
                if (RibbonDebuggingEnabled)
                    return false;

                return m_windows10StyleEnabled;
            }

            set { m_windows10StyleEnabled = value; }
        }

        internal bool RibbonKeyTipsEnabled
        {
            get;
            private set;
        }

        internal bool RibbonKeyTipsGrouped
        {
            get;
            private set;
        }

        internal bool RibbonDebuggingEnabled
        {
            get;
            private set;
        }

        internal bool RibbonSearchDebuggingEnabled
        {
            get;
            private set;
        }
        #endregion

        #region Private Properties

        private Color DefaultAccentColor
        {
            get
            {
                // "That" Windows blue. Microstation is slightly different (0, 122, 204).
                return Color.FromArgb(255, 0, 120, 215);
            }
        }

        private Color DefaultBasicColor
        {
            get { return Colors.Silver; }
        }

        private Color DefaultMainColor
        {
            get { return Colors.WhiteSmoke; }
        }

        private Color DefaultStrongColor
        {
            get
            {
                return Color.FromArgb(255, 28, 28, 28); // Microstation strong color
            }
        }

        private Color DefaultBackstageButtonHighlightColor
        {
            get
            {
                return Colors.LightBlue;
            }
        }

        private Color DefaultBackstageHighlightColor
        {
            get
            {
                return Color.FromArgb(255, 0, 103, 176);
            }
        }

        private Color DefaultBackstageSelectedColor
        {
            get
            {
                return Color.FromArgb(255, 51, 149, 214);
            }
        }

        private double DefaultFontSize
        {
            get { return 12.0;  }
        }

        private bool DefaultRibbonKeyTipsEnabled
        {
            get { return true; }
        }

        private bool DefaultRibbonKeyTipsGrouped
        {
            get { return false; }
        }

        private bool DefaultRibbonDebuggingEnabled
        {
            get { return false; }
        }

        private bool DefaultRibbonSearchDebuggingEnabled
        {
            get { return false; }
        }

        private bool DefaultRibbonWindows10StyleEnabled
        {
            get { return false; }
        }
        #endregion

        #region Private Fields
        private bool m_windows10StyleEnabled;
        #endregion

        #region Private Static Fields
        private static RibbonExternalConfiguration m_instance;
        #endregion

        #region Private Structs
        private struct UserFriendlyKeyNames // TODO 1: <whar> If this becomes a feature; may wish to localize these strings.
        {
            public const string Ribbon_AccentColor = "Ribbon_FileTabAndBackstageColor";
            public const string Ribbon_BasicColor = "Ribbon_ControlOutlineColor";
            public const string Ribbon_MainColor = "Ribbon_BackgroundColor";
            public const string Ribbon_StrongColor = "Ribbon_TextAndDecalColor";
            public const string Ribbon_Backstage_ButtonHighlightColor = "Ribbon_FileTab_ButtonHighlightColor";
            public const string Ribbon_Backstage_HighlightColor = "Ribbon_FileTab_HighlightColor";
            public const string Ribbon_Backstage_SelectedColor = "Ribbon_FileTab_SelectedColor";
            public const string Ribbon_FontSize = "Ribbon_TextSize";
            public const string Ribbon_Windows10Style_Enabled = "Ribbon_Windows10Style_Enabled";
            public const string Ribbon_KeyTips_Enabled = "Ribbon_KeyTips_Enabled";
            public const string Ribbon_KeyTips_Grouped = "Ribbon_KeyTips_Grouped";
            public const string Ribbon_Debugging_Enabled = "Ribbon_Debugging_Enabled";
            public const string Ribbon_RibbonSearchDebugging_Enabled = "Ribbon_RibbonSearchDebugging_Enabled";
        }
        #endregion
    }
}
