//- sixten: Managing nodes 
static workspace_editor_node *Workspace_GetNewEditorNode(workspace_view *View)
{
    Assert(View->Type == W_View_Editor);
    
    workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
    
    workspace_editor_node *Result = 0;
    
    if(DLLIsEmpty(Editor->FirstFreeNode))
    {
        Result = PushStruct(View->Arena, workspace_editor_node);
    }
    else
    {
        Result = Editor->FirstFreeNode;
        DLLRemove(Editor->FirstFreeNode, Editor->LastFreeNode, Result);
    }
    
    if(Result)
    {
        *Result = {};
        DLLInsertLast(Editor->FirstNode, Editor->LastNode, Result);
    }
    
    return(Result);
}

//- sixten: Transformations
inline r32 Workspace_ViewToWorld(r32 Offset, r32 Scale, r32 Dim, r32 P)
{
    r32 Result = (P - Dim*0.5)*(1.0/Scale) - Offset;
    return(Result);
} 

inline r32 Workspace_WorldToView(r32 Offset, r32 Scale, r32 Dim, r32 P)
{
    r32 Result = (P + Offset)*Scale + Dim*0.5;
    return(Result);
} 

inline v2 Workspace_ViewToWorld(v2 Offset, r32 Scale, v2 Dim, v2 P)
{
    v2 Result = (P - Dim*0.5)*(1.0/Scale) - Offset;
    return(Result);
} 

inline v2 Workspace_WorldToView(v2 Offset, r32 Scale, v2 Dim, v2 P)
{
    v2 Result = (P + Offset)*Scale + Dim*0.5;
    return(Result);
} 

inline r32 Workspace_CalculateScaleFromZoomLevel(r32 ZoomLevel)
{
    r32 PixelsPerUnit = 100.0;
    
    r32 Scale = PixelsPerUnit*Pow(1.25, ZoomLevel);
    return(Scale);
}

//- sixten: Commands


//- sixten: Builder code
static void Workspace_BuildEditorListerDropdown(workspace_editor_lister_dropdown *ListerDropdown)
{
    b32 ActiveInDropdown = false;
    
    UI_PushBackgroundColor(SetAlpha(Color_Black, 0.3));
    UI_PushBorderColor(SetAlpha(Color_Black, 0.7));
    
    r32 HeightTransition = AC_AnimateValueF(1, 0, 0.3, "Editor Lister Dropdown %p", ListerDropdown);
    
    UI_SetNextSize(UI_Em(15, 1), UI_Em(25*HeightTransition, 1));
    UI_SetNextCornerRadius(4.0);
    UI_SetNextFixedP(ListerDropdown->P);
    UI_SetNextLayoutAxis(Axis2_Y);
    
    ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawBackground |
                             UI_BoxFlag_FloatingX      |
                             UI_BoxFlag_FloatingY      |
                             UI_BoxFlag_Clickable      |
                             UI_BoxFlag_Clip,
                             StrLit("Editor Lister Dropdown"));
    
    UI_Parent(Box)
    {
        
        UI_BorderColor(SetAlpha(Color_Grey, 0.7))
            UI_Row() UI_Column()
        {
            UI_Size(UI_TextContent(15, 1), UI_TextContent(12, 1)) UI_LabelF("Create new node");
            
            // sixten: Build search bar
            UI_SetNextWidth(UI_Percent(1, 1));
            UI_SetNextHeight(UI_Em(2, 1));
            UI_SetNextCornerRadius(4.0);
            UI_SetNextLayoutAxis(Axis2_X);
            UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, StrLit("Editor Lister Field")))
            {
                UI_Spacer(UI_Em(0.8, 1));
                UI_Width(UI_TextContent(1, 1)) UI_Font(Font_Icons) UI_LabelF("%U", FontIcon_Filter);
                UI_Width(UI_Percent(1, 0))
                {
                    UI_MakeBox(0, StrLit(""));
                }
            }
            
            struct lister_option
            {
                char *Text;
                u32 Icons;
            };
            
            lister_option Options[] =
            {
                {"Text", FontIcon_Pencil},
                {"Branch", FontIcon_Menu},
            };
            
            for(s32 OptionIndex = 0;
                OptionIndex < ArrayCount(Options);
                ++OptionIndex)
            {
                lister_option *Option = Options + OptionIndex;
                
                UI_SetNextSize(UI_Percent(1, 1), UI_Em(2, 1));
                UI_SetNextLayoutAxis(Axis2_X);
                ui_box *ClickableBox = UI_MakeBoxF(UI_BoxFlag_Clickable, "Editor Lister %s", Option->Text);
                
                ui_signal Signal = UI_SignalFromBox(ClickableBox);
                
                if(AreEqual(UI_GetActive(), ClickableBox->Key))
                {
                    ActiveInDropdown = true;
                }
                
                UI_Parent(ClickableBox)
                    UI_Height(UI_Percent(1, 1))
                {
                    b32 IsHot = AreEqual(UI_GetHot(), ClickableBox->Key);
                    r32 TargetHot = IsHot*0.8;
                    
                    UI_SetNextCornerRadius(3.0);
                    UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
                    UI_SetNextBackgroundColor(SetAlpha(Theme_HighlightBorderColor,
                                                       AC_AnimateValueF(TargetHot, TargetHot, 0.1, "Editor Lister %s%p",
                                                                        Option->Text, ListerDropdown)));
                    UI_SetNextLayoutAxis(Axis2_X);
                    ui_box *HighlightBox = UI_MakeBox(UI_BoxFlag_DrawBackground, StrLit(""));
                    
                    UI_Parent(HighlightBox)
                        UI_Padding(UI_Em(0.8, 1))
                    {
                        UI_Width(UI_TextContent(0, 1))
                            UI_Font(Font_Icons) UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Option->Icons);
                        UI_Spacer(UI_Em(0.6, 1));
                        UI_Width(UI_TextContent(0, 1)) UI_MakeBoxF(UI_BoxFlag_DrawText, "%s", Option->Text);
                        
                        if(Signal.Clicked)
                        {
                            // sixten(TODO): Issue the requested command.
                            ListerDropdown->Open = false;
                        }
                    }
                }
            }
        }
        
        ui_signal Signal = UI_SignalFromBox(Box);
        if(AreEqual(UI_GetActive(), Box->Key))
        {
            ActiveInDropdown = true;
        }
    }
    UI_PopBackgroundColor();
    UI_PopBorderColor();
    
    if(!ActiveInDropdown && !AreEqual(UI_GetActive(), UI_EmptyKey()))
    {
        ListerDropdown->Open = false;
    }
}

static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data)
{
    workspace_view_editor *Editor = (workspace_view_editor *)Data;
    
    r32 Scale = Editor->Scale;
    
    v4 LineColor = Theme_BorderColor;
    
    v2 Dim = DimOfRange(Box->Rect);
    
    s32 VerticalLineCount = Dim.x / Scale + 4;
    for(s32 LineIndex = -VerticalLineCount/2;
        LineIndex < VerticalLineCount/2;
        ++LineIndex)
    {
        r32 OffsetX = Workspace_WorldToView(Editor->Offset.x, Scale, Dim.x, LineIndex - (s32)Editor->Offset.x);
        v2 Min = Box->Rect.Min + V2(OffsetX, 0);
        v2 Max = Min + V2(1.5, Dim.y);
        PushQuad(Group, Range2R32(Min, Max), LineColor, 0, 1.2, 0);
    }
    
    s32 HorizontalLineCount = Dim.y / Scale + 4;
    for(s32 LineIndex = -HorizontalLineCount/2;
        LineIndex < HorizontalLineCount/2;
        ++LineIndex)
    {
        r32 OffsetY = Workspace_WorldToView(Editor->Offset.y, Scale, Dim.y, LineIndex - (s32)Editor->Offset.y);
        v2 Min = Box->Rect.Min + V2(0, OffsetY);
        v2 Max = Min + V2(Dim.x, 1.5);
        
        PushQuad(Group, Range2R32(Min, Max), LineColor, 0, 1.2, 0);
    }
}

static void Workspace_BuildEditor(workspace_view *View)
{
    workspace *Workspace = W_GetState();
    
    workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
    
    UI_SetNextWidth(UI_Percent(1, 1));
    UI_SetNextHeight(UI_Percent(1, 1));
    
    ui_box *EditorBox = UI_MakeBoxF(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "Workspace Editor %p", View);
    UI_EquipBoxCustomDrawCallback(EditorBox, Workspace_EditorDrawCallback, Editor);
    
    r32 AnimatedZoomLevel = AC_AnimateValueF(Editor->ZoomLevel, 0, 0.25, "Workspace Editor Zoom");
    Editor->Scale = Workspace_CalculateScaleFromZoomLevel(AnimatedZoomLevel);
    
    v2 EditorDim = DimOfRange(EditorBox->Rect);
    
    UI_Parent(EditorBox)
    {
        // sixten: Build the node boxes.
        for(workspace_editor_node *Node = Editor->FirstNode;
            Node != 0;
            Node = Node->Next)
        {
            v2 ViewDim = V2(2, 1.5)*Editor->Scale;
            v2 ViewP = Workspace_WorldToView(Editor->Offset, Editor->Scale, EditorDim, Node->P) - ViewDim*0.5;
            
            UI_SetNextSize(UI_Pixels(ViewDim.x, 1), UI_Pixels(ViewDim.y, 1));
            UI_SetNextFixedP(ViewP);
            UI_SetNextLayoutAxis(Axis2_Y);
            
            Node->Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
                                    UI_BoxFlag_DrawBorder     |
                                    UI_BoxFlag_FloatingX      |
                                    UI_BoxFlag_FloatingY      |
                                    UI_BoxFlag_DrawDropShadow,
                                    "Workspace Editor Node %p", Node);
            
            UI_Parent(Node->Box)
            {
                UI_SetNextBackgroundColor(LinearBlend(Theme_BackgroundColor, Color_Black, 0.3));
                UI_SetNextLayoutAxis(Axis2_X);
                UI_SetNextSize(UI_Percent(1, 1), UI_Em(1.8, 1));
                Node->TitleBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
                                             UI_BoxFlag_DrawBorder     |
                                             UI_BoxFlag_Clickable,
                                             "Workspace Editor Node Title");
                
                UI_Parent(Node->TitleBox)
                {
                    UI_Spacer(UI_Em(0.5, 1));
                    
                    UI_Width(UI_TextContent(0, 1)) UI_Font(Font_Bold) UI_LabelF("Node");
                    UI_Spacer(UI_Percent(1, 0));
                    
                    UI_SetNextSize(UI_Em(1.8, 1), UI_Percent(1, 1));
                    UI_SetNextFont(Font_Icons);
                    Node->CloseBox = UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", FontIcon_Cancel);
                }
            }
        }
        
        if(Editor->ListerDropdown.Open)
        {
            Workspace_BuildEditorListerDropdown(&Editor->ListerDropdown);
        }
    }
    
    // sixten: Get input from boxes.
    {
        workspace_editor_node *Next = 0;
        for(workspace_editor_node *Node = Editor->FirstNode;
            Node != 0;
            Node = Next)
        {
            Next = Node->Next;
            
            ui_signal Signal = UI_SignalFromBox(Node->TitleBox);
            if(Signal.Dragging)
            {
                if(Signal.Pressed)
                {
                    UI_StoreDragV2(Node->P);
                }
                
                v2 StartP = UI_GetDragV2();
                v2 EndP = StartP + Signal.DragDelta*(1.0 / Editor->Scale);
                
                Node->P = EndP;
            }
            
            if(Signal.Dragging || Signal.Hovering)
            {
                Platform.SetCursor(PlatformCursor_ArrowAll);
            }
        }
    }
    
    // sixten: Process panning and zooming of the editor.
    ui_signal Signal = UI_SignalFromBox(EditorBox);
    {
        if(Signal.Dragging)
        {
            if(Signal.Pressed)
            {
                UI_StoreDragV2(Editor->Offset);
            }
            
            v2 StartOffset = UI_GetDragV2();
            v2 EndOffset = StartOffset + Signal.DragDelta*(1.0 / Editor->Scale);
            
            Editor->Offset = EndOffset;
            
            // sixten: Update node positions, as to not get a one frame delay.
            for(workspace_editor_node *Node = 0;
                Node != 0;
                Node = Node->Next)
            {
                v2 ViewDim = V2(2, 1.5)*Editor->Scale;
                v2 ViewP = Workspace_WorldToView(Editor->Offset, Editor->Scale, EditorDim, Node->P) - ViewDim*0.5;
                
                Node->Box->FixedP = ViewP;
            }
        }
    }
    
    for(platform_event *Event = Workspace->EventList->First;
        Event != 0;
        Event = Event->Next)
    {
        if(Event->Type == PlatformEvent_MouseScroll)
        {
            if(Signal.Dragging)
            {
                UI_StoreDragV2(Editor->Offset);
                UI_UpdateDragStartP();
            }
            
            Editor->ZoomLevel = Clamp(Editor->ZoomLevel + Event->Scroll.y, -4, 5);
        }
    }
    
    // sixten: Process shortcuts.
    if(Platform_KeyPress(Workspace->EventList, Key_Space, PlatformModifier_Ctrl))
    {
        workspace_editor_lister_dropdown *ListerDropdown = &Editor->ListerDropdown;
        
        if(ListerDropdown->Open)
        {
            ListerDropdown->Open = false;
        }
        else if(InRange(EditorBox->Rect, UI_GetState()->MouseP))
        {
            ListerDropdown->Open = true;
            ListerDropdown->P = UI_GetState()->MouseP - EditorBox->Rect.Min;
        }
    }
}
