#include <gui/ui.hpp>

#include <algo/misc.hpp>
#include <utils/math.hpp>

#include <iostream>
#include <string>

void show_ui(const osi::Window &window, edit::UIData &data, const double &current_second)
{
    using namespace edit;
    using enum phase;

    data.current_second = current_second;

    if (!data.ui_visible)
        return;

    menu_bar_ui(window, data);

    switch(data.editor_phase)
    {
        case one:
            phase_one_ui(window, data);
            break;
        case two:
            phase_two_ui(window, data);
            break;
    }
    
    show_help(window, data.help_controls);
}

void show_edit_error_msg(const osi::Window &window, edit::UIData &data, const double current_second)
{
    if (!data.vocal_error || current_second - data.error_start_second > 2)
        return;

    auto message_c_str = data.error_msg.c_str();
    auto error_name = "Invalid operation -";

    ImGui::SetNextWindowPos(ImVec2(0, window.size().y - ImGui::GetTextLineHeight() - 80), ImGuiCond_Always);
    auto text_size = ImGui::CalcTextSize(message_c_str);
    text_size.x += ImGui::CalcTextSize(error_name).x;
    ImGui::SetNextWindowSize(ImVec2(text_size.x + 30, text_size.y), ImGuiCond_Always);

    ImGui::Begin("Error", nullptr, ImGuiWindowFlags_NoDecoration);
    ImGui::Text(error_name);
    ImGui::SameLine();
    ImGui::Text(message_c_str);
    ImGui::End();
}

void menu_bar_ui(const osi::Window &window, edit::UIData &data)
{
    if (ImGui::BeginMainMenuBar())
    {
        if (ImGui::BeginMenu("File"))
        {
            file_menu_ui(window, data);
            ImGui::EndMenu();
        }
        if (ImGui::BeginMenu("Phase"))
        {
            phase_menu_ui(window, data);
            ImGui::EndMenu();
        }
        if (ImGui::BeginMenu("Mode"))
        {
            mode_menu_ui(window, data);
            ImGui::EndMenu();
        }
        switch(data.editor_phase)
        {
            case edit::phase::one:
                if (ImGui::BeginMenu("Module"))
                {
                    module_menu_ui(window, data);
                    ImGui::EndMenu();
                }
                break;
            case edit::phase::two:
                if (ImGui::BeginMenu("RofiWorld"))
                {
                    rofiworld_menu_ui(window, data);
                    ImGui::EndMenu();
                }
                break;
        }
        if (ImGui::BeginMenu("Help"))
        {
            help_menu_ui(window, data);
            ImGui::EndMenu();
        }

        ImGui::EndMainMenuBar();
    }
}

void phase_menu_ui(const osi::Window &window, edit::UIData &data)
{
    using enum edit::phase;
    if (ImGui::MenuItem("Module Phase", "Alt + 1", data.editor_phase == one)) 
    {
        data.editor_phase = one;
    }

    if (ImGui::MenuItem("RofiWorld Phase", "Alt + 2", data.editor_phase == two)) 
    {
        data.editor_phase = two;
    }
}

void mode_menu_ui(const osi::Window &window, edit::UIData &data)
{
    using enum edit::phase;
    if (data.editor_phase == one)
        mode_I_menu_ui(window, data);
    else if (data.editor_phase == two)
        mode_II_menu_ui(window, data);
    else
        ASSUMPTION(false);
    
}

void mode_I_menu_ui(const osi::Window &window, edit::UIData &data)
{
    using enum edit::mode_I;
    auto &mode = data.editor_mode_I;

    if (ImGui::MenuItem("Build", "Ctrl + 1", mode == build)) 
    {
        mode = build;
    }
    if (ImGui::MenuItem("Photo", "Ctrl + 2", mode == spectate)) 
    {
        mode = spectate;
    }
    if (ImGui::MenuItem("Debug", "Ctrl + 3", mode == debug)) 
    {
        mode = debug;
    }
}

void mode_II_menu_ui(const osi::Window &window, edit::UIData &data)
{
    using enum edit::mode_II;
    auto &mode = data.editor_mode_II;

    if (ImGui::MenuItem("Build", "Ctrl + 1", mode == build)) 
    {
        mode = build;
    }
    if (ImGui::MenuItem("Photo", "Ctrl + 2", mode == spectate)) 
    {
        mode = spectate;
    }
    if (ImGui::MenuItem("Debug", "Ctrl + 3", mode == debug)) 
    {
        mode = debug;
    }
}

void module_menu_ui(const osi::Window &window, edit::UIData &data)
{
    if (ImGui::MenuItem("Save##SaveModuleMenuItem")) 
    {
        data.save_module_visible = true;
    }
}

void rofiworld_menu_ui(const osi::Window &window, edit::UIData &data)
{
    bool enabled = data.editor_mode_II == edit::mode_II::build 
                   && std::find(data.rofiworld_selection.begin(), data.rofiworld_selection.end(), data.rofiworld) == data.rofiworld_selection.end();
                   
    if (ImGui::MenuItem("Save##SaveRofiWorldMenuIteM", NULL, false, enabled)) 
    {
        data.save_rofiworld_visible = true;
    }

    if (ImGui::MenuItem("New##NewRofiWorldMenuIteM", NULL, false, data.editor_mode_II == edit::mode_II::build)) 
    {
        data.start_new_rofiworld_visible = true;
    }

    rofiworld_selection_menu_ui(window, data);
}

void rofiworld_selection_menu_ui(const osi::Window &window, edit::UIData &data)
{
    

    if (ImGui::BeginMenu("Select##SelectRofiWorldMenu", data.editor_mode_II == edit::mode_II::build)) 
    {
        for (int i = 0; i < data.rofiworld_selection.size(); ++i)
        {
            const auto rw = data.rofiworld_selection[i];
            const auto label_string = rw->getName() + std::string("##RofiWorldSelection") + std::to_string(i);
            const char* label = label_string.c_str();
            if (ImGui::MenuItem(label, NULL, data.rofiworld == rw)) 
            {
                data.select_rofiworld_prompt = true;
                data.selected_rofiworld = rw;
            }
        }

        ImGui::EndMenu();
    }
}

void file_menu_ui(const osi::Window &window, edit::UIData &data)
{
    using namespace edit;
    bool available = (data.editor_mode_I == mode_I::build && data.editor_phase == phase::one)
                     || (data.editor_mode_II == mode_II::build && data.editor_phase == phase::two);
    if (ImGui::MenuItem("Export Configuration", NULL, false, available)) 
    {
        data.export_file_visible = true;
    }

    if (data.editor_phase == phase::one)
        return;
    
    if (ImGui::MenuItem("Import Configuration", NULL, false, available)) 
    {
        data.import_file_visible = true;
    }
}

void help_menu_ui(const osi::Window &window, edit::UIData &data)
{
    if (ImGui::MenuItem("Controls")) 
    {
        data.help_controls = true;
    }
}

void phase_one_ui(const osi::Window &window, edit::UIData &data)
{
    using enum edit::mode_I;
    switch(data.editor_mode_I)
    {
        case build:
            mode_I_build_ui(window, data);
            break;
        case spectate:
            spectate_ui(window);
            break;
        case debug:
            debug_controls(data.control_state);
            break;
    }
}

void phase_two_ui(const osi::Window &window, edit::UIData &data)
{
    using enum edit::mode_II;
    switch(data.editor_mode_II)
    {
        case build:
            mode_II_build_ui(window, data);
            break;
        case spectate:
            spectate_ui(window);
            break;
        case debug:
            debug_controls(data.control_state);
            break;
    }
}

void mode_I_build_ui(const osi::Window &window, edit::UIData &data)
{
    mode_I_build_selection_ui(window, data);
    build_toolbar_ui(window, data);
    save_module_ui(window, data);
    export_file_ui(window, data);
    import_file_ui(window, data);

    create_pad_ui(window, data);
    rotation_settings(window, data);
    experimental_warning(window, data);
}

void mode_II_build_ui(const osi::Window &window, edit::UIData &data)
{
    module_id_ui(window, data);
    module_change_id_ui(window, data);
    mode_II_build_selection_ui(window, data);
    module_selection_ui(window, data);
    module_connection_ui(window, data);
    module_movement_ui(window, data);
    module_rotation_ui(window, data);
    component_rotation_ui(window, data);
    export_file_ui(window, data);
    import_file_ui(window, data);
    save_rofiworld_ui(window, data);
    start_new_rofiworld_ui(window, data);
}

int build_mode_I_to_int(edit::build_mode_I mode)
{
    using enum edit::build_mode_I;
    switch(mode)
    {
        case cube:
            return 0;
        case universal:
            return 1;
        case pad:
            return 2;
        case unknown:
            return 3;
        default:
            ASSUMPTION(false);
            return -1;
    }
}

edit::build_mode_I int_to_build_mode_I(int value)
{
    edit::build_mode_I build_mode_I;
    switch(value)
    {
        using enum edit::build_mode_I;
        case 0:
            build_mode_I = cube;
            break;
        case 1:
            build_mode_I = universal;
            break;
        case 2:
            build_mode_I = pad;
            break;
        case 3:
            build_mode_I = unknown;
            break;
        default:
            ASSUMPTION(false);
            break;
    }
    return build_mode_I;
}

void mode_I_build_selection_ui(const osi::Window &window, edit::UIData &data)
{
    const char* items[] = { "Cube", "Universal", "Pad", "Unknown" };
    int item_current_idx = build_mode_I_to_int(data.editor_build_mode_I); // Here we store our selection data as an index.
    const auto preview = std::string("Build Mode: ") + std::string(items[item_current_idx]);
    const char* combo_preview_value = preview.c_str();  // Pass in the preview value visible before opening the combo (it could be anything)
    
    ImGui::Begin("##ModeIBuildSelectionCombo", NULL, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground);
    if (ImGui::BeginCombo("##ModeIBuildSelection", combo_preview_value, ImGuiComboFlags_HeightSmall | ImGuiComboFlags_NoArrowButton))
    {
        for (int n = 0; n < IM_ARRAYSIZE(items); n++)
        {
            const bool is_selected = (item_current_idx == n);
            if (ImGui::Selectable(items[n], is_selected))
            {
                item_current_idx = n;
                data.editor_build_mode_I = int_to_build_mode_I(item_current_idx);
            }

            // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
            if (is_selected)
                ImGui::SetItemDefaultFocus();
        }
        ImGui::EndCombo();
    }

    ImGui::End();
}

int build_mode_II_to_int(edit::build_mode_II mode)
{
    using enum edit::build_mode_II;
    switch(mode)
    {
        case add_module:
            return 0;
        case connect_module:
            return 1;
        case manipulate_module:
            return 2;
        case rotate_component:
            return 3;
        default:
            ASSUMPTION(false);
            return -1;
    }
}

edit::build_mode_II int_to_build_mode_II(int value)
{
    edit::build_mode_II build_mode_II;
    switch(value)
    {
        using enum edit::build_mode_II;
        case 0:
            build_mode_II = add_module;
            break;
        case 1:
            build_mode_II = connect_module;
            break;
        case 2:
            build_mode_II = manipulate_module;
            break;
        case 3:
            build_mode_II = rotate_component;
            break;
        default:
            ASSUMPTION(false);
            break;
    }
    return build_mode_II;
}

void mode_II_build_selection_ui(const osi::Window &window, edit::UIData &data)
{
    const char* items[] = { "Add Module", "Connect Module", "Manipulate Module", "Rotate Component" };
    int item_current_idx = build_mode_II_to_int(data.editor_build_mode_II); // Here we store our selection data as an index.
    const auto preview = std::string("Build Mode: ") + std::string(items[item_current_idx]);
    const char* combo_preview_value = preview.c_str();  // Pass in the preview value visible before opening the combo (it could be anything)
    
    ImGui::Begin("##ModeIIBuildSelectionCombo", NULL, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground);
    if (ImGui::BeginCombo("##ModeIIBuildSelection", combo_preview_value, ImGuiComboFlags_HeightSmall | ImGuiComboFlags_NoArrowButton))
    {
        for (int n = 0; n < IM_ARRAYSIZE(items); n++)
        {
            const bool is_selected = (item_current_idx == n);
            if (ImGui::Selectable(items[n], is_selected))
            {
                item_current_idx = n;
                data.editor_build_mode_II = int_to_build_mode_II(item_current_idx);
            }

            // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
            if (is_selected)
                ImGui::SetItemDefaultFocus();
        }
        ImGui::EndCombo();
    }

    ImGui::End();
}

void build_toolbar_ui(const osi::Window &window, edit::UIData &data)
{
    if (data.allowed_components.empty())
        return;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);

	ImGui::SetNextWindowPos(ImVec2(size_x * 0.5f, size_y), ImGuiCond_Always, ImVec2(0.5f, 1.0f));
	ImGui::SetNextWindowSize(ImVec2(build_toolbar_button_width * data.allowed_components.size(), build_toolbar_height));

	ImGuiWindowFlags window_flags = 0
		| ImGuiWindowFlags_NoTitleBar 
		| ImGuiWindowFlags_NoResize 
		| ImGuiWindowFlags_NoMove 
		| ImGuiWindowFlags_NoScrollbar 
		| ImGuiWindowFlags_NoSavedSettings
		;
	ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
	ImGui::Begin("Toolbar", NULL, window_flags);
	ImGui::PopStyleVar();
  
	build_toolbar_buttons(data);
  
	ImGui::End();
}

void build_toolbar_buttons(edit::UIData &data)
{
    using namespace rofi;
    auto button_relative_offset = 20.0f;
    set_build_toolbar_button_colors(data);

    std::map<component, const char*> buttons = { 
        {component::voxel, "Cube"}, 
        {component::fixed_con, "Fixed"}, 
        {component::open_con, "RoFICoM"}, 
        {component::rotation_con, "Shoe"},
        {component::shared_rotation_con, "Body Joint"}
    };

    for (auto &comp : data.allowed_components)
    {
        if (ImGui::Button(buttons[comp]))
        {
            data.chosen_component = comp;
        }
        ImGui::SameLine();
        ImGui::SetCursorPosX(ImGui::GetCursorPosX() + button_relative_offset);
        ImGui::PopStyleColor();
    }
}

void set_build_toolbar_button_colors(edit::UIData &data)
{
    int component_count = static_cast<int>(data.allowed_components.size());
    for (int i = component_count - 1; i >= 0; --i)
    {
        ImVec4 color = data.allowed_components[i] == data.chosen_component ? ImVec4(0.1f, 0.3f, 0.1f, 1.0f) : ImVec4(0.4f, 0.4f, 0.4f, 1.0f);
        ImGui::PushStyleColor(ImGuiCol_Button, color);
    }
}

const std::vector<std::pair<const std::string&, const std::string&>> get_module_selection_names_types(edit::UIData &data)
{
    std::vector<std::pair<const std::string&, const std::string&>> names_types;
    for (auto &mod : data.modules)
        names_types.emplace_back(std::pair<const std::string&, const std::string&>{mod->getName(), mod->getType()});
    
    return names_types;
}

void create_pad_ui(const osi::Window &window, edit::UIData &data)
{
    if (data.editor_build_mode_I != edit::build_mode_I::pad)
        return;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(size_x, size_y - 40.0f), ImGuiCond_Always, ImVec2(1.0f, 1.0f));

    ImGui::Begin("Choose Pad Dimensions##PadCreateMenu", NULL, ImGuiWindowFlags_NoMove 
                                                              | ImGuiWindowFlags_NoResize 
                                                              | ImGuiWindowFlags_NoCollapse 
                                                              | ImGuiWindowFlags_AlwaysAutoResize);

    int width = static_cast<int>(data.selected_pad_width);
    int height = static_cast<int>(data.selected_pad_height);
    ImGui::InputInt("Width", &width, 1, 1);
    ImGui::InputInt("Height", &height, 1, 1);

    if (ImGui::Button("Create"))
        data.is_creating_pad = true;

    ImGui::End();

    data.selected_pad_width = width > 0 ? static_cast<std::size_t>(width) : 1;                        
    data.selected_pad_height = height > 0 ? static_cast<std::size_t>(height) : 1;                        
}

void module_id_ui(const osi::Window &window, edit::UIData &data)
{
    if (!data.selected_module)
        return;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(0, size_y), ImGuiCond_Always, ImVec2(0.0f, 1.0f));

    ImGui::Begin("##ModuleID", NULL, ImGuiWindowFlags_NoDecoration 
                                     | ImGuiWindowFlags_NoFocusOnAppearing 
                                     | ImGuiWindowFlags_NoBackground 
                                     | ImGuiWindowFlags_NoMove 
                                     | ImGuiWindowFlags_AlwaysAutoResize);
    ImGui::Text(std::string("Module ID: " + std::to_string(data.rofiworld->getModuleID(data.selected_module))).c_str());
    ImGui::End();
}

void module_change_id_ui(const osi::Window &window, edit::UIData &data)
{
    if (data.editor_build_mode_II != edit::build_mode_II::add_module || !data.selected_module)
        return;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(0, size_y - 40.0f), ImGuiCond_Always, ImVec2(0.0f, 1.0f));

    auto ui_id = data.rofiworld->getModuleID(data.selected_module);

    ImGui::Begin("Change ID##ChangeModuleID", NULL, ImGuiWindowFlags_NoResize 
                                                    | ImGuiWindowFlags_NoMove 
                                                    | ImGuiWindowFlags_NoCollapse 
                                                    | ImGuiWindowFlags_AlwaysAutoResize);

    bool input_change = ImGui::InputScalar("##ChangeModuleIDInput", ImGuiDataType_U64, &ui_id, NULL, NULL, NULL, ImGuiInputTextFlags_EnterReturnsTrue);
    if(input_change)
    {
        if (data.rofiworld->containsID(ui_id))
            data.ui_error_start_second = data.current_second;
        else
            data.rofiworld->changeModuleID(data.selected_module, ui_id);
    }

    if (data.current_second - data.ui_error_start_second < 2)
        ImGui::Text("ID already used.");
    else
        ImGui::NewLine();

    ImGui::End();
}

void module_selection_ui(const osi::Window &window, edit::UIData &data)
{
    if (data.editor_build_mode_II != edit::build_mode_II::add_module)
        return;

    // Using the generic BeginListBox() API, you have full control over how to display the combo contents.
    // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
    // stored in the object itself, etc.)
    const std::vector<std::pair<const std::string&, const std::string&>> names_types = get_module_selection_names_types(data);

    if (!data.selected_add_module)
        data.add_module_list_index = -1;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(size_x, size_y - 40.0f), ImGuiCond_Always, ImVec2(1.0f, 1.0f));

    ImGui::Begin("Modules##ModuleSelectionListBox", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize);
    if (ImGui::BeginListBox("##ModuleSelection"))
    {
        for (int n = 0; n < names_types.size(); n++)
        {
            auto & [name, type] = names_types[n];
            bool is_selected = (data.add_module_list_index == n);
            const auto label_string = name + " (" + type + ")" + "##ModuleSelectionItem" + std::to_string(n);
            const char* label = label_string.c_str();
            if (ImGui::Selectable(label, is_selected))
            {
                if (!is_selected)
                {
                    data.add_module_list_index = n;
                    data.selected_add_module = data.modules[n];
                }
                else
                {
                    data.add_module_list_index = -1;
                    is_selected = false;
                    data.selected_add_module = nullptr;
                }
            }

            // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
            if (is_selected)
                ImGui::SetItemDefaultFocus();
        }
        ImGui::EndListBox();
    }
    ImGui::End();
}

void module_connection_ui(const osi::Window &window, edit::UIData &data)
{
    using namespace rofi;
    if (data.editor_build_mode_II != edit::build_mode_II::connect_module 
        || (data.selected_connectors.first == nullptr 
            && data.selected_connectors.second == nullptr))
        return;

    bool both_connectors_selected = data.selected_connectors.first != nullptr 
                                    && data.selected_connectors.second != nullptr;
    if (!both_connectors_selected)
        data.is_connecting_modules = false;


    const auto fst_connector = data.selected_connectors.first;
    const auto snd_connector = data.selected_connectors.second;
    const auto fst_module = data.selected_modules_connect.first;
    const auto snd_module = data.selected_modules_connect.second;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(size_x, size_y - 40.0f), ImGuiCond_Always, ImVec2(1.0f, 1.0f));

    ImGui::Begin("Connect##ModuleConnectionMenu", NULL, ImGuiWindowFlags_NoMove 
                                                              | ImGuiWindowFlags_NoResize 
                                                              | ImGuiWindowFlags_NoCollapse 
                                                              | ImGuiWindowFlags_AlwaysAutoResize);

    if (fst_connector)
    {
        ImGui::Text("Source Connector: ");
        ImGui::SameLine();
        std::string s_con = !fst_module->getConnectorDocks().empty()
                            ? fst_module->getConnectorDock(fst_connector)
                            : std::to_string(fst_module->getComponentID(fst_connector));
        ImGui::Text(s_con.c_str());                                    
    }
    else
        ImGui::NewLine();

    if (snd_connector)
    {
        ImGui::Text("Target Connector: ");
        ImGui::SameLine();
        std::string t_con = !snd_module->getConnectorDocks().empty()
                            ? snd_module->getConnectorDock(snd_connector)
                            : std::to_string(snd_module->getComponentID(snd_connector));
        ImGui::Text(t_con.c_str());
    }
    else    
        ImGui::NewLine();

    if (!both_connectors_selected)
    {
        for (int i = 0; i < 6; ++i)
            ImGui::NewLine();
        ImGui::End();
        return;
    }

    using enum cardinal;
    
    if (Connector::shares_module_link(fst_connector, snd_connector))
    {
        ImGui::Text("Mutual Orientation:");
        std::string orientation;
        switch(Connector::get_mutual_orientation(fst_connector, snd_connector))
        {
            case North: 
                orientation = "North";
                break;
            case East:  
                orientation = "East";
                break;
            case South:  
                orientation = "South";
                break;
            case West:  
                orientation = "West";
                break;
            case Invalid:
                orientation = "Invalid";
                break;
        }
        ImGui::Text(orientation.c_str());
        ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.7f, 0.0f, 0.0f, 1.0f));
        data.is_connecting_modules = ImGui::Button("Disconnect");
        
        if (ImGui::IsItemHovered())
            ImGui::SetTooltip("Disconnect (M)");
        ImGui::PopStyleColor();
    }
    else
    {
        int selection = static_cast<int>(data.selected_cardinality);
        ImGui::RadioButton("North", &selection, 0);                       
        ImGui::RadioButton("East", &selection, 1);                       
        ImGui::RadioButton("South", &selection, 2);                       
        ImGui::RadioButton("West", &selection, 3);
        data.selected_cardinality = selection == 0 ? North : selection == 1 ? East : selection == 2 ? South : West;
        
        if (!data.can_connect_modules)
        {
            ImGui::Text("Cannot Connect.");
        }
        else
        {
            ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.7f, 1.0f));
            data.is_connecting_modules = ImGui::Button("Connect");
            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Connect (M)");
            ImGui::PopStyleColor();
        }
    }


    ImGui::End();
}

void module_movement_ui(const osi::Window &window, edit::UIData &data)
{
    if (data.editor_build_mode_II != edit::build_mode_II::manipulate_module || !data.selected_module)
        return;

    const char *input_labels[3] = { "X##ModuleMovementInputX", "Y##ModuleMovementInputY", "Z##ModuleMovementInputZ" };
    auto position = convert_to_rofi_coordinates(data.selected_module->getNode()->getPositionWorld());
    const auto prev_position = position;

    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(0, size_y - 40.0f), ImGuiCond_Always, ImVec2(0.0f, 1.0f));

    ImGui::Begin("Module Position##ModuleMovementMenu", NULL, ImGuiWindowFlags_NoMove 
                                                              | ImGuiWindowFlags_NoResize 
                                                              | ImGuiWindowFlags_NoCollapse 
                                                              | ImGuiWindowFlags_AlwaysAutoResize);

    ImGui::DragFloat("Step", &data.module_translation_step, 0.25f, 0.0f, 100.0f, "%.3f", ImGuiSliderFlags_AlwaysClamp);

    for (int i = 0; i < 3; ++i)
        if (ImGui::InputFloat(input_labels[i], &position[i], data.module_translation_step, 1.0f, "%.3f"))
            continue;

    if (ImGui::Button("Reset##ZeroModulePos"))
        position = glm::vec3(0.0f);

    ImGui::End();

    data.module_position = convert_to_editor_coordinates(position - prev_position);
    data.is_moving_module = data.module_position != glm::vec3(0.0f);
}


void module_rotation_ui(const osi::Window &window, edit::UIData &data)
{
    if (data.editor_build_mode_II != edit::build_mode_II::manipulate_module || !data.selected_module)
        return;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(size_x, size_y - 40.0f), ImGuiCond_Always, ImVec2(1.0f, 1.0f));

    ImGui::Begin("Module Rotation##ModuleRotationMenu", NULL, ImGuiWindowFlags_NoMove 
                                                              | ImGuiWindowFlags_NoResize 
                                                              | ImGuiWindowFlags_NoCollapse 
                                                              | ImGuiWindowFlags_NoScrollbar);

    ImGui::DragFloat("Step", &data.module_rotation_step, 0.25f, 0.0f, 90.0f, "%.3f", ImGuiSliderFlags_AlwaysClamp);

    glm::vec3 euler_angles = convert_to_rofi_coordinates(glm::eulerAngles(data.selected_module->getNode()->getRotationWorld()));
    euler_angles = glm::degrees(euler_angles);
    glm::vec3 prev_euler_angles = euler_angles;



    ImGui::Text("Rotation Axes:");
    ImGui::RadioButton("Local", &data.coordinate_space_selection, 0); 
    ImGui::SameLine();
    ImGui::RadioButton("World", &data.coordinate_space_selection, 1);

    ImGui::Text("Input:");
    ImGui::RadioButton("Drag", &data.module_rotation_input, 0); 
    ImGui::SameLine();
    ImGui::RadioButton("Manual", &data.module_rotation_input, 1);

    ImGui::Separator();

    ImGui::Text("World Space Angles");
    if (data.module_rotation_input == 0)
        module_rotation_drag(data, euler_angles);
    else
        module_rotation_manual(data, euler_angles);

    data.is_resetting_module_rotation = ImGui::Button("Reset##ZeroModuleRotation");

    ImGui::End();

    data.module_rotation_angles = convert_to_editor_coordinates(euler_angles - prev_euler_angles);
    data.is_rotating_module = data.is_resetting_module_rotation 
                              || (data.module_rotation_step != 0.0f && data.module_rotation_angles != glm::vec3(0.0f, 0.0f, 0.0f));
}

void module_rotation_drag(edit::UIData &data, glm::vec3 &euler_angles)
{
    const char *button_labels[6] = { "##Arrow-X", "##Arrow-Y", "##Arrow-Z", "##Arrow+X", "##Arrow+Y", "##Arrow+Z" };
    const char *drag_labels[3] = { "X##ModuleRotationDragX", "Y##ModuleRotationDragY", "Z##ModuleRotationDragZ" };

    float min_limit = -360.0f;
    float max_limit = 360.0f;

    for (int i = 0; i < 3; ++i)
    {
        if (ImGui::ArrowButton(button_labels[i], ImGuiDir_Left))
            euler_angles[i] = glm::clamp(euler_angles[i] - data.module_rotation_step, min_limit, max_limit);
        ImGui::SameLine();
        ImGui::DragFloat(drag_labels[i], &euler_angles[i], data.module_rotation_step, min_limit, max_limit, "%.3f°", 
                         ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_NoInput);
        ImGui::SameLine();
        if (ImGui::ArrowButton(button_labels[i + 3], ImGuiDir_Right))
            euler_angles[i] = glm::clamp(euler_angles[i] + data.module_rotation_step, min_limit, max_limit);
    }
}
void module_rotation_manual(edit::UIData &data, glm::vec3 &euler_angles)
{
    const char *input_labels[3] = { "X##ModuleRotationInputX", "Y##ModuleRotationInputY", "Z##ModuleRotationInputZ" };
    for (int i = 0; i < 3; ++i)
    {
        ImGui::InputFloat(input_labels[i], &euler_angles[i], data.module_rotation_step, data.module_rotation_step, "%.3f°", 
                          ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue);
    }
}

void component_rotation_ui(const osi::Window &window, edit::UIData &data)
{
    if (data.editor_build_mode_II != edit::build_mode_II::rotate_component || !data.selected_module || !(data.voxel_selected || data.connector_selected))
        return;

    float min_limit = -360.0f;
    float max_limit = 360.0f;
    float current_rotation = 0.0f;
    float prev_rotation = 0.0f;
    std::string component_info;

    if (data.connector_selected)
    {
        component_info = data.selected_module->getConnectorDock(data.connector) == "A-Z" ? "Shoe A" : "Shoe B";
        auto rot_con = std::dynamic_pointer_cast<rofi::RotationConnector>(data.connector);
        min_limit = rot_con->getNegRotationLimit();
        max_limit = rot_con->getPosRotationLimit();
        current_rotation = rot_con->getCurrentRotation();
    }
    else
    {
        component_info = data.voxel->getNode()->getPositionLocal() == glm::vec3(0.0f) ? "Body A" : "Body B";
        auto voxel_y_axis = data.voxel->getNode()->getRotationAxisYLocal();
        auto rotated_angle_rad = glm::orientedAngle(glm::vec3(0.0f, 1.0f, 0.0f), voxel_y_axis, glm::vec3(0.0f, 0.0f, 1.0f));

        current_rotation = voxel_y_axis.z < 0.0f ? -glm::degrees(rotated_angle_rad) : glm::degrees(rotated_angle_rad);
        current_rotation = component_info == "Body A" ? -current_rotation : current_rotation;
    }
    prev_rotation = current_rotation;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(size_x, size_y - 40.0f), ImGuiCond_Always, ImVec2(1.0f, 1.0f));

    ImGui::Begin("Component Rotation##ComponentRotationMenu", NULL, ImGuiWindowFlags_NoMove 
                                                              | ImGuiWindowFlags_NoResize 
                                                              | ImGuiWindowFlags_NoCollapse 
                                                              | ImGuiWindowFlags_AlwaysAutoResize);

    ImGui::Text(component_info.c_str());                                                          

    ImGui::DragFloat("Step", &data.component_rotation_step, 0.25f, 0.0f, 90.0f, "%.3f", ImGuiSliderFlags_AlwaysClamp);

    if (ImGui::ArrowButton("##ArrowLeftCompRot", ImGuiDir_Left))
        current_rotation = glm::clamp(current_rotation - data.component_rotation_step, min_limit, max_limit);

    ImGui::SameLine();

    ImGui::DragFloat("##ComponentRotationDrag", &current_rotation, data.component_rotation_step, min_limit, max_limit, "%.3f°", ImGuiSliderFlags_AlwaysClamp);
    
    ImGui::SameLine();
    
    if (ImGui::ArrowButton("##ArrowRightCompRot", ImGuiDir_Right))
        current_rotation = glm::clamp(current_rotation + data.component_rotation_step, min_limit, max_limit);

    ImGui::End();

    data.component_rotation_angle = component_info == "Body A" ? prev_rotation - current_rotation : current_rotation - prev_rotation;
    data.is_rotating_component = data.component_rotation_step != 0.0f && data.component_rotation_angle != 0;
}

void save_module_ui(const osi::Window &window, edit::UIData &data)
{
    if (!data.save_module_visible)
        return;
        
    ImGui::SetNextWindowPos(ImVec2(0, mode_toolbar_height * 3), ImGuiCond_Appearing, ImVec2(0.0f, 0.0f));

    if (!ImGui::Begin("Save Module Configuration", &data.save_module_visible, ImGuiWindowFlags_NoCollapse))
    {
        ImGui::End();
        return;
    }

    ImGui::InputText("Module Name##ModuleNameInput", data.name_buffer, sizeof(data.name_buffer), 
                     ImGuiInputTextFlags_AutoSelectAll);

    ImGui::InputInt("Module ID##SaveModuleIDInput", &data.module_id, 1, 1, 
                    ImGuiInputTextFlags_AutoSelectAll
                    | ImGuiInputTextFlags_CharsDecimal);

    if (data.save_module_error && data.current_second - data.error_start_second < 2)
        ImGui::Text(data.error_msg.c_str());
    else
    {
        data.save_module_error = false;
        ImGui::NewLine();
    }
    
    if (ImGui::Button("Submit##SaveModuleButton")) {
        data.save_module_prompt = true;
        data.export_file_prompt = true;
        data.save_module_visible = false;
    }

    ImGui::End();
}

void save_rofiworld_ui(const osi::Window &window, edit::UIData &data)
{
    if (!data.save_rofiworld_visible)
        return;

    ImGui::SetNextWindowPos(ImVec2(0, mode_toolbar_height * 3), ImGuiCond_Appearing, ImVec2(0.0f, 0.0f));

    if (!ImGui::Begin("Save RofiWorld Configuration", &data.save_rofiworld_visible, 
                      ImGuiWindowFlags_NoCollapse 
                      | ImGuiWindowFlags_NoResize 
                      | ImGuiWindowFlags_AlwaysAutoResize))
    {
        ImGui::End();
        return;
    }

    const auto flags = data.save_rofiworld_use_current_name 
                       ? ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_ReadOnly
                       : ImGuiInputTextFlags_AutoSelectAll;

    ImGui::Text("RofiWorld Name:");
    ImGui::InputText("##ModuleNameInput", data.name_buffer, sizeof(data.name_buffer), flags);

    const auto label_string = "Use Current Name: " + data.rofiworld->getName() + "##SaveRofiWorldUseCurrentName";
    const auto label = label_string.c_str();
    ImGui::Checkbox(label, &data.save_rofiworld_use_current_name);

    if (ImGui::Button("Submit##SaveRofiWorldButton")) {
        data.save_rofiworld_prompt = true;
        data.save_rofiworld_visible = false;
    }

    ImGui::End();
}

void export_file_ui(const osi::Window &window, edit::UIData &data)
{
    if (!data.export_file_visible)
        return;

    ImGui::SetNextWindowPos(ImVec2(0, mode_toolbar_height * 3), ImGuiCond_Appearing, ImVec2(0.0f, 0.0f));

    if (data.editor_phase == edit::phase::one)
        export_module_file_ui(window, data);
    else if (data.editor_phase == edit::phase::two)
        export_rofiworld_file_ui(window, data);

}

void export_module_file_ui(const osi::Window &window, edit::UIData &data)
{
    if (!ImGui::Begin("Export Module Configuration", &data.export_file_visible, 
                      ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize))
    {
        ImGui::End();
        return;
    }

    ImGui::Text("Enter Text:");
    
    // InputText takes a pointer to a buffer, a maximum buffer size, and optional flags
    ImGui::InputText("File Name##ModuleFileNameInput", data.name_buffer, sizeof(data.name_buffer), 
                     ImGuiInputTextFlags_AutoSelectAll);

    ImGui::InputInt("Module ID##ExportModuleIDInput", &data.module_id, 1, 1,
                     ImGuiInputTextFlags_AutoSelectAll
                     | ImGuiInputTextFlags_CharsDecimal);

    if (data.export_file_error && data.current_second - data.error_start_second < 2)
        ImGui::Text(data.error_msg.c_str());
    else
    {
        data.export_file_error = false;
        ImGui::NewLine();
    }

    if (ImGui::Button("Submit##ExportModuleButton")) {
        data.export_file_prompt = true;
        data.export_file_visible = false;
    }

    ImGui::End();
}

void export_rofiworld_file_ui(const osi::Window &window, edit::UIData &data)
{
    if (!ImGui::Begin("Export RofiWorld Configuration", &data.export_file_visible, 
                      ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
    {
        ImGui::End();
        return;
    }

    ImGui::Text("Enter Text:");
    
    // InputText takes a pointer to a buffer, a maximum buffer size, and optional flags
    if (ImGui::InputText("File Name##RofiWorldExportFileNameInput", data.name_buffer, sizeof(data.name_buffer), 
                     ImGuiInputTextFlags_AutoSelectAll
                     | ImGuiInputTextFlags_EnterReturnsTrue))
    {
        data.export_file_prompt = true;
        data.export_file_visible = false;
    }

    if (data.export_file_error && data.current_second - data.error_start_second < 2)
        ImGui::Text(data.error_msg.c_str());
    else
    {
        data.export_file_error = false;
        ImGui::NewLine();
    }

    ImGui::Checkbox("Selected Module as spaceJoint##spaceJointCheckBox", &data.export_rofiworld_use_selected_space_joint);

    if (ImGui::Button("Submit##ExportRofiWorldButton")) {
        data.export_file_prompt = true;
        data.export_file_visible = false;
    }

    ImGui::End();
}

void import_file_ui(const osi::Window &window, edit::UIData &data)
{
    if (!data.import_file_visible)
        return;

    ImGui::SetNextWindowPos(ImVec2(0, mode_toolbar_height * 3), ImGuiCond_Appearing, ImVec2(0.0f, 0.0f));

    import_rofiworld_file_ui(window, data);
}

void import_rofiworld_file_ui(const osi::Window &window, edit::UIData &data)
{
    if (!ImGui::Begin("Import RofiWorld Configuration", &data.import_file_visible, 
                      ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
    {
        ImGui::End();
        return;
    }

    ImGui::Text("Enter name of file");
    ImGui::Text("from /data/rofi/rofiworlds/:");
    
    // InputText takes a pointer to a buffer, a maximum buffer size, and optional flags
    if (ImGui::InputText(".json##RofiWorldImportFileNameInput", data.name_buffer, sizeof(data.name_buffer), 
                     ImGuiInputTextFlags_AutoSelectAll
                     | ImGuiInputTextFlags_EnterReturnsTrue))
    {
        data.import_file_prompt = true;
        data.import_file_visible = false;
    }

    if (data.import_file_error && data.current_second - data.error_start_second < 2)
        ImGui::Text(data.error_msg.c_str());
    else
    {
        data.import_file_error = false;
        ImGui::NewLine();
    }

    if (ImGui::Button("Submit##ImportRofiWorldButton")) {
        data.import_file_prompt = true;
        data.import_file_visible = false;
    }

    ImGui::End();
}

void start_new_rofiworld_ui(const osi::Window &window, edit::UIData &data)
{
    if (!data.start_new_rofiworld_visible)
        return;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(size_x * 0.5f, size_y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f));

    ImGui::Begin("New RofiWorld##NewRofiWorldConfirm", &data.start_new_rofiworld_visible, 
                 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove);

    ImGui::Text("Do you want to start a new RofiWorld?");
    ImGui::Text("Any unsaved configuration will be lost.");

    if (ImGui::Button("Confirm##NewRofiWorldConfirmButton"))
    {
        data.start_new_rofiworld_prompt = true;
        data.start_new_rofiworld_visible = false;
    }
    ImGui::SameLine();

    if (ImGui::Button("Cancel##NewRofiWorldConfirmButton"))
    {
        data.start_new_rofiworld_visible = false;
    }

    ImGui::End();
}

void rotation_settings(const osi::Window &window, edit::UIData &data)
{
    if (!data.connector_selected 
        || data.connector->getType(true) != rofi::connector_type::rotation)
        return;

    /* RoFI */
    auto rot_con = std::dynamic_pointer_cast<rofi::RotationConnector>(data.connector);
    if (!rot_con->isHead())
        return;

    auto &neg_ref = rot_con->getNegRotationLimit();
    auto &pos_ref = rot_con->getPosRotationLimit();

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(size_x, size_y - 40.0f), ImGuiCond_Always, ImVec2(1.0f, 1.0f));

    ImGui::Begin("Rotation Limits", NULL, ImGuiWindowFlags_NoMove 
                                          | ImGuiWindowFlags_NoResize 
                                          | ImGuiWindowFlags_NoCollapse 
                                          | ImGuiWindowFlags_AlwaysAutoResize);

    ImGui::DragFloatRange2("##RotationLimitsRange", &neg_ref, &pos_ref, 0.25f, -90.0f, 90.0f, "Min: %.3f°", "Max: %.3f°", ImGuiSliderFlags_AlwaysClamp);
    
    ImGui::End();
}

void experimental_warning(const osi::Window &window, edit::UIData &data)
{
    if (data.editor_build_mode_I != edit::build_mode_I::unknown)
        return;

    float size_x = static_cast<float>(window.size().x);
    float size_y = static_cast<float>(window.size().y);
    ImGui::SetNextWindowPos(ImVec2(size_x * 0.5f, size_y * 0.25f), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
    ImGui::Begin("##ExperimentalWarning", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoMove);
    ImGui::Text("WARNING: Experimental Mode! Use at own risk.");
    ImGui::End();
}

void spectate_ui(const osi::Window &window)
{
    const char* message = "Press H to toggle UI";
    auto text_size = ImGui::CalcTextSize(message);
    text_size.x += 15.0f;
    ImGui::SetNextWindowPos(ImVec2(window.size().x / 2 - text_size.x / 2, 
                                   window.size().y - text_size.y - 15.0f), 
                            ImGuiCond_Always);
    ImGui::Begin("Spectate Hint", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground);
    ImGui::Text(message);
    ImGui::End();
}

void debug_controls(edit::state &control_state)
{
    using namespace edit;
    ImGui::SetNextWindowPos(ImVec2(0, mode_toolbar_height + 5.0f));
    ImGui::SetNextWindowSize(ImVec2(ImGui::CalcTextSize("Select Move Rotate +").x * 1.5f, 80));
    ImGui::Begin("Debug Controls", nullptr, ImGuiWindowFlags_NoMove 
                                      | ImGuiWindowFlags_NoResize 
                                      | ImGuiWindowFlags_NoCollapse);
	    ImGui::Text("Operation: %s", state_to_str(control_state).c_str());

        if (ImGui::Button("Select"))
            control_state = state::select;
        
        ImGui::SameLine();
        ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);

        if (ImGui::Button("Move"))
            control_state = state::move;

        ImGui::SameLine();
        ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);

        if (ImGui::Button("Rotate"))
            control_state = state::rotate;

        ImGui::SameLine();
        ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);

        if (ImGui::Button("+"))
            control_state = state::plus;

    ImGui::End();
}

std::string state_to_str(edit::state &control_state)
{
    using enum edit::state;
    switch(control_state)
    {
        case select:
            return "Select";
        case move:
            return "Move";
        case rotate:
            return "Rotate";
        case plus:
            return "+";
        default:
            return "Enum Error";
    }
}

void show_help(const osi::Window &window, bool &help_controls_displayed)
{
    if (!help_controls_displayed)
        show_help_minimized(window);
    else
        show_help_controls(window, help_controls_displayed);
}

void show_help_minimized(const osi::Window &window)
{
    const char* message = "Press F1 for help";
    auto text_size = ImGui::CalcTextSize(message);
    text_size.x += 15.0f;
    ImGui::SetNextWindowPos(ImVec2(window.size().x - text_size.x, 
                                   window.size().y - text_size.y - 15.0f), 
                            ImGuiCond_Always);
    ImGui::Begin("Help_Minimized", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoMove);
    ImGui::Text(message);
    ImGui::End();
}
void show_help_controls(const osi::Window &window, bool &help_controls_displayed)
{
    ImGui::SetNextWindowPos(ImVec2(window.size().x * 0.5f, window.size().y * 0.5f), ImGuiCond_Appearing, ImVec2(0.5f,0.5f));
    ImGui::SetNextWindowSize(ImVec2(window.size().x * 0.75f, window.size().y * 0.75f), ImGuiCond_Appearing);
    ImGui::Begin("Controls", &help_controls_displayed, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize);

    ImGui::Text("In the event of encountering a bug, please contact me at 525032@mail.muni.cz");
    ImGui::Separator();
    ImGui::Spacing();

    if (ImGui::BeginTabBar("MyTabBar", ImGuiTabBarFlags_FittingPolicyScroll))
    {
        if (ImGui::BeginTabItem("General"))
        {
            general_controls_tab();
            ImGui::EndTabItem();
        }
        if (ImGui::BeginTabItem("Phase I"))
        {
            phase_i_controls_tab();
            ImGui::EndTabItem();
        }
        if (ImGui::BeginTabItem("Phase II"))
        {
            phase_ii_controls_tab();
            ImGui::EndTabItem();
        }
        ImGui::EndTabBar();
    }

    ImGui::End();
}

void general_controls_tab()
{
    ImGui::SeparatorText("Editor Controls:");
    ImGui::BulletText("Hold 'Left Alt' and press '1' or '2' to select editor phase.");
    ImGui::BulletText("Hold 'Left Ctrl' and press '1' - '3' to select editor mode.");
    ImGui::Spacing();

    ImGui::SeparatorText("Camera Controls:");
    ImGui::BulletText("Hold 'RMB' to look around.");
    ImGui::BulletText("Use 'Mouse Scroll Wheel' to zoom in and out.");
    ImGui::BulletText("Press 'W', 'A', 'S', 'D' to move horizontally.");
    ImGui::BulletText("Press 'R', 'F' to move vertically.");
    ImGui::BulletText("Press 'C' to center the camera to a selected object.");
    ImGui::BulletText("Press 'V' to switch between perspective and orthographic view. (NOTE: This function is experimental)");
    ImGui::Spacing();
}

void phase_i_controls_tab()
{
    ImGui::SeparatorText("Build Controls:");
    ImGui::BulletText("Hold 'Left Shift' and press '1' - '4' to select build mode.");
    ImGui::BulletText("Press '1' - '5' to select component if available.");
    ImGui::BulletText("Press 'LMB' to select an object.");
    ImGui::BulletText("Press 'LMB' to add selected component into the scene.");
    ImGui::BulletText("Press 'Delete' to remove component from the scene.");
    ImGui::Spacing();
}

void phase_ii_controls_tab()
{
    ImGui::SeparatorText("Build Controls:");
    ImGui::BulletText("Hold 'Left Shift' and press '1' - '4' to select build mode.");
    ImGui::Spacing();

    ImGui::SeparatorText("Add Module:");
    ImGui::BulletText("Press 'LMB' to place down a module from Modules list selection.");
    ImGui::BulletText("Press 'Escape' to cancel current Modules list selection.");
    ImGui::BulletText("Press 'LMB' to select a module.");
    ImGui::BulletText("Press 'Delete' to remove a module.");
    ImGui::Spacing();

    ImGui::SeparatorText("Connect Module:");
    ImGui::BulletText("Press 'LMB' to select a RoFICoM.");
    ImGui::BulletText("Press 'Escape' to cancel current RoFICoM selection.");
    ImGui::BulletText("Press 'M' to connect / disconnect two selected modules.");
    ImGui::Spacing();

    ImGui::SeparatorText("Manipulate Module:");
    ImGui::BulletText("Hold 'Left Ctrl' and 'LMB' to move selected module horizontally.");
    ImGui::BulletText("Hold 'Left Shift' and 'LMB' to move selected module vertically.");
    ImGui::Spacing();

    ImGui::SeparatorText("Rotate Component:");
    ImGui::BulletText("Press 'LMB' to select a rotation capable component.");

    ImGui::Spacing();
}
