/*
 * Copyright 2016 - 2023 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 "projectexplorer.hpp"
#include "projecttreemodel.hpp"

namespace studio {

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

	private:
		turbine::Context &m_ctx;
		ox::String m_projectDir;
		ox::UniquePtr<studio::Project> m_project;
		studio::TaskRunner m_taskRunner;
		ox::Vector<ox::UniquePtr<studio::BaseEditor>> m_editors;
		ox::Vector<ox::UniquePtr<studio::Widget>> m_widgets;
		ox::HashMap<ox::String, studio::EditorMaker::Func> m_editorMakers;
		ox::UniquePtr<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;
		AboutPopup m_aboutPopup;
		const ox::Array<studio::Popup*, 2> m_popups = {
			&m_newMenu,
			&m_aboutPopup
		};
		bool m_showProjectExplorer = true;

	public:
		explicit StudioUI(turbine::Context *ctx, ox::StringView projectDir) 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(const studio::Module *mod) noexcept;

		void loadModules() noexcept;

		void toggleProjectExplorer() noexcept;

		void redo() noexcept;

		void undo() noexcept;

		void save() noexcept;

		ox::Error openProject(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;
};

}
