/* date = April 29th 2023 8:22 pm */

#ifndef VN_UI_H
#define VN_UI_H

//- sixten: Keying
struct ui_key
{
    u64 Value;
};

inline b32 AreEqual(ui_key A, ui_key B)
{
    b32 Result = (A.Value == B.Value);
    return(Result);
}

//- sixten: Semantic sizing
enum ui_size_type
{
    UI_SizeType_Pixels,
    UI_SizeType_TextContent,
    UI_SizeType_PercentOfParent,
    UI_SizeType_ChildrenSum,
};

struct ui_size
{
    ui_size_type Type;
    r32 Value;
    r32 Strictness;
};

inline ui_size UI_Pixels(r32 Value, r32 Strictness);
inline ui_size UI_Em(r32 Value, r32 Strictness);
inline ui_size UI_TextContent(r32 Value, r32 Strictness);
inline ui_size UI_Percent(r32 Value, r32 Strictness);
inline ui_size UI_ChildrenSum(r32 Value, r32 Strictness);

//- sixten: UI core
enum
{
    UI_BoxFlag_Clickable       = (1 << 0),
    UI_BoxFlag_DrawText        = (1 << 1),
    UI_BoxFlag_DrawBorder      = (1 << 2),
    UI_BoxFlag_DrawBackground  = (1 << 3),
    UI_BoxFlag_DrawDropShadow  = (1 << 4),
    UI_BoxFlag_Clip            = (1 << 5),
    UI_BoxFlag_HotAnimation    = (1 << 6),
    UI_BoxFlag_ActiveAnimation = (1 << 7),
    UI_BoxFlag_OverflowX       = (1 << 8),
    UI_BoxFlag_OverflowY       = (1 << 9),
    UI_BoxFlag_FloatingX       = (1 << 10),
    UI_BoxFlag_FloatingY       = (1 << 11),
    UI_BoxFlag_Scrollable      = (1 << 12),
    UI_BoxFlag_AnimatePosition = (1 << 13),
};
typedef u32 ui_box_flags;

#define UI_CUSTOM_DRAW_CALLBACK(name) void name(render_group *Group, glyph_atlas *Atlas, struct ui_box *Box, void *Data)
typedef UI_CUSTOM_DRAW_CALLBACK(ui_custom_draw_callback);

struct ui_box
{
    // sixten: building
    ui_box *First;
    ui_box *Last;
    ui_box *Next;
    ui_box *Prev;
    ui_box *Parent;
    
    // sixten: hashing
    ui_box *HashNext;
    ui_box *HashPrev;
    ui_key Key;
    ui_key Seed;
    u64 LastFrameTouched;
    
    // sixten: per-frame data
    ui_box_flags Flags;
    string String;
    ui_size SemanticSize[Axis2_Count];
    v2 FixedP;
    v4 TextColor;
    v4 BackgroundColor;
    v4 BorderColor;
    r32 BorderThickness;
    axis2 LayoutAxis;
    r32 CornerRadius;
    font_id Font;
    r32 FontSize;
    v2 Offset;
    platform_cursor HoverCursor;
    ui_custom_draw_callback *DrawCallback;
    void *DrawCallbackData;
    
    v2 ComputedRelativeP;
    v2 ComputedDim;
    
    // sixten: retained data
    range2_r32 Rect;
    r32 HotTransition;
    r32 ActiveTransition;
    v2 ApproachingRelativeP;
};

struct ui_box_bucket
{
    ui_box *First;
    ui_box *Last;
};

struct ui_signal
{
    ui_box *Box;
    v2 MouseP;
    v2 DragDelta;
    v2 Scroll;
    b8 Clicked;
    b8 Pressed;
    b8 PressedRight;
    b8 Released;
    b8 Hovering;
    b8 Dragging;
};

#include "generated/vn_ui.meta.h"

struct ui
{
    memory_arena *Arena;
    memory_arena *FrameArena;
    ui_box *FirstFreeBox;
    ui_box *LastFreeBox;
    
    ui_box_bucket BoxBuckets[256];
    
    ui_box *RootNode;
    ui_box *TooltipNode;
    ui_box *ContainerNode;
    
    u64 CurrentFrame;
    ui_key Hot;
    ui_key Active;
    
    ui_key NextHot;
    b32 NextHotSet;
    
    u64 DragData[8];
    v2 DragStartP;
    
    ui_style_stacks Stacks;
    
    platform_event_list *EventList;
    v2 MouseP;
    
    glyph_atlas *GlyphAtlas;
};

//- sixten: State management
inline void UI_SetState(ui *UI);
inline ui *UI_GetState(void);
inline ui_key UI_GetHot(void);
inline ui_key UI_GetActive(void);
inline platform_event_list *UI_EventList(void);
inline memory_arena *UI_FrameArena(void);
inline v2 UI_MouseP(void);
inline glyph_atlas *UI_GlyphAtlas(void);

//- sixten: Drag helpers
inline void UI_SetDragStartP(v2 P);
inline void UI_UpdateDragStartP(void);
inline v2 UI_GetDragStartP(void);
inline void UI_StoreDragV2(v2 DragData);
inline v2 UI_GetDragV2(void);
inline void UI_StoreDragR32(r32 DragData);
inline r32 UI_GetDragR32(void);
inline void UI_StoreDragPayload(void *Data); // sixten(NOTE): Payload MUST be 64-bytes.
inline void UI_GetDragDataPayload(void *Data);
inline void UI_StoreDragPointer(void *Data);
inline void *UI_GetDragDataPointer(void);

//- sixten: Key functions
static ui_key UI_EmptyKey(void);
static ui_key UI_SeedKey(ui_key Key, ui_key Seed);
static ui_key UI_GenerateKeyFromString(string String);
static string UI_GetBoxNameByKey(ui_key Key);
static ui_box *UI_GetBoxByKey(ui *UI, ui_key Key);

//- sixten: Box creation
static ui_box *UI_MakeBox(ui_box_flags Flags, string String);
static ui_box *UI_MakeBoxF(ui_box_flags Flags, char *Format, ...);
static void UI_EquipBoxText(ui_box *Box, string String);
static void UI_EquipBoxCustomDrawCallback(ui_box *Box, ui_custom_draw_callback *DrawCallback, void *Data);

//- sixten: User interaction
static ui_signal UI_SignalFromBox(ui_box *Box);

//- sixten: Building and rendering
static void UI_Init(ui *UI);
static void UI_BeginBuild(ui *UI, v2 ScreenDim);
static void UI_EndBuild(void);
static void UI_RenderFrame(render_group *RenderGroup);
static void UI_NewFrame(ui *UI, platform_event_list *EventList, v2 MouseP, glyph_atlas *GlyphAtlas);

#endif //VN_UI_H
