#include <iostream>
#include <OgreOverlaySystem.h>
#include <OgreOverlayManager.h>
#include <OgreImGuiOverlay.h>
#include <OgreImGuiInputListener.h>
#include <OgreRenderTargetListener.h>
#include <OgreSceneNode.h>
#include <OgreApplicationContext.h>
#include <OgreImGuiInputListener.h>
#include <OgreFontManager.h>
#include <OgreTerrainGroup.h>
#include <OgrePagedWorld.h>
#include <OgreTerrainPaging.h>
#include <OgreTerrainPagedWorldSection.h>
#include <nlohmann/json.hpp>
#include "GameData.h"
#include "Components.h"
#include "LuaData.h"
#include "AppModule.h"
#include "TerrainModule.h"
#include "StaticGeometryModule.h"
#include "EditorGizmoModule.h"
#include "PhysicsModule.h"
#include "items.h"
#include "property_editor.h"
#include "EditorGUIModule.h"
#include "GUIModuleCommon.h"

namespace ECS
{

struct EditorGUIListener;
struct EditorGUIData {
    Ogre::ImGuiOverlay *mGuiOverlay;
    std::vector<Ogre::String> glb_names;
    EditorGUIListener *mGUIListener;
};
struct EditorGUIListener : public Ogre::RenderTargetListener {
    float panel_width;
    bool enableEditor;
    bool enableMapEditor;
    ImFont *smallFont, *midFont, *bigFont;
    Ogre::FontPtr _smallFont, _midFont, _bigFont;
    Ogre::TexturePtr worldMap;
    Ogre::Image worldMapImage;

    EditorGUIListener(Ogre::ImGuiOverlay *overlay)
        : Ogre::RenderTargetListener()
        , enableEditor(false)
        , enableMapEditor(false)
        , keepCameraAbove(true)
        , command(COMMAND_NONE)
    {
        _midFont = createFont("midFont", "General",
                      "Jupiteroid-Regular.ttf", 24.0f);
        _smallFont = createFont("smallFont", "General",
                    "Jupiteroid-Regular.ttf", 18.0f);
        _bigFont = createFont("bigFont", "General", "Kenney Bold.ttf",
                      36.0f);
        smallFont = overlay->addFont("smallFont", "General");
        OgreAssert(smallFont, "Could not load font");
        midFont = overlay->addFont("midFont", "General");
        OgreAssert(midFont, "Could not load font");
        bigFont = overlay->addFont("bigFont", "General");
        OgreAssert(bigFont, "Could not load font");
        worldMapImage.load(
            "world_map.png",
            Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
#if 0
        int x, y, i, j;
        for (y = 0; y < worldMapImage.getWidth(); y++)
            for (x = 0; x < worldMapImage.getWidth(); x++) {
                float r = 0.0f;
                for (i = -2; i < 3; i++)
                    for (j = -2; j < 3; j++) {
                        int xj = Ogre::Math::Clamp(
                            x + j, 0,
                            (int)worldMapImage
                                    .getWidth() -
                                1);
                        int yi = Ogre::Math::Clamp(
                            y + i, 0,
                            (int)worldMapImage
                                    .getHeight() -
                                1);
                        r += worldMapImage
                                 .getColourAt(xj,
                                      yi, 0)
                                 .r;
                    }
                r /= 25.0f;
                Ogre::ColourValue cv =
                    worldMapImage.getColourAt(x, y, 0);
                cv.r = r;
                worldMapImage.setColourAt(cv, x, y, 0);
            }
#endif
        worldMap = Ogre::TextureManager::getSingleton().createManual(
            "worldMap",
            Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
            Ogre::TEX_TYPE_2D, worldMapImage.getWidth(),
            worldMapImage.getHeight(),
            worldMapImage.getNumMipmaps(),
            worldMapImage.getFormat(), Ogre::TU_DYNAMIC_WRITE_ONLY);
        worldMap->loadImage(worldMapImage);
        OgreAssert(worldMap, "could not load world map");
    }
    Ogre::FontPtr createFont(const Ogre::String &name,
                 const Ogre::String &group,
                 const Ogre::String &ttfname, float fontSize)
    {
        Ogre::FontPtr ret =
            Ogre::FontManager::getSingleton().create(name, group);
        ret->setType(Ogre::FontType::FT_TRUETYPE);
        ret->setSource(ttfname);
        ret->setTrueTypeSize(fontSize);
        ret->setTrueTypeResolution(75);
        ret->addCodePointRange(Ogre::Font::CodePointRange(30, 128));
        ret->load();
        return ret;
    }
    void
    preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override
    {
        preview(evt);
    }
    void
    postViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override
    {
#if 0
        if (switchWindow) {
            ECS::get().set<EditorSceneSwitch>({ 1 });
            switchWindow = false;
        }
#endif
    }
#if 0
    bool switchWindow = false;
#endif
    void buttons_panel()
    {
        bool enableDebugRender = ECS::get<EngineData>().enableDbgDraw;

        ImVec2 size = ImGui::GetMainViewport()->Size;
        float window_width = size.x * 0.3f;
        if (window_width > 300)
            window_width = 300;
        float window_height = size.y * 0.5f - 20;
        ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
        ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
                     ImGuiCond_Always);
        ImGui::Begin("Items", NULL, ImGuiWindowFlags_MenuBar);
        Items::itemsEditorMenu();
        Items::itemsEditorHierarchy();
        ImGui::End();
        ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.5f + 20),
                    ImGuiCond_Always);
        ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
                     ImGuiCond_Always);
        ImGui::Begin("Control");
        //		if (ECS::get().get<GUI>().enabled)
        //			ECS::get().get<App>().app->setWindowGrab(true);
        if (ImGui::Button("Quit"))
            Ogre::Root::getSingleton().queueEndRendering();
        if (ImGui::Button("Return"))
            ECS::get().get<GUI>().finish();
        if (ImGui::Checkbox("Enable physics debug",
                    &enableDebugRender)) {
            ECS::get_mut<EngineData>().enableDbgDraw =
                enableDebugRender;
            ECS::modified<EngineData>();
            PhysicsModule::setDebugDraw(enableDebugRender);
        }
#if 0
        if (ImGui::Button("AltCam")) {
            switchWindow = true;
        }
#endif
        if (ImGui::Button("Deploy config")) {
            std::function m = [&](const Ogre::String &src,
                          const Ogre::String &dst) {
                std::ifstream source(src, std::ios::binary);
                std::ofstream destination(dst,
                              std::ios::binary);

                OgreAssert(source.is_open(),
                       "Failed to copy files " + src +
                           " -> " + dst);
                OgreAssert(destination.is_open(),
                       "Failed to copy files " + src +
                           " -> " + dst);
                OgreAssert(source.is_open() &&
                           destination.is_open(),
                       "Failed to copy files " + src +
                           " -> " + dst);
                destination << source.rdbuf();
                destination.close();
                source.close();
            };
            m("resources/buildings/items.list",
              "../../resources/buildings/items.list");
            m("resources/terrain/world_map.png",
              "../../resources/terrain/world_map.png");
        }
        ImGui::Checkbox("Keep camera above 0", &keepCameraAbove);
#if 0
        if (ImGui::Button("Enable/Disable item editor")) {
            enableEditor ^= true;
            if (enableEditor)
                enableMapEditor = false;
        }
        if (ImGui::Button("Enable/Disable map editor")) {
            enableMapEditor ^= true;
            if (enableMapEditor)
                enableEditor = false;
        }
        ImGui::Text("Text message...");
#endif
        ImGui::Checkbox("Enable Map", &enableMapEditor);
        ImGui::End();
    }
    void create_entity_node(const Ogre::String &name, int key)
    {
        Ogre::Entity *ent =
            ECS::get().get<EngineData>().mScnMgr->createEntity(
                name);
        Ogre::SceneNode *pnode =
            ECS::get()
                .get<EngineData>()
                .mScnMgr->getRootSceneNode()
                ->createChildSceneNode(
                    "ent:" + name +
                        Ogre::StringConverter::toString(
                            key),
                    ECS::get()
                        .get<Camera>()
                        .mCameraPivot->getPosition(),
                    ECS::get()
                        .get<Camera>()
                        .mCameraPivot->getOrientation());
        pnode->attachObject(ent);
        Ogre::Quaternion q = pnode->getOrientation();
        Ogre::Radian yaw = q.getYaw();
        Ogre::Quaternion nq(yaw, Ogre::Vector3(0, 1, 0));
        pnode->setOrientation(nq);

        ECS::get().get<GUI>().finish();
    }
#if 0
    void buildings_editor()
    {
        int i;
        ImVec2 size = ImGui::GetMainViewport()->Size;
        float window_width = size.x * 0.2f;
        if (window_width > panel_width)
            window_width = panel_width;
        float window_height = size.y * 0.5 - 20;
        ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
        ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
                     ImGuiCond_Always);
        ImGui::Begin("Droppings...");
        for (i = 0;
             i < ECS::get().get<EditorGUIData>().glb_names.size();
             i++) {
            Ogre::String id_button =
                "Create entity: " +
                ECS::get().get<EditorGUIData>().glb_names[i] +
                "##ent:" +
                ECS::get().get<EditorGUIData>().glb_names[i];
            if (ImGui::Button(id_button.c_str())) {
                create_entity_node(ECS::get()
                               .get<EditorGUIData>()
                               .glb_names[i],
                           i);
            }
        }
        ImGui::End();
    }
#endif
    void position_editor(Ogre::SceneNode *node)
    {
        Ogre::Vector3 position = node->getPosition();
        float v[3] = { position.x, position.y, position.z };
        ImGui::InputFloat3("position", v);
        position.x = v[0];
        position.y = v[1];
        position.z = v[2];
        node->setPosition(position);
    }
    void orientation_editor(Ogre::SceneNode *node)
    {
        Ogre::Quaternion q = node->getOrientation();
        float yaw = Ogre::Radian(q.getYaw()).valueDegrees();
        float pitch = Ogre::Radian(q.getPitch()).valueDegrees();
        float roll = Ogre::Radian(q.getRoll()).valueDegrees();
        bool m1 = ImGui::InputFloat("yaw", &yaw);
        bool m2 = ImGui::InputFloat("pitch", &pitch);
        bool m3 = ImGui::InputFloat("roll", &roll);
        if (m1 || m2 || m3) {
            Ogre::Quaternion q1(Ogre::Radian(Ogre::Degree(yaw)),
                        Ogre::Vector3::UNIT_Y);
            Ogre::Quaternion q2(Ogre::Degree(pitch),
                        Ogre::Vector3::UNIT_X);
            Ogre::Quaternion q3(Ogre::Degree(roll),
                        Ogre::Vector3::UNIT_Z);
            node->setOrientation(q1 * q2 * q3);
        }
    }
    void attachments_editor(Ogre::SceneNode *node)
    {
        const Ogre::SceneNode::ObjectMap &pmap =
            node->getAttachedObjects();
        int i;
        for (i = 0; i < pmap.size(); i++) {
            const Ogre::MovableObject *mobj = pmap[i];
            const Ogre::String &pname = mobj->getName();
            ImGui::Text("Name: %s", pname.c_str());
        }
    }
#if 0
    void map_editor()
    {
    }
#endif
    int pos_x = 0;
    int pos_y = 0;
    int top_x = 0;
    int top_y = 0;
    int selected_x = 0;
    int selected_y = 0;
    bool locationSelected = false;
    float strength = 0.0f;
    int size = 0;
    long slot_x, slot_y;
    float cursorAngle = 0;
    void updateWorldTexture()
    {
        // Get the hardware pixel buffer
        Ogre::HardwarePixelBufferSharedPtr pixelBuffer =
            worldMap->getBuffer();

        // Lock the buffer for writing, discarding previous contents for performance
        pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);

        // Get information about the locked region (PixelBox)
        const Ogre::PixelBox &pixelBox = pixelBuffer->getCurrentLock();

        // Ensure the image format matches the texture format
        OgreAssert(pixelBox.format == worldMapImage.getFormat(),
               "bad format");

        // Copy the image data to the pixel box's data pointer
        memcpy(pixelBox.data, worldMapImage.getData(),
               worldMapImage.getSize());

        // Unlock the buffer to apply changes to the GPU
        pixelBuffer->unlock();
    }
    void updateHeightmap()
    {
        Ogre::Vector3 worldPos =
            ECS::get<Camera>().mCameraPivot->_getDerivedPosition();
        TerrainModule::update_heightmap(worldMapImage);
        long x, y;
        ECS::get<Terrain>()
            .mTerrainGroup->convertWorldPositionToTerrainSlot(
                worldPos, &x, &y);
        for (auto &slot :
             ECS::get<Terrain>().mTerrainGroup->getTerrainSlots()) {
            Ogre::uint32 page =
                ECS::get<Terrain>().mTerrainGroup->packIndex(
                    slot.second->x, slot.second->y);
            Ogre::Terrain *terrain =
                ECS::get<Terrain>().mTerrainGroup->getTerrain(
                    x, y);
            if (terrain)
                terrain->waitForDerivedProcesses();
            ECS::get<Terrain>()
                .mTerrainPagedWorldSection->unloadPage(page,
                                       false);
        }
        ECS::get<Terrain>().mTerrainGroup->update(false);
    }
    void setCursorPos(Ogre::Vector3 &cursorPosition,
              Ogre::Quaternion &orientation)
    {
        Ogre::Vector3 worldPos =
            ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
        worldPos.x = TerrainModule::get_world_x(selected_x);
        worldPos.z = TerrainModule::get_world_y(selected_y);
        worldPos.y = TerrainModule::get_height(
            ECS::get<Terrain>().mTerrainGroup, worldPos);
        ECS::get<EditorGizmo>().sceneNode->_setDerivedPosition(
            worldPos);
        cursorPosition = worldPos;
        orientation = ECS::get<EditorGizmo>()
                      .sceneNode->_getDerivedOrientation();
    }
    bool keepCameraAbove = true;
    void setCameraPos()
    {
        Ogre::Vector3 cursorPos;
        Ogre::Quaternion cursorOrientation;
        setCursorPos(cursorPos, cursorOrientation);
        Ogre::Vector3 cameraPos =
            ECS::get<Camera>().mCameraPivot->_getDerivedPosition();
        Ogre::Vector3 cameraOffset =
            cursorOrientation * Ogre::Vector3::UNIT_Z * 30.0f;
        cameraPos.x = cursorPos.x;
        cameraPos.z = cursorPos.z;
        cameraPos += cameraOffset;
        cameraPos.y =
            TerrainModule::get_height(
                ECS::get<Terrain>().mTerrainGroup, cameraPos) +
            10.0f;
        if (keepCameraAbove) {
            if (cameraPos.y < 0.0f)
                cameraPos.y = 10.0f;
        } else {
            Ogre::TerrainGroup *tg =
                ECS::get<Terrain>().mTerrainGroup;
            long x, y;
            tg->convertWorldPositionToTerrainSlot(cameraPos, &x,
                                  &y);
            if (tg->getTerrain(x, y) &&
                tg->getTerrain(x, y)->isLoaded()) {
                float height =
                    tg->getHeightAtWorldPosition(cameraPos);
                cameraPos.y = height + 10.0f;
            }
        }
        ECS::get<Camera>().mCameraPivot->_setDerivedPosition(cameraPos);
        ECS::get<Camera>().mCameraPivot->_setDerivedOrientation(
            cursorOrientation);
        cameraPos =
            ECS::get<Camera>().mCameraGoal->_getDerivedPosition();
        ECS::get<Camera>().mCameraNode->_setDerivedPosition(cameraPos);
        ECS::get<Camera>().mCameraNode->_setDerivedOrientation(
            ECS::get<Camera>()
                .mCameraGoal->_getDerivedOrientation());
        updateHeightmap();
    }
    void setCursorSelectedPos(flecs::entity e, Ogre::Vector3 &position,
                  Ogre::Quaternion &orientation)
    {
        StaticGeometryModule::getItemPositionAndRotation(e, position,
                                 orientation);
        selected_x = TerrainModule::get_img_x(position.x);
        selected_y = TerrainModule::get_img_y(position.z);
        ECS::get<EditorGizmo>().sceneNode->_setDerivedPosition(
            position);
        ECS::get<EditorGizmo>().sceneNode->_setDerivedOrientation(
            orientation);
    }
    void setCameraSelectedPos(flecs::entity e)
    {
        Ogre::Vector3 cursorPos;
        Ogre::Quaternion cursorOrientation;
        setCursorSelectedPos(e, cursorPos, cursorOrientation);
        Ogre::Vector3 cameraPos =
            ECS::get<Camera>().mCameraPivot->_getDerivedPosition();
        Ogre::Vector3 cameraOffset =
            cursorOrientation * Ogre::Vector3::UNIT_Z * 30.0f;
        cameraPos.x = cursorPos.x;
        cameraPos.z = cursorPos.z;
        cameraPos += cameraOffset;
        cameraPos.y =
            TerrainModule::get_height(
                ECS::get<Terrain>().mTerrainGroup, cameraPos) +
            10.0f;
        if (keepCameraAbove) {
            if (cameraPos.y < 0.0f)
                cameraPos.y = 10.0f;
        } else {
            Ogre::TerrainGroup *tg =
                ECS::get<Terrain>().mTerrainGroup;
            long x, y;
            tg->convertWorldPositionToTerrainSlot(cameraPos, &x,
                                  &y);
            if (tg->getTerrain(x, y) &&
                tg->getTerrain(x, y)->isLoaded()) {
                float height =
                    tg->getHeightAtWorldPosition(cameraPos);
                cameraPos.y = height + 10.0f;
            }
        }
        ECS::get<Camera>().mCameraPivot->_setDerivedPosition(cameraPos);
        ECS::get<Camera>().mCameraPivot->_setDerivedOrientation(
            cursorOrientation);
        cameraPos =
            ECS::get<Camera>().mCameraGoal->_getDerivedPosition();
        ECS::get<Camera>().mCameraNode->_setDerivedPosition(cameraPos);
        ECS::get<Camera>().mCameraNode->_setDerivedOrientation(
            ECS::get<Camera>()
                .mCameraGoal->_getDerivedOrientation());
        updateHeightmap();
    }
    void setSurfaceLevel(int actualSize, int center_x, int center_y,
                 float level)
    {
        int i, j;
        float original = level;
        if (actualSize == 1)
            level += 0.4f;
        else if (actualSize == 2)
            level += 0.35f;
        original = Ogre::Math::Clamp(original, 0.0f, 1.0f);
        for (i = -actualSize; i < actualSize + 1; i++)
            for (j = -actualSize; j < actualSize + 1; j++) {
                if (i * i + j * j > actualSize * actualSize)
                    continue;
                if (center_x + j < 0 ||
                    center_x + j >= worldMap->getWidth())
                    continue;
                if (center_y + i < 0 ||
                    center_y + i >= worldMap->getHeight())
                    continue;
                Ogre::ColourValue cv =
                    worldMapImage.getColourAt(
                        center_x + j, center_y + i, 0);
                cv.r = original;
                worldMapImage.setColourAt(cv, center_x + j,
                              center_y + i, 0);
            }
        updateWorldTexture();
        updateHeightmap();
    }
    void setHarbourSurface()
    {
        int base_size = 3;
        float base_height = 0.517f;
        float base_step = 0.1f;
        float deep = 0.25f;
        float shallow = 0.35f;
        float maxStep = 600.0f;
        Ogre::Vector3 basePos =
            ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
        Ogre::Quaternion baseRot =
            ECS::get<EditorGizmo>()
                .sceneNode->_getDerivedOrientation();
        float baseOffset = 200.0f;
        Ogre::Vector3 stepOffset =
            baseRot * Ogre::Vector3::NEGATIVE_UNIT_Z * baseOffset;
        std::vector<float> heights = { deep, shallow, base_height,
                           base_height + base_step,
                           base_height + base_step * 2.0f };
        int step_count = 0;
        for (float height : heights) {
            float localStep = 0.0f;
            Ogre::Vector3 currentPosition =
                basePos + stepOffset * (float)step_count -
                stepOffset * 0.5f;
            float goTill = maxStep;
            if (step_count < 2)
                goTill += 420.0f;
            while (localStep <
                   goTill - 150.0f * (float)step_count) {
                localStep += baseOffset;
                currentPosition += stepOffset;
                int center_x = TerrainModule::get_img_x(
                    currentPosition.x);
                int center_y = TerrainModule::get_img_y(
                    currentPosition.z);
                int size = base_size + 10 - step_count * 2;
                if (step_count < 2)
                    size = base_size + 14 - step_count * 2;
                if (step_count == 0)
                    size += 1;

                setSurfaceLevel(size, center_x, center_y,
                        height);
            }
            step_count++;
        }
    }
    static void to_json(nlohmann::json &j, const Ogre::Vector3 &position)
    {
        j["x"] = position.x;
        j["y"] = position.y;
        j["z"] = position.z;
    }
    float setLevelValue = 0.0f;
    float riseLowerChange = 0.0f;
    enum {
        COMMAND_NONE,
        COMMAND_RISELOWER,
        COMMAND_RISELOWER2,
        COMMAND_SMOOTH,
        COMMAND_SETLEVEL
    };
    int command;
    void heightmapMenu()
    {
        command = COMMAND_NONE;
        if (ImGui::Button("Elevate")) {
            riseLowerChange = strength;
            command = COMMAND_RISELOWER;
        }
        ImGui::SameLine();
        if (ImGui::Button("Elevate2")) {
            riseLowerChange = strength;
            command = COMMAND_RISELOWER2;
        }
        ImGui::SameLine();
        if (ImGui::Button("Lower")) {
            riseLowerChange = -strength;
            command = COMMAND_RISELOWER;
        }
        std::pair<Ogre::String, float> setLevelCommands[] = {
            { "Deepest", 0.0f },   { "Deep", 0.25f },
            { "Shallow1", 0.35f }, { "Shallow2", 0.47f },
            { "Beach", 0.517f },   { "Shore1", 0.536f },
            { "Shore2", 0.556f },  { "Shore3", 0.586f },
            { "Shore4", 0.606f },  { "Shore5", 0.626f },
            { "Shore6", 0.646f },  { "Highest", 1.0f },
        };
        int buttonCounter = 0;
        for (const auto &mb : setLevelCommands) {
            if (ImGui::SmallButton(mb.first.c_str())) {
                setLevelValue = mb.second;
                command = COMMAND_SETLEVEL;
            }
            if ((buttonCounter & 3) != 0)
                ImGui::SameLine();
            buttonCounter++;
        }
        ImGui::Spacing();
        if (ImGui::Button("Smooth")) {
            command = COMMAND_SMOOTH;
        }
        ImGui::Separator();
        if (ImGui::MenuItem("Save heightmap")) {
            updateWorldTexture();
            updateHeightmap();
            TerrainModule::save_heightmap();
        }
    }
    void executeCommands()
    {
        switch (command) {
        case COMMAND_RISELOWER: {
            int actualSize = 1 + size * 2;
            int i, j;
            for (i = -actualSize; i < actualSize + 1; i++)
                for (j = -actualSize; j < actualSize + 1; j++) {
                    if (i * i + j * j >
                        actualSize * actualSize)
                        continue;
                    if (selected_x + j < 0 ||
                        selected_x + j >=
                            worldMap->getWidth())
                        continue;
                    if (selected_y + i < 0 ||
                        selected_y + i >=
                            worldMap->getHeight())
                        continue;
                    Ogre::ColourValue cv =
                        worldMapImage.getColourAt(
                            selected_x + j,
                            selected_y + i, 0);
                    float original = cv.r;
                    original += riseLowerChange;
                    original = Ogre::Math::Clamp(
                        original, 0.0f, 1.0f);
                    cv.r = original;
                    worldMapImage.setColourAt(
                        cv, selected_x + j,
                        selected_y + i, 0);
                }
            updateWorldTexture();
            updateHeightmap();

        } break;
        case COMMAND_RISELOWER2: {
            int actualSize = 1 + size * 2;
            int i, j;
            Ogre::ColourValue maxcv = worldMapImage.getColourAt(
                selected_x, selected_y, 0);
            for (i = -actualSize; i < actualSize + 1; i++)
                for (j = -actualSize; j < actualSize + 1; j++) {
                    if (i * i + j * j >
                        actualSize * actualSize)
                        continue;
                    if (selected_x + j < 0 ||
                        selected_x + j >=
                            worldMap->getWidth())
                        continue;
                    if (selected_y + i < 0 ||
                        selected_y + i >=
                            worldMap->getHeight())
                        continue;
                    float actualStrength =
                        riseLowerChange /
                        (1.0f + (float)(i * i + j * j));
                    Ogre::ColourValue cv =
                        worldMapImage.getColourAt(
                            selected_x + j,
                            selected_y + i, 0);
                    float original =
                        maxcv.r + actualStrength;
                    original = Ogre::Math::Clamp(
                        original, 0.0f, 1.0f);
                    if (cv.r >= original)
                        continue;
                    cv.r = original;
                    worldMapImage.setColourAt(
                        cv, selected_x + j,
                        selected_y + i, 0);
                }
            updateWorldTexture();
            updateHeightmap();
        } break;
        case COMMAND_SMOOTH: {
            int actualSize = 1 + size * 2;
            int i, j, k, l;
            for (i = -actualSize; i < actualSize + 1; i++)
                for (j = -actualSize; j < actualSize + 1; j++) {
                    if (i * i + j * j >
                        actualSize * actualSize)
                        continue;
                    if (selected_x + j < 0 ||
                        selected_x + j >=
                            worldMap->getWidth())
                        continue;
                    if (selected_y + i < 0 ||
                        selected_y + i >=
                            worldMap->getHeight())
                        continue;
                    int kernel = 3;
                    float original = 0.0f;
                    Ogre::ColourValue cv;
                    float count = 0.0f;
                    for (k = -kernel; k < kernel + 1; k++) {
                        if (selected_y + i + k < 0 ||
                            selected_y + i + k >=
                                worldMap->getHeight())
                            continue;
                        for (l = -kernel;
                             l < kernel + 1; l++) {
                            if (selected_x + j + l <
                                    0 ||
                                selected_x + j +
                                        l >=
                                    worldMap->getWidth())
                                continue;
                            cv = worldMapImage.getColourAt(
                                selected_x + j,
                                selected_y + i,
                                0);
                            original += cv.r;
                            count += 1.0f;
                        }
                    }
                    original /= count;
                    cv = worldMapImage.getColourAt(
                        selected_x + j, selected_y + i,
                        0);
                    original = Ogre::Math::Clamp(
                        original, 0.0f, 1.0f);
                    cv.r = original;
                    worldMapImage.setColourAt(
                        cv, selected_x + j,
                        selected_y + i, 0);
                }
            updateWorldTexture();
            updateHeightmap();
        } break;
        case COMMAND_SETLEVEL: {
            int actualSize = 1 + size * 2;
            int i, j;
            float original = setLevelValue;
            original = Ogre::Math::Clamp(original, 0.0f, 1.0f);
            for (i = -actualSize; i < actualSize + 1; i++)
                for (j = -actualSize; j < actualSize + 1; j++) {
                    if (i * i + j * j >
                        actualSize * actualSize)
                        continue;
                    if (selected_x + j < 0 ||
                        selected_x + j >=
                            worldMap->getWidth())
                        continue;
                    if (selected_y + i < 0 ||
                        selected_y + i >=
                            worldMap->getHeight())
                        continue;
                    Ogre::ColourValue cv =
                        worldMapImage.getColourAt(
                            selected_x + j,
                            selected_y + i, 0);
                    cv.r = original;
                    worldMapImage.setColourAt(
                        cv, selected_x + j,
                        selected_y + i, 0);
                }
            updateWorldTexture();
            updateHeightmap();

        } break;
        }
    }
    void displayItems()
    {
        std::pair<flecs::entity, Ogre::String> selected_item;
        std::list<std::pair<flecs::entity, Ogre::String> > items;
        StaticGeometryModule::getItemsProperties(&items);
        bool item_is_selected = false;
        for (const auto &item : items) {
            nlohmann::json j = nlohmann::json::parse(item.second);
            Ogre::String label = Ogre::StringConverter::toString(
                item.first.id());
            label += ":" + j["type"].get<Ogre::String>();
            if (j.find("name") != j.end())
                label += " " + j["name"].get<Ogre::String>();

            if (ImGui::SmallButton(label.c_str())) { /* select */
                selected_item = item;
                item_is_selected = true;
            }
            Items::showItemButtons(item);
        }
        if (item_is_selected)
            setCameraSelectedPos(selected_item.first);
        for (const auto &item : items)
            Items::showItemPopup(item);
    }
    void displayInfo()
    {
        ImGui::Text("Position: %d %d", pos_x, pos_y);
        ImGui::Text("Selected Position: %d %d", selected_x, selected_y);
        ImGui::Text("Height: %f",
                worldMapImage.getColourAt(pos_x, pos_y, 0).r);
        ImGui::Text(
            "Selected height: %f",
            worldMapImage.getColourAt(selected_x, selected_y, 0).r);
        {
            Ogre::Vector3 position =
                ECS::get<EditorGizmo>()
                    .sceneNode->_getDerivedPosition();
            ImGui::Text("Cursor position %f %f %f", position.x,
                    position.y, position.z);
        }
    }
    std::vector<std::string> split(const std::string &str)
    {
        std::vector<std::string> lines;
        std::istringstream iss(
            str); // Create a stringstream from the input string.
        std::string line;

        while (std::getline(
            iss, line)) { // Read lines until the end of the stream.
            // Optional: you can add logic here to handle different newline conventions
            // (e.g., Windows uses \r\n, which getline handles by discarding \n,
            // but the \r might remain if not explicitly handled/removed).
            lines.push_back(line);
        }

        return lines;
    }
    void cleanupTownTemplateData(nlohmann::json &jtown)
    {
        if (jtown.find("districts") != jtown.end()) {
            nlohmann::json &districts = jtown["districts"];
            for (auto &jdistrict : districts) {
                if (jdistrict.find("lots") != jdistrict.end()) {
                    nlohmann::json &lots =
                        jdistrict["lots"];
                    for (auto &lot : lots) {
                        if (lot.find("cells") !=
                            lot.end())
                            lot.erase("cells");
                        if (lot.find(
                                "furniture_cells") !=
                            lot.end())
                            lot.erase(
                                "furniture_cells");
                        if (lot.find("roofs") !=
                            lot.end())
                            lot.erase("roofs");
                    }
                }
            }
        }
    }
    Ogre::String createTownScript(const Ogre::String &townData)
    {
        Ogre::String ret = "-- generated template\n";
        return ret;
    }
    void editTownTemplateScript(const Ogre::String &templateLabel)
    {
    }
    void worldMapView()
    {
        bool update_cursor_position = false;
        bool update_cursor_height = false;
        bool update_cursor_angle = false;
        OgreAssert(TerrainModule::get_img_x(0) ==
                   worldMap->getWidth() / 2,
               "get_img_x");
        OgreAssert(TerrainModule::get_img_y(0) ==
                   worldMap->getHeight() / 2,
               "get_img_x");
        OgreAssert(TerrainModule::get_world_x(worldMap->getWidth() /
                              2) == 0.0f,
               "get_world_x");
        OgreAssert(TerrainModule::get_world_y(worldMap->getHeight() /
                              2) == 0.0f,
               "get_world_y");
        if (ECS::get<EditorGizmo>().sceneNode) {
            Ogre::Vector3 worldPos =
                ECS::get<EditorGizmo>()
                    .sceneNode->_getDerivedPosition();
            selected_x = TerrainModule::get_img_x(worldPos.x);
            selected_y = TerrainModule::get_img_y(worldPos.z);
            locationSelected = true;
            OgreAssert(selected_x >= 0 &&
                       selected_x < worldMap->getWidth(),
                   "mix width");
            OgreAssert(selected_y >= 0 &&
                       selected_y < worldMap->getHeight(),
                   "mix height");
            ECS::get<Terrain>()
                .mTerrainGroup
                ->convertWorldPositionToTerrainSlot(
                    worldPos, &slot_x, &slot_y);
        }
        ImGui::SetNextWindowSizeConstraints(ImVec2(512 + 20, 512 + 20),
                            ImVec2(768, 768));
        //		ImGui::SetNextWindowScroll(
        //			ImVec2(worldMap->getWidth(), worldMap->getHeight()));
        ImGui::Begin("WorldMap...", nullptr, ImGuiWindowFlags_MenuBar);
        if (ImGui::BeginMenuBar()) {
            if (ImGui::BeginMenu("Create")) {
                Items::createItemsMenu();
                ImGui::EndMenu();
            }
            if (ImGui::BeginMenu("Heightmap")) {
                if (ImGui::MenuItem("Update terrain"))
                    ECS::get<Terrain>()
                        .mTerrainGroup->update(false);
                ImGui::Separator();
                ImGui::SliderFloat("Strength...", &strength,
                           0.0f, 1.0f);
                ImGui::SliderInt("Size", &size, 0, 32);
                ImGui::Separator();
                heightmapMenu();
                ImGui::EndMenu();
            }
            if (ImGui::BeginMenu("Cursor")) {
                if (ImGui::MenuItem("Update cursor position"))
                    update_cursor_height = true;
                Ogre::Vector3 cursorPosition =
                    ECS::get<EditorGizmo>()
                        .sceneNode
                        ->_getDerivedPosition();
                bool modified = false;
                if (ImGui::SmallButton("X-1")) {
                    cursorPosition.x -= 1.0f;
                    modified = true;
                }
                ImGui::SameLine();
                if (ImGui::SmallButton("X+1")) {
                    cursorPosition.x += 1.0f;
                    modified = true;
                }
                ImGui::SameLine();
                if (ImGui::SmallButton("Y-1")) {
                    cursorPosition.y -= 1.0f;
                    modified = true;
                }
                ImGui::SameLine();
                if (ImGui::SmallButton("Y+1")) {
                    cursorPosition.y += 1.0f;
                    modified = true;
                }
                ImGui::SameLine();
                if (ImGui::SmallButton("Z-1")) {
                    cursorPosition.z -= 1.0f;
                    modified = true;
                }
                ImGui::SameLine();
                if (ImGui::SmallButton("Z+1")) {
                    cursorPosition.z += 1.0f;
                    modified = true;
                }
                ImGui::EndMenu();
                if (modified) {
                    ECS::get<EditorGizmo>()
                        .sceneNode->_setDerivedPosition(
                            cursorPosition);
                    modified = false;
                }
            }
            if (ImGui::BeginMenu("Furniture")) {
                if (ImGui::BeginMenu("Create New Furniture")) {
                    static char nameBuffer[32];
                    static int current_mesh = 0;
                    static std::vector<Ogre::String>
                        glb_names;
                    const std::vector<Ogre::String> &groups =
                        Ogre::ResourceGroupManager::
                            getSingleton()
                                .getResourceGroups();
                    if (glb_names.size() == 0) {
                        int i;
                        glb_names.push_back("");
                        for (i = 0; i < groups.size();
                             i++) {
                            std::vector<Ogre::String> names =
                                *Ogre::ResourceGroupManager::getSingleton()
                                     .findResourceNames(
                                         groups[i],
                                         "furniture-*.glb");
                            glb_names.insert(
                                glb_names.end(),
                                names.begin(),
                                names.end());
                        }
                    }
                    ImGui::InputText(
                        "Furniture Name", nameBuffer,
                        IM_ARRAYSIZE(nameBuffer));
                    if (glb_names.size() > 0) {
                        if (ImGui::BeginCombo(
                                "Furniture Mesh",
                                glb_names[current_mesh]
                                    .c_str())) {
                            int i;
                            for (i = 0;
                                 i <
                                 glb_names.size();
                                 i++) {
                                bool isSelected =
                                    i ==
                                    current_mesh;
                                if (ImGui::Selectable(
                                        (glb_names[i] +
                                         "##select" +
                                         Ogre::StringConverter::
                                             toString(
                                                 i))
                                            .c_str(),
                                        isSelected)) {
                                    current_mesh =
                                        i;
                                }
                                if (isSelected)
                                    ImGui::SetItemDefaultFocus();
                            }
                            ImGui::EndCombo();
                        }
                    } else
                        ImGui::Text(
                            "No furniture meshes found");
                    if (ImGui::MenuItem(
                            "Create Furniture")) {
                    }
                    ImGui::EndMenu();
                }
                if (ImGui::BeginMenu("Edit Furniture")) {
                    if (ImGui::MenuItem("Edit Furniture")) {
                    }
                    ImGui::EndMenu();
                }
                ImGui::EndMenu();
            }
            ImGui::EndMenuBar();
        }
        ImGui::Spacing();
        ImGui::BeginChild("WorldMap...", ImVec2(480, 480),
                  ImGuiChildFlags_None,
                  ImGuiWindowFlags_HorizontalScrollbar);
        ImGui::Spacing();
        Ogre::ResourceHandle hdl = worldMap->getHandle();
        int w = worldMap->getWidth();
        int h = worldMap->getHeight();
        ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
                    ImVec2((float)5, (float)5));
        ImGui::ImageButton("WorldMapPress", (ImTextureID)hdl,
                   ImVec2(w, h));
        ImVec2 mouse_absolute_pos = ImGui::GetMousePos();
        ImVec2 item_absolute_pos = ImGui::GetItemRectMin();
        top_x = item_absolute_pos.x + 5;
        top_y = item_absolute_pos.y + 5;
        bool hovered = false;
        if (ImGui::IsItemHovered()) {
            ImVec2 mouse_absolute_pos = ImGui::GetMousePos();
            ImVec2 item_absolute_pos = ImGui::GetItemRectMin();
            pos_x = mouse_absolute_pos.x - item_absolute_pos.x - 5;
            pos_y = mouse_absolute_pos.y - item_absolute_pos.y - 5;
            hovered = true;
        }
        pos_x = Ogre::Math::Clamp(pos_x, 0,
                      (int)worldMap->getWidth() - 1);
        pos_y = Ogre::Math::Clamp(pos_y, 0,
                      (int)worldMap->getHeight() - 1);
        if (pos_x < 0)
            pos_x = 0;
        if (pos_x >= worldMap->getWidth())
            pos_x = worldMap->getWidth() - 1;
        if (pos_y < 0)
            pos_y = 0;
        if (pos_y >= worldMap->getHeight())
            pos_y = worldMap->getHeight() - 1;
        if (ImGui::IsItemActivated()) {
            locationSelected = true;
            selected_x = pos_x;
            selected_y = pos_y;
            OgreAssert(selected_x >= 0 &&
                       selected_x < worldMap->getWidth(),
                   "mix width");
            OgreAssert(selected_y >= 0 &&
                       selected_y < worldMap->getHeight(),
                   "mix height");
            setCameraPos();
            std::cout << "worldClickPos: " << pos_x << " " << pos_y
                  << std::endl;
        }
        ImDrawList *draw_list = ImGui::GetWindowDrawList();
        draw_list->AddCircleFilled(ImVec2(top_x + pos_x, top_y + pos_y),
                       1.0f, IM_COL32(0, 255, 0, 255));
        {
            std::list<Ogre::Vector3> positions;
            StaticGeometryModule::getItemPositions(&positions);
            for (auto pos : positions) {
                int item_x = TerrainModule::get_img_x(pos.x);
                int item_y = TerrainModule::get_img_y(pos.z);
                draw_list->AddCircleFilled(
                    ImVec2(top_x + item_x, top_y + item_y),
                    3.0f, IM_COL32(255, 255, 0, 255));
            }
        }
        if (locationSelected)
            draw_list->AddCircleFilled(
                ImVec2(top_x + selected_x, top_y + selected_y),
                4.0f, IM_COL32(64, 255, 64, 255));
        {
            Ogre::Vector3 cursorPos =
                ECS::get<EditorGizmo>()
                    .sceneNode->_getDerivedPosition();
            int cursor_x = TerrainModule::get_img_x(cursorPos.x);
            int cursor_y = TerrainModule::get_img_y(cursorPos.z);
            draw_list->AddCircleFilled(
                ImVec2(top_x + cursor_x, top_y + cursor_y),
                4.0f, IM_COL32(255, 64, 64, 128));
        }
        ImGui::PopStyleVar();
        ImGui::Spacing();
        ImGui::EndChild();
        ImGui::SameLine();
        ImGui::BeginChild("WorldMap...", ImVec2(64, 480),
                  ImGuiChildFlags_None,
                  ImGuiWindowFlags_HorizontalScrollbar);
        ImGui::EndChild();
        ImGui::Spacing();
        ImGui::BeginChild("WorldMap Bottom...", ImVec2(0, 0));
        if (ImGui::CollapsingHeader("Display Info")) {
            displayInfo();
            if (ImGui::SliderFloat("Cursor Angle...", &cursorAngle,
                           -180.0f, 180.0f))
                update_cursor_angle = true;
        }
        if (ImGui::SmallButton("Display Templates"))
            ImGui::OpenPopup("display_templates_popup");
        if (ImGui::BeginPopup("display_templates_popup")) {
            ImGui::Text("Town templates");
            ImGui::Separator();
            std::list<std::pair<flecs::entity, Ogre::String> > items;
            StaticGeometryModule::getItemsProperties(&items);
            nlohmann::json &templates =
                StaticGeometryModule::getTemplates();
            bool changed = false;
            for (auto p = templates.begin(); p != templates.end();
                 p++) {
                Ogre::String templateLabel = p.key();
                ImGui::Text("%s", templateLabel.c_str());
                ImGui::SameLine();
                if (ImGui::SmallButton(
                        ("Delete##" + templateLabel)
                            .c_str())) {
                    templates.erase(p.key());
                    changed = true;
                }
            }
            for (const auto &item : items) {
                nlohmann::json j =
                    nlohmann::json::parse(item.second);
                Ogre::String label =
                    Ogre::StringConverter::toString(
                        item.first.id());
                Ogre::String type =
                    j["type"].get<Ogre::String>();
                label += ":" + type;
                if (type == "town") {
                    ImGui::Text("%llu",
                            (unsigned long long)
                                item.first.id());
                    ImGui::SameLine();
                    if (ImGui::SmallButton(
                            ("Create Template##" + label)
                                .c_str())) { /* select */
                        cleanupTownTemplateData(j);
                        nlohmann::json t;
                        Ogre::String townScript =
                            createTownScript(
                                item.second);
                        t["townScript"] = townScript;
                        if (j.find("colorRects") !=
                            j.end())
                            t["colorRects"] =
                                j["colorRects"];
                        if (j.find("districts") !=
                            j.end())
                            t["districts"] =
                                j["districts"];
                        if (j.find("districtTemplates") !=
                            j.end())
                            t["districtTemplates"] =
                                j["districtTemplates"];
                        if (j.find("lotTemplates") !=
                            j.end())
                            t["lotTemplates"] =
                                j["lotTemplates"];
                        templates["Default_" +
                              Ogre::StringConverter::toString(
                                  item.first
                                      .id())] =
                            t;
                        changed = true;
                    }
                }
            }
            ImGui::EndPopup();
            if (changed)
                StaticGeometryModule::saveTemplates();
        }
        Items::itemsEditor();
        if (ImGui::SmallButton("Run script for all towns..."))
            Items::runScriptsForAllTowns();
        displayItems();
        ImGui::EndChild();
        ImGui::Spacing();
        ImGui::End();
        if (update_cursor_height || update_cursor_angle) {
            if (update_cursor_height) {
                Ogre::Vector3 position =
                    ECS::get<EditorGizmo>()
                        .sceneNode
                        ->_getDerivedPosition();
                position.y = ECS::get<Terrain>()
                             .mTerrainGroup
                             ->getHeightAtWorldPosition(
                                 position);
                ECS::get<EditorGizmo>()
                    .sceneNode->_setDerivedPosition(
                        position);
            }
            if (update_cursor_angle)
                ECS::get<EditorGizmo>()
                    .sceneNode->_setDerivedOrientation(
                        Ogre::Quaternion(
                            Ogre::Degree(
                                cursorAngle),
                            Ogre::Vector3::UNIT_Y));
        }
        executeCommands();
    }
    void panel()
    {
        ImVec2 size = ImGui::GetMainViewport()->Size;
        float window_width = size.x * 0.5f;
        if (window_width > 550)
            window_width = 550;
        float window_height = size.y - 20;
        ImGui::SetNextWindowPos(ImVec2(size.x - window_width, 20),
                    ImGuiCond_Always);
        ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
                     ImGuiCond_Always);
        // ImGui::Begin("Dumb and Stupid", &mKbd.gui_active);
        ImGui::Begin("Panel...");
        std::deque<Ogre::SceneNode *> tree_input_queue,
            tree_output_queue;
        std::vector<Ogre::SceneNode *> tree_list;
        tree_input_queue.push_back(
            ECS::get()
                .get<EngineData>()
                .mScnMgr->getRootSceneNode());
        tree_input_queue.push_back(nullptr);
        std::set<Ogre::SceneNode *> visited;
        while (true) {
            int new_nodes_count = 0;
            while (!tree_input_queue.empty()) {
                int child;
                Ogre::SceneNode *item =
                    tree_input_queue.front();
                tree_input_queue.pop_front();
                if (item && visited.find(item) ==
                            visited.end()) { // new node
                    new_nodes_count++;
                    tree_output_queue.push_back(item);
                    visited.insert(item);
                    const Ogre::Node::ChildNodeMap
                        &children = item->getChildren();
                    for (child = 0; child < children.size();
                         child++) {
                        tree_output_queue.push_back(
                            static_cast<Ogre::SceneNode
                                        *>(
                                children[child]));
                        tree_output_queue.push_back(
                            nullptr);
                    }
                } else
                    tree_output_queue.push_back(item);
            }
            if (new_nodes_count == 0)
                break;
            tree_input_queue = tree_output_queue;
            tree_output_queue.clear();
        }
        tree_list.insert(tree_list.begin(), tree_output_queue.begin(),
                 tree_output_queue.end());
        int count = 0;
        int depth = 0;
        std::vector<int> check_depth;
        int max_depth = 0;
        check_depth.push_back(0);
        for (count = 0; count < tree_list.size(); count++) {
            int t;

            Ogre::SceneNode *node = tree_list[count];
            if (node && max_depth >= depth) {
                Ogre::String name = node->getName();
                if (name.length() == 0) {
                    name = "Node #" +
                           Ogre::StringConverter::toString(
                               count);
                }
                if (ImGui::TreeNode(name.c_str())) {
                    check_depth.push_back(max_depth);
                    max_depth++;
                    ImGui::Text(
                        "%s",
                        (name + "##caption").c_str());
                    position_editor(node);
                    ImGui::Separator();
                    orientation_editor(node);
                    ImGui::Separator();
                    if (ImGui::Button("From Cursor"))
                        std::cout << name
                              << " From Cursor"
                              << std::endl;
                    if (ImGui::Button("To Cursor"))
                        std::cout << name
                              << " To Cursor"
                              << std::endl;
                    ImGui::Separator();
                    ImGui::Text("Attachments");
                    attachments_editor(node);
                }
            } else if (!node && max_depth >= depth) {
                max_depth = check_depth.back();
                check_depth.pop_back();
                ImGui::TreePop();
            }
            if (tree_list[count])
                depth++;
            else
                depth--;
        }
        ImGui::Spacing();
        Items::itemsEditorProperties();
        ImGui::End();
    }
    void preview(const Ogre::RenderTargetViewportEvent &evt)
    {
        int i;
        Ogre::ImGuiOverlay::NewFrame();
        if (ECS::get().get<GUI>().enabled) {
            buttons_panel();
            panel();
            if (enableMapEditor)
                worldMapView();
        }
    }
};
EditorGUIModule::EditorGUIModule(flecs::world &ecs)
{
    ecs.module<EditorGUIModule>();
    ecs.import <AppModule>();
    ecs.import <StaticGeometryModule>();
    ecs.component<GUI>()
        .on_add([](GUI &gui) {
            gui.enabled = true;
            gui.grab = false;
            gui.grabChanged = false;
        })
        .add(flecs::Singleton);
    ecs.component<EditorGUIData>()
        .on_add([](EditorGUIData &priv) {
            priv.glb_names.clear();
            priv.mGUIListener = nullptr;
            priv.mGuiOverlay = nullptr;
        })
        .add(flecs::Singleton);
    ecs.observer<const RenderWindow, const App, GUI>("SupportEditorGUI")
        .event(flecs::OnSet)
        .without<EditorGUIData>()
        .each([](const RenderWindow &window, const App &app, GUI &gui) {
            float vpScale = window.dpi / 96;
            if (vpScale < 1.0f)
                vpScale = 1.0f;
            Ogre::OverlayManager::getSingleton().setPixelRatio(
                vpScale);
            std::cout << "Editor GUI configure\n";
            OgreAssert(app.mGuiOverlay, "No ImGUI overlay");
            Ogre::ImGuiOverlay *guiOverlay = app.mGuiOverlay;
            EditorGUIListener *guiListener =
                new EditorGUIListener(guiOverlay);
            guiOverlay->setZOrder(300);
            guiOverlay->show();
            guiListener->panel_width = 550.0f;
            guiListener->enableEditor = false;
            window.window->addListener(guiListener);

            ECS::get().set<EditorGUIData>(
                { app.mGuiOverlay, {}, guiListener });
            std::cout << "Editor GUI configure finished\n";
        });
}
}
