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

#pragma once

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

namespace nostalgia::studio {

class UndoCommand {
	public:
		virtual ~UndoCommand() noexcept = default;
		virtual void redo() noexcept = 0;
		virtual void undo() noexcept = 0;
		[[nodiscard]]
		virtual int commandId() const noexcept = 0;
		virtual bool mergeWith(const UndoCommand *cmd) noexcept;
};

class UndoStack {
	private:
		ox::Vector<ox::UniquePtr<UndoCommand>> m_stack;
		std::size_t m_stackIdx = 0;

	public:
		void push(UndoCommand *cmd) noexcept;

		void redo() noexcept;

		void undo() noexcept;

		[[nodiscard]]
		constexpr bool canRedo() const noexcept {
			return m_stackIdx < m_stack.size();
		}

		[[nodiscard]]
		constexpr bool canUndo() const noexcept {
			return m_stackIdx;
		}

		ox::Signal<ox::Error(const studio::UndoCommand*)> redoTriggered;
		ox::Signal<ox::Error(const studio::UndoCommand*)> undoTriggered;
		ox::Signal<ox::Error(const studio::UndoCommand*)> changeTriggered;
};

}
