import window

class Slot(object):
    window = None
    def __init__(self, height, width, y_offset=0, x_offset=0):
        self.resize(height, width, y_offset, x_offset)
    def is_empty(self):
        return self.window is None
    def resize(self, height, width, y_offset=0, x_offset=0):
        self.height   = height
        self.width    = width
        self.y_offset = y_offset
        self.x_offset = x_offset
        if self.window is not None:
            self.window.set_size(self.width, self.height)
    def reset(self):
        self.window.set_size(self.width, self.height)
    def set(self, w):
        self.window  = w
        w.set_size(self.width, self.height)
    def unset(self):
        if not self.is_empty():
            old_w = self.window
            self.window = None
            return old_w
        else:
            return None

class BufferList(object):
    def __init__(self, height, width, buffers=()):
        self.height         = height
        self.width          = width
        self.buffers        = set()
        self.buffer_names   = {}
        self.hidden_buffers = []
        self.slots          = []
        self.mini_height    = 1

        self.add_slot()
        self.fit_slots()
        for b in buffers:
            self.add_buffer(b)
    def fit_slots(self):
        total = self.height - len(self.slots) + 1 - self.mini_height
        heights = [total / len(self.slots)] * len(self.slots)
        for i in xrange(0, total % len(self.slots)):
            heights[i] += 1
        offsets = [0]
        for i in xrange(1, len(self.slots)):
            offsets.insert(i, offsets[i - 1] + heights[i - 1] + 1)
        for i in xrange(0, len(self.slots)):
            self.slots[i].resize(heights[i], self.width, offsets[i])
    def resize_mini(self, n):
        self.mini_height = n
        self.fit_slots()
    def resize(self, height, width):
        self.height = height
        self.width  = width
        self.fit_slots()
    
    def find_window_slot(self, w):
        for slot in self.slots:
            if w is slot.window:
                return slot
        return None
    def is_window_visible(self, w):
        return self.find_window_slot(w) is not None
    def is_buffer_visible(self, b):
        for slot in self.slots:
            if slot.window is not None and b is slot.window.buffer:
                return True
        return False

    # manipulate slots
    def add_slot(self):
        self.slots.append(Slot(self.height, self.width, 0))
        self.fit_slots()
        return len(self.slots) - 1
    def empty_slot(self, i):
        assert i > -1 and i < len(self.slots), "slot %d does not exist" % i
        return self.slots[i].is_empty()
    def unset_slot(self, i):
        assert i > -1 and i < len(self.slots), "slot %d does not exist" % i
        old_w = self.slots[i].unset()
        if old_w is not None:
            old_b = old_w.buffer
            if not self.is_buffer_visible(old_b):
                self.hidden_buffers.insert(0, old_b)
            if len(old_b.windows) > 1:
                old_b.remove_window(old_w)

    def set_slot(self, i, b):
        assert i > -1 and i < len(self.slots), "slot %d does not exist" % i
        assert b in self.buffers, "buffer %s does not exist" % (b.name())
        slot = self.slots[i]
        self.unset_slot(i)

        if b in self.hidden_buffers:
            self.hidden_buffers.remove(b)
        if self.is_window_visible(b.windows[0]):
            app = b.windows[0].application
            w = window.Window(b, app, height=slot.height, width=slot.width)
        else:
            w = b.windows[0]
        slot.set(w)

    def remove_slot(self, i):
        assert i > -1 and i < len(self.slots), "slot %d does not exist" % i
        self.unset_slot(i)
        del self.slots[i]
        self.fit_slots()

    # add/remove buffers
    def add_buffer(self, b):
        assert b not in self.buffers, "buffer %s already exists" % (b.name())
        self.buffers.add(b)
        self.buffer_names[b.name()] = b
        self.hidden_buffers.append(b)
    def has_buffer(self, b):
        return b in self.buffers
    def has_buffer_name(self, name):
        return name in self.buffer_names
    def get_buffer_by_name(self, name):
        return self.buffer_names[name]
    def get_buffer_by_path(self, path):
        for b in self.buffers:
            if hasattr(b, 'path') and b.path == path:
                return b
        return None
    def close_buffer(self, b):
        for i in xrange(0, len(self.slots)):
            slot = self.slots[i]
            if slot.window is not None and slot.window.buffer is b:
                self.unset_slot(i)
    def remove_buffer(self, b):
        assert b in self.buffers, "buffer %s does not exist" % (b.name())
        for i in xrange(0, len(self.slots)):
            slot = self.slots[i]
            if slot.window is not None and slot.window.buffer is b:
                self.unset_slot(i)
        self.buffers.remove(b)
        del self.buffer_names[b.name()]
        if b in self.hidden_buffers:
            self.hidden_buffers.remove(b)

    # query buffers
    def is_buffer_hidden(self, b):
        assert b in self.buffers, "buffer %s does not exist" % (b.name())
        return b in self.hidden_buffers