-- lx-bundle:true

local config = require("core.config")

local undo = {}

-- Pushes an undo command entry and advances stack index with pruning
function undo.push_undo(undo_stack, time, type, ...)
	undo_stack[undo_stack.idx] = { type = type, time = time, ... }
	undo_stack[undo_stack.idx - config.max_undos] = nil
	undo_stack.idx = undo_stack.idx + 1
end

-- Pops and applies one merged undo/redo command sequence
function undo.pop_undo(self, undo_stack, redo_stack)
	-- pop command
	local cmd = undo_stack[undo_stack.idx - 1]
	if not cmd then
		return
	end
	undo_stack.idx = undo_stack.idx - 1

	-- Delegate replay so base undo stays generic
	if self:apply_undo_entry(cmd, redo_stack) == false then
		return false
	end

	-- if next undo command is within the merge timeout then treat as a single
	-- command and continue to execute it
	local next = undo_stack[undo_stack.idx - 1]
	if next and math.abs(cmd.time - next.time) < config.undo_merge_timeout then
		return undo.pop_undo(self, undo_stack, redo_stack)
	end
end

-- Performs one undo step from the undo stack
function undo.undo(self)
	undo.pop_undo(self, self.undo_stack, self.redo_stack)
end

-- Performs one redo step from the redo stack
function undo.redo(self)
	undo.pop_undo(self, self.redo_stack, self.undo_stack)
end

return undo
