// 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.

//
// Description:
//      A helper class for tracking the change of the system high contrast setting.
//
// Features:
//


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;

namespace MS.Internal.Ink
{
    /// <summary>
    /// HighContrastCallback Classs - An abstract helper class
    /// </summary>
    internal abstract class HighContrastCallback
    {
        /// <summary>
        /// TurnHighContrastOn
        /// </summary>
        /// <param name="highContrastColor"></param>
        internal abstract void TurnHighContrastOn(Color highContrastColor);

        /// <summary>
        /// TurnHighContrastOff
        /// </summary>
        internal abstract void TurnHighContrastOff();

        /// <summary>
        /// Returns the dispatcher if the object is associated to a UIContext.
        /// </summary>
        internal abstract Dispatcher Dispatcher
        {
            get;
        }
    }

    /// <summary>
    /// StylusEditingBehavior - a base class for all stylus related editing behaviors
    /// </summary>
    internal static class HighContrastHelper
    {
        //-------------------------------------------------------------------------------
        //
        // Constructors
        //
        //-------------------------------------------------------------------------------

        #region Constructors

        /// <summary>
        /// Constructor
        /// </summary>
        static HighContrastHelper()
        {
            __highContrastCallbackList = new List<WeakReference>();
            __increaseCount = 0;
        }
        
        #endregion Constructors


        //-------------------------------------------------------------------------------
        //
        // Internal Methods
        //
        //-------------------------------------------------------------------------------

        #region Internal Methods

        /// <summary>
        /// Register the weak references for HighContrastCallback
        /// </summary>
        /// <param name="highContrastCallback"></param>
        internal static void RegisterHighContrastCallback(HighContrastCallback highContrastCallback)
        {
            lock ( __lock )
            {
                int count = __highContrastCallbackList.Count;
                int i = 0;
                int j = 0;

                // Every 100 items, We go through the list to remove the references
                // which have been collected by GC.
                if ( __increaseCount > CleanTolerance )
                {
                    while ( i < count )
                    {
                        WeakReference weakRef = __highContrastCallbackList[j];
                        if ( weakRef.IsAlive )
                        {
                            j++;
                        }
                        else
                        {
                            // Remove the unavaliable reference from the list
                            __highContrastCallbackList.RemoveAt(j);
                        }
                        i++;
                    }

                    // Reset the count
                    __increaseCount = 0;
                }

                __highContrastCallbackList.Add(new WeakReference(highContrastCallback));
                __increaseCount++;
            }
        }

        /// <summary>
        /// The method is called from SystemResources.SystemThemeFilterMessage
        /// </summary>
        internal static void OnSettingChanged()
        {
            UpdateHighContrast();
        }

        #endregion Internal Methods

        //-------------------------------------------------------------------------------
        //
        // Private Methods
        //
        //-------------------------------------------------------------------------------

        #region Private Methods

        /// <summary>
        /// UpdateHighContrast which calls out all the registered callbacks.
        /// </summary>
        private static void UpdateHighContrast()
        {
            lock ( __lock )
            {
                int count = __highContrastCallbackList.Count;
                int i = 0;
                int j = 0;

                // Now go through the list,
                // And we will notify the alive callbacks 
                // or remove the references which have been collected by GC.
                while ( i < count )
                {
                    WeakReference weakRef = __highContrastCallbackList[j];
                    if ( weakRef.IsAlive )
                    {
                        HighContrastCallback highContrastCallback = weakRef.Target as HighContrastCallback;

                        if ( highContrastCallback.Dispatcher != null )
                        {
                            highContrastCallback.Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                new UpdateHighContrastCallback(OnUpdateHighContrast),
                                highContrastCallback);
                        }
                        else
                        {
                            OnUpdateHighContrast(highContrastCallback);
                        }

                        j++;
                    }
                    else
                    {
                        // Remove the dead ones
                        __highContrastCallbackList.RemoveAt(j);
                    }
                    i++;
                }

                // Reset the count
                __increaseCount = 0;
}
        }

        private delegate void UpdateHighContrastCallback(HighContrastCallback highContrastCallback);

        /// <summary>
        /// Invoke the callback
        /// </summary>
        /// <param name="highContrastCallback"></param>
        private static void OnUpdateHighContrast(HighContrastCallback highContrastCallback)
        {
            // Get the current setting.
            bool isHighContrast = SystemParameters.HighContrast;
            Color windowTextColor = SystemColors.WindowTextColor;

            if ( isHighContrast )
            {
                highContrastCallback.TurnHighContrastOn(windowTextColor);
            }
            else
            {
                highContrastCallback.TurnHighContrastOff();
            }
        }

        #endregion Private Methods

        //-------------------------------------------------------------------------------
        //
        // Private Fields
        //
        //-------------------------------------------------------------------------------

        #region Private Fields

        private static readonly object          __lock = new object();
        private static List<WeakReference>      __highContrastCallbackList;
        private static int                      __increaseCount;
        private const int                       CleanTolerance = 100;

        #endregion Private Fields
    }
}
