/*
 * Copyright 2016 - 2022 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 "lib/editor.hpp"
#include "lib/module.hpp"
#include "lib/project.hpp"
#include "lib/task.hpp"
#include "aboutpopup.hpp"
#include "newmenu.hpp"
#include "projectexplorer.hpp"
#include "projecttreemodel.hpp"

namespace nostalgia {

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

	private:
		ox::UniquePtr<studio::Project> m_project;
		studio::TaskRunner m_taskRunner;
		core::Context *m_ctx = nullptr;
		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_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(core::Context *ctx) noexcept;

		void update() noexcept;

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

		[[nodiscard]]
		constexpr auto project() noexcept {
			return m_project.get();
		}

	protected:
		void draw() noexcept;

	private:
		void drawMenu() noexcept;

		void drawTabBar() noexcept;

		void drawTabs() noexcept;

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

		void loadModule(studio::Module *module) noexcept;

		void loadModules() noexcept;

		void toggleProjectExplorer() noexcept;

		void redo() noexcept;

		void undo() noexcept;

		void save() noexcept;

		ox::Error openProject(const ox::String &path) noexcept;

		ox::Error openFile(const ox::String &path) noexcept;

		ox::Error openFileActiveTab(const ox::String &path, bool makeActiveTab) noexcept;

		ox::Error closeFile(const ox::String &path) noexcept;
};

}
