/*
 * Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
 */

#pragma once

#include <ox/event/signal.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>

#include <studio/editor.hpp>
#include <studio/module.hpp>
#include <studio/project.hpp>
#include <studio/task.hpp>
#include "aboutpopup.hpp"
#include "newmenu.hpp"
#include "newproject.hpp"
#include "projectexplorer.hpp"
#include "projecttreemodel.hpp"

namespace studio {

class StudioUI: public ox::SignalHandler {
	friend class StudioUIDrawer;

	private:
		studio::StudioContext m_sctx;
		turbine::Context &m_ctx;
		ox::String m_projectDataDir;
		ox::UPtr<studio::Project> m_project;
		studio::TaskRunner m_taskRunner;
		ox::Vector<ox::UPtr<studio::BaseEditor>> m_editors;
		ox::Vector<ox::UPtr<studio::Widget>> m_widgets;
		ox::HashMap<ox::String, studio::EditorMaker::Func> m_editorMakers;
		ProjectExplorer m_projectExplorer;
		ox::Vector<ox::String> m_openFiles;
		studio::BaseEditor *m_activeEditorOnLastDraw = nullptr;
		studio::BaseEditor *m_activeEditor = nullptr;
		studio::BaseEditor *m_activeEditorUpdatePending = nullptr;
		NewMenu m_newMenu;
		NewProject m_newProject;
		AboutPopup m_aboutPopup;
		ox::Array<studio::Popup*, 3> const m_popups = {
			&m_newMenu,
			&m_newProject,
			&m_aboutPopup
		};
		bool m_showProjectExplorer = true;

	public:
		explicit StudioUI(turbine::Context &ctx, ox::StringView projectDataDir) noexcept;

		void update() noexcept;

		void handleKeyEvent(turbine::Key, bool down) noexcept;

		[[nodiscard]]
		constexpr studio::Project *project() noexcept {
			return m_project.get();
		}

	protected:
		void draw() noexcept;

	private:
		void drawMenu() noexcept;

		void drawTabBar() noexcept;

		void drawTabs() noexcept;

		void loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept;

		void loadModule(studio::Module const*mod) noexcept;

		void loadModules() noexcept;

		void toggleProjectExplorer() noexcept;

		void redo() noexcept;

		void undo() noexcept;

		void save() noexcept;

		ox::Error createOpenProject(ox::CRStringView path) noexcept;

		ox::Error openProjectPath(ox::CRStringView path) noexcept;

		ox::Error openFile(ox::CRStringView path) noexcept;

		ox::Error openFileActiveTab(ox::CRStringView path, bool makeActiveTab) noexcept;

		ox::Error closeFile(ox::CRStringView path) noexcept;
};

}
