import rox
from rox import g

DELETE = 1
INSERT = 2

class Buffer(g.TextBuffer):
	"A buffer that deals with undo/redo."

	def __init__(self):
		g.TextBuffer.__init__(self, None)
		self.undo_buffer = []
		self.redo_buffer = []	# Will be None during undo or redo
	
	def start_undo_history(self):
		self.connect('delete-range', self.delete_range)
		self.connect('insert-text', self.insert_text)
	
	def delete_range(self, buffer, start, end):
		self.undo_buffer.append((INSERT,
					 start.get_offset(),
					 buffer.get_slice(start, end, g.TRUE)))
		if self.redo_buffer:
			self.redo_buffer = []
	
	def insert_text(self, buffer, where, text, len):
		text = text[:len]	# PyGtk bug?
		start = where.get_offset()
		self.undo_buffer.append((DELETE, start, start + len, text))
		if self.redo_buffer:
			self.redo_buffer = []

	def do_action(self, op):
		if op[0] == DELETE:
			start = self.get_iter_at_offset(op[1])
			end = self.get_iter_at_offset(op[2])
			self.delete(start, end)
		elif op[0] == INSERT:
			start = self.get_iter_at_offset(op[1])
			self.insert(start, op[2], -1)
		else:
			rox.alert('Unknown entry in undo buffer!\n' + `op`)

	def undo(self):
		if not self.undo_buffer:
			g.gdk.beep()
			return
		op = self.undo_buffer.pop()

		old_undo = self.undo_buffer
		self.undo_buffer = self.redo_buffer # Put undos in redo buffer
		self.redo_buffer = None		    # Don't clear redo buffer

		try:
			self.do_action(op)
		finally:
			self.redo_buffer = self.undo_buffer
			self.undo_buffer = old_undo
	
	def redo(self):
		if not self.redo_buffer:
			g.gdk.beep()
			return
		op = self.redo_buffer.pop()

		old_redo = self.redo_buffer
		self.redo_buffer = None		# Don't clear redo buffer

		try:
			self.do_action(op)
		finally:
			self.redo_buffer = old_redo
