// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;

namespace System.Windows.Forms.VisualStyles;

/// <summary>
///  Provides information about the current visual style.
///
///  NOTE:
///
///  1) These properties (except SupportByOS, which is always meaningful) are meaningful only
///  if visual styles are supported and have currently been applied by the user.
///  2) A subset of these use VisualStyleRenderer objects, so they are
///  not meaningful unless VisualStyleRenderer.IsSupported is true.
/// </summary>
public static class VisualStyleInformation
{
    // Make this per-thread, so that different threads can safely use these methods.
    [ThreadStatic]
    private static VisualStyleRenderer? t_visualStyleRenderer;

    /// <summary>
    ///  Used to find whether visual styles are supported by the current OS. Same as
    ///  using the OSFeature class to see if themes are supported.
    ///  This is always supported on platforms that .NET Core supports.
    /// </summary>
    public static bool IsSupportedByOS => true;

    /// <summary>
    ///  Returns true if a visual style has currently been applied by the user, else false.
    /// </summary>
    public static bool IsEnabledByUser => PInvoke.IsAppThemed();

    internal static unsafe string ThemeFilename
    {
        get
        {
            if (IsEnabledByUser)
            {
                Span<char> filename = stackalloc char[512];
                fixed (char* pFilename = filename)
                {
                    PInvoke.GetCurrentThemeName(pFilename, filename.Length, null, 0, null, 0);
                }

                return filename.SliceAtFirstNull().ToString();
            }

            return string.Empty;
        }
    }

    /// <summary>
    ///  The current visual style's color scheme name.
    /// </summary>
    public static unsafe string ColorScheme
    {
        get
        {
            if (IsEnabledByUser)
            {
                Span<char> colorScheme = stackalloc char[512];
                fixed (char* pColorScheme = colorScheme)
                {
                    PInvoke.GetCurrentThemeName(null, 0, pColorScheme, colorScheme.Length, null, 0);
                }

                return colorScheme.SliceAtFirstNull().ToString();
            }

            return string.Empty;
        }
    }

    /// <summary>
    ///  The current visual style's size name.
    /// </summary>
    public static unsafe string Size
    {
        get
        {
            if (IsEnabledByUser)
            {
                Span<char> size = stackalloc char[512];
                fixed (char* pSize = size)
                {
                    PInvoke.GetCurrentThemeName(null, 0, null, 0, pSize, size.Length);
                }

                return size.SliceAtFirstNull().ToString();
            }

            return string.Empty;
        }
    }

    /// <summary>
    ///  The current visual style's display name.
    /// </summary>
    public static unsafe string DisplayName => IsEnabledByUser
        ? PInvoke.GetThemeDocumentationProperty(ThemeFilename, "DisplayName")
        : string.Empty;

    /// <summary>
    ///  The current visual style's company.
    /// </summary>
    public static string Company => IsEnabledByUser
        ? PInvoke.GetThemeDocumentationProperty(ThemeFilename, "Company")
        : string.Empty;

    /// <summary>
    ///  The name of the current visual style's author.
    /// </summary>
    public static string Author => IsEnabledByUser
        ? PInvoke.GetThemeDocumentationProperty(ThemeFilename, "Author")
        : string.Empty;

    /// <summary>
    ///  The current visual style's copyright information.
    /// </summary>
    public static string Copyright => IsEnabledByUser
        ? PInvoke.GetThemeDocumentationProperty(ThemeFilename, "Copyright")
        : string.Empty;

    /// <summary>
    ///  The current visual style's url.
    /// </summary>
    public static string Url => IsEnabledByUser
        ? PInvoke.GetThemeDocumentationProperty(ThemeFilename, "Url")
        : string.Empty;

    /// <summary>
    ///  The current visual style's version.
    /// </summary>
    public static string Version => IsEnabledByUser
        ? PInvoke.GetThemeDocumentationProperty(ThemeFilename, "Version")
        : string.Empty;

    /// <summary>
    ///  The current visual style's description.
    /// </summary>
    public static string Description => IsEnabledByUser
        ? PInvoke.GetThemeDocumentationProperty(ThemeFilename, "Description")
        : string.Empty;

    /// <summary>
    ///  Returns true if the current theme supports flat menus, else false.
    /// </summary>
    public static bool SupportsFlatMenus =>
        Application.RenderWithVisualStyles
        && PInvoke.GetThemeSysBool(
            SetParameters(VisualStyleElement.Window.Caption.Active).HTHEME,
            THEME_PROPERTY_SYMBOL_ID.TMT_FLATMENUS);

    /// <summary>
    ///  The minimum color depth supported by the current visual style.
    /// </summary>
    public static int MinimumColorDepth
    {
        get
        {
            if (!Application.UseVisualStyles)
            {
                return 0;
            }

            PInvoke.GetThemeSysInt(
                SetParameters(VisualStyleElement.Window.Caption.Active).HTHEME,
                THEME_PROPERTY_SYMBOL_ID.TMT_MINCOLORDEPTH,
                out int depth);

            return depth;
        }
    }

    /// <summary>
    ///  Border Color that Windows renders for controls like TextBox and ComboBox.
    /// </summary>
    public static Color TextControlBorder => Application.RenderWithVisualStyles
        ? SetParameters(VisualStyleElement.TextBox.TextEdit.Normal).GetColor(ColorProperty.BorderColor)
        : SystemColors.WindowFrame;

    /// <summary>
    ///  This is the color buttons and tab pages are highlighted with when they are moused over on themed OS.
    /// </summary>
    public static Color ControlHighlightHot => Application.RenderWithVisualStyles
        ? SetParameters(VisualStyleElement.Button.PushButton.Normal).GetColor(ColorProperty.AccentColorHint)
        : SystemColors.ButtonHighlight;

    private static VisualStyleRenderer SetParameters(VisualStyleElement element)
    {
        if (t_visualStyleRenderer is null)
        {
            t_visualStyleRenderer = new VisualStyleRenderer(element);
        }
        else
        {
            t_visualStyleRenderer.SetParameters(element);
        }

        return t_visualStyleRenderer;
    }
}
