#pragma once

#include "DearImGui/imgui.h"
#include "imgui_offset_rect.h"

// Type forward declarations, definitions below in this file.
struct ImGuiToggleConfig;                   // Configuration data to fully customize a toggle.
struct ImGuiToggleStateConfig;              // The data describing how to draw a toggle in a given state.
struct ImGuiTogglePalette;                  // Color data to adjust how a toggle is drawn.

typedef int ImGuiToggleFlags;               // -> enum ImGuiToggleFlags_        // Flags: for Toggle() modes
typedef int ImGuiToggleA11yStyle;            // -> enum ImGuiToggleA11yStyle_   // Describes how to draw A11y labels.

namespace ImGui
{
    // Widgets: Toggle Switches
    // - Toggles behave similarly to ImGui::Checkbox()
    // - Sometimes called a toggle switch, see also: https://en.wikipedia.org/wiki/Toggle_switch_(widget)
    // - They represent two mutually exclusive states, with an optional animation on the UI when toggled.
    // Optional parameters:
    // - flags: Values from the ImGuiToggleFlags_ enumeration to set toggle modes.
    // - animation_duration: Animation duration. Amount of time in seconds the toggle should animate. (0,...] default: 1.0f (Overloads with this parameter imply ImGuiToggleFlags_Animated)
    // - frame_rounding: A scalar that controls how rounded the toggle frame is. 0 is square, 1 is round. (0, 1) default 1.0f
    // - knob_rounding: A scalar that controls how rounded the toggle knob is. 0 is square, 1 is round. (0, 1) default 1.0f
    // - size: A width and height to draw the toggle at. Defaults to `ImGui::GetFrameHeight()` and that height * Phi for the width.
    // Config structure:
    // - The overload taking a reference to an ImGuiToggleConfig structure allows for more complete control over the widget.
    IMGUI_API bool Toggle(const char* label, bool* v, const ImVec2& size = ImVec2());
    IMGUI_API bool Toggle(const char* label, bool* v, ImGuiToggleFlags flags, const ImVec2& size = ImVec2());
    IMGUI_API bool Toggle(const char* label, bool* v, ImGuiToggleFlags flags, float animation_duration, const ImVec2& size = ImVec2());
    IMGUI_API bool Toggle(const char* label, bool* v, ImGuiToggleFlags flags, float frame_rounding, float knob_rounding, const ImVec2& size = ImVec2());
    IMGUI_API bool Toggle(const char* label, bool* v, ImGuiToggleFlags flags, float animation_duration, float frame_rounding, float knob_rounding, const ImVec2& size = ImVec2());
    IMGUI_API bool Toggle(const char* label, bool* v, const ImGuiToggleConfig& config);

} // namespace ImGui


// ImGuiToggleFlags: A set of flags that adjust behavior and display for ImGui::Toggle().
enum ImGuiToggleFlags_
{
    ImGuiToggleFlags_None                   = 0,
    ImGuiToggleFlags_Animated               = 1 << 0, // The toggle's knob should be animated.
                                                      // Bits 1-2 reserved.
    ImGuiToggleFlags_BorderedFrame          = 1 << 3, // The toggle should have a border drawn on the frame.
    ImGuiToggleFlags_BorderedKnob           = 1 << 4, // The toggle should have a border drawn on the knob.
    ImGuiToggleFlags_ShadowedFrame          = 1 << 5, // The toggle should have a shadow drawn under the frame.
    ImGuiToggleFlags_ShadowedKnob           = 1 << 6, // The toggle should have a shadow drawn under the knob.
                                                      // Bit 7 reserved.
    ImGuiToggleFlags_A11y                   = 1 << 8, // The toggle should draw on and off glyphs to help indicate its state.
    ImGuiToggleFlags_Bordered               = ImGuiToggleFlags_BorderedFrame | ImGuiToggleFlags_BorderedKnob, // Shorthand for bordered frame and knob.
    ImGuiToggleFlags_Shadowed               = ImGuiToggleFlags_ShadowedFrame | ImGuiToggleFlags_ShadowedKnob, // Shorthand for shadowed frame and knob.
    ImGuiToggleFlags_Default                = ImGuiToggleFlags_None, // The default flags used when no ImGuiToggleFlags_ are specified.
};

// ImGuiToggleA11yStyle: Styles to draw A11y labels.
enum ImGuiToggleA11yStyle_
{
    ImGuiToggleA11yStyle_Label,             // A11y glyphs draw as text labels.
    ImGuiToggleA11yStyle_Glyph,             // A11y glyphs draw as power-icon style "I/O" glyphs.
    ImGuiToggleA11yStyle_Dot,               // A11y glyphs draw as a small dot that can be colored separately from the frame.
    ImGuiToggleA11yStyle_Default            = ImGuiToggleA11yStyle_Label, // Default: text labels.
};

// ImGuiToggleConstants: A set of defaults and limits used by ImGuiToggleConfig
namespace ImGuiToggleConstants
{
    // The golden ratio.
    constexpr float Phi = 1.6180339887498948482045f;

    // d = 2r
    constexpr float DiameterToRadiusRatio = 0.5f;

    // Animation is disabled with a animation_duration of 0.
    constexpr float AnimationDurationDisabled = 0.0f;

    // The default animation duration, in seconds. (0.1f: 100 ms.)
    constexpr float AnimationDurationDefault = 0.1f;

    // The lowest allowable value for animation duration. (0.0f: Disabled animation.)
    constexpr float AnimationDurationMinimum = AnimationDurationDisabled;

    // The default frame rounding value. (1.0f: Full rounding.)
    constexpr float FrameRoundingDefault = 1.0f;

    // The minimum frame rounding value. (0.0f: Full rectangle.)
    constexpr float FrameRoundingMinimum = 0.0f;

    // The maximum frame rounding value. (1.0f: Full rounding.)
    constexpr float FrameRoundingMaximum = 1.0f;

    // The default knob rounding value. (1.0f: Full rounding.)
    constexpr float KnobRoundingDefault = 1.0f;

    // The minimum knob rounding value. (0.0f: Full rectangle.)
    constexpr float KnobRoundingMinimum = 0.0f;

    // The maximum knob rounding value. (1.0f: Full rounding.)
    constexpr float KnobRoundingMaximum = 1.0f;

    // The default height to width ratio. (Phi: The golden ratio.)
    constexpr float WidthRatioDefault = Phi;

    // The minimum allowable width ratio. (1.0f: Toggle width==height, not very useful but interesting.)
    constexpr float WidthRatioMinimum = 1.0f;

    // The maximum allowable width ratio. (10.0f: It starts to get silly quickly.)
    constexpr float WidthRatioMaximum = 10.0f;

    // The default amount of pixels the knob should be inset into the toggle frame. (1.5f in each direction: Pleasing to the eye.)
    constexpr ImOffsetRect KnobInsetDefault = 1.5f;

    // The minimum amount of pixels the knob should be negatively inset (outset) from the toggle frame. (-100.0f: Big overgrown toggle.)
    constexpr float KnobInsetMinimum = -100.0f;

    // The maximum amount of pixels the knob should be inset into the toggle frame. (100.0f: Toggle likely invisible!)
    constexpr float KnobInsetMaximum = 100.0f;

    // The default thickness for borders drawn on the toggle frame and knob.
    constexpr float BorderThicknessDefault = 1.0f;

    // The default thickness for shadows drawn under the toggle frame and knob.
    constexpr float ShadowThicknessDefault = 2.0f;

    // The default a11y string used when the toggle is on.
    const char* const LabelA11yOnDefault = "1";

    // The default a11y string used when the toggle is off.
    const char* const LabelA11yOffDefault = "0";
}

struct ImGuiToggleStateConfig
{
    // The thickness the border should be drawn on the frame when ImGuiToggleFlags_BorderedFrame is specified in `Flags`.
    float FrameBorderThickness = ImGuiToggleConstants::BorderThicknessDefault;

    // The thickness the shadow should be drawn on the frame when ImGuiToggleFlags_ShadowedFrame is specified in `Flags`.
    float FrameShadowThickness = ImGuiToggleConstants::ShadowThicknessDefault;

    // The thickness the border should be drawn on the frame when ImGuiToggleFlags_BorderedKnob is specified in `Flags`.
    float KnobBorderThickness = ImGuiToggleConstants::BorderThicknessDefault;

    // The thickness the shadow should be drawn on the frame when ImGuiToggleFlags_ShadowedKnob is specified in `Flags`.
    float KnobShadowThickness = ImGuiToggleConstants::ShadowThicknessDefault;

    // The label drawn on the toggle to show the toggle is in the when ImGuiToggleFlags_A11yLabels is specified in `Flags`.
    // If left null, default strings will be used.
    const char* Label = nullptr;

    // The number of pixels the knob should be inset into the toggle frame.
    // With a round (circle) knob, an average of each offset will be used.
    // With a rectangular knob, each offset will be used in it's intended direction.
    ImOffsetRect KnobInset = ImGuiToggleConstants::KnobInsetDefault;

    // A custom amount of pixels to offset the knob by. Positive x values will move the knob towards the inside, negative the outside.
    ImVec2 KnobOffset = ImVec2(0.0f, 0.0f);

    // An optional custom palette to use for the colors to use when drawing the toggle. If left null, theme colors will be used.
    // If any of the values in the palette are zero, those specific colors will default to theme colors.
    const ImGuiTogglePalette* Palette = nullptr;
};

// ImGuiToggleConfig: A collection of data used to customize the appearance and behavior of a toggle widget.
struct ImGuiToggleConfig
{
    // Flags that control the toggle's behavior and display.
    ImGuiToggleFlags Flags = ImGuiToggleFlags_Default;

    // What style of A11y glyph to draw on the widget.
    ImGuiToggleFlags A11yStyle = ImGuiToggleA11yStyle_Default;

    // The a duration in seconds that the toggle should animate for. If 0, animation will be disabled.
    float AnimationDuration = ImGuiToggleConstants::AnimationDurationDefault;

    // A scalar that controls how rounded the toggle frame is. 0 is square, 1 is round. (0, 1) default 1.0f
    float FrameRounding = ImGuiToggleConstants::FrameRoundingDefault;

    //A scalar that controls how rounded the toggle knob is. 0 is square, 1 is round. (0, 1) default 1.0f
    float KnobRounding = ImGuiToggleConstants::KnobRoundingDefault;

    // A ratio that controls how wide the toggle is compared to it's height. If `Size.x` is non-zero, this value is ignored.
    float WidthRatio = ImGuiToggleConstants::WidthRatioDefault;

    // A custom size to draw the toggle with. Defaults to (0, 0). If `Size.x` is zero, `WidthRatio` will control the toggle width.
    // If `Size.y` is zero, the toggle height will be set by `ImGui::GetFrameHeight()`.
    ImVec2 Size = ImVec2(0.0f, 0.0f);

    // Specific configuration data to use when the knob is in the on state.
    ImGuiToggleStateConfig On;

    // Specific configuration data to use when the knob is in the off state.
    ImGuiToggleStateConfig Off;
};
