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

#pragma once

#include <ox/event/signal.hpp>

#include "undostack.hpp"
#include "widget.hpp"

#include "nostalgiastudio_export.h"

namespace nostalgia {
class StudioUI;
}

namespace nostalgia::studio {

class NOSTALGIASTUDIO_EXPORT BaseEditor: public Widget {

	friend StudioUI;

	private:
		bool m_unsavedChanges = false;
		bool m_exportable = false;
		bool m_cutEnabled = false;
		bool m_copyEnabled = false;
		bool m_pasteEnabled = false;

	public:
		~BaseEditor() override = default;

		/**
		 * Returns the name of item being edited.
		 */
		[[nodiscard]]
		virtual const ox::String &itemName() const noexcept = 0;

		[[nodiscard]]
		virtual const ox::String &itemDisplayName() const noexcept;

		virtual void cut();

		virtual void copy();

		virtual void paste();

		virtual void exportFile();

		virtual void keyStateChanged(core::Key key, bool down);

		void close();

		/**
		 * Save changes to item being edited.
		 */
		void save() noexcept;

		/**
		 * Sets indication of item being edited has unsaved changes. Also emits
		 * unsavedChangesChanged signal.
		 */
		void setUnsavedChanges(bool);

		[[nodiscard]]
		bool unsavedChanges() const noexcept;

		void setExportable(bool);

		[[nodiscard]]
		bool exportable() const;

		void setCutEnabled(bool);

		[[nodiscard]]
		bool cutEnabled() const;

		void setCopyEnabled(bool);

		[[nodiscard]]
		bool copyEnabled() const;

		void setPasteEnabled(bool);

		[[nodiscard]]
		bool pasteEnabled() const;

	protected:
		/**
		 * Save changes to item being edited.
		 */
		virtual ox::Error saveItem() noexcept;

		/**
		 * Returns the undo stack holding changes to the item being edited.
		 */
		[[nodiscard]]
		virtual UndoStack *undoStack() noexcept {
			return nullptr;
		}

	// signals
	public:
		ox::Signal<ox::Error(bool)> unsavedChangesChanged;
		ox::Signal<ox::Error(bool)> exportableChanged;
		ox::Signal<ox::Error(bool)> cutEnabledChanged;
		ox::Signal<ox::Error(bool)> copyEnabledChanged;
		ox::Signal<ox::Error(bool)> pasteEnabledChanged;
		ox::Signal<ox::Error(const ox::String&)> closed;

};

class Editor: public studio::BaseEditor {
	private:
		studio::UndoStack m_undoStack;

	public:
		Editor() noexcept;

		UndoStack *undoStack() noexcept final {
			return &m_undoStack;
		}

	private:
		ox::Error markUnsavedChanges(const UndoCommand*) noexcept;
};


}
