class Context(object):
    """This object stores and updates contextual metadata about the buffer."""
    def __init__(self, mode):
        self.mode      = mode
        self.names     = None
        self.namelines = None

    def region_added(self, p, newlines):
        if self.names:
            self.adjust_name_map(p, len(newlines) - 1)
            self.rebuild_name_map(p.y, p.y + len(newlines))
    def region_removed(self, p1, p2):
        if self.names:
            self.adjust_name_map(p2, p1.y - p2.y)
            self.rebuild_name_map(p1.y, p1.y + 1)

    def adjust_name_map(self, p, delta):
        if delta == 0:
            return
        elif delta > 0:
            self.namelines.extend([(None, None)] * delta)
            for i in reversed(range(p.y + 1, len(self.mode.window.buffer.lines))):
                self.namelines[i] = self.namelines[i - delta]
            for i in range(p.y, p.y + delta):
                self.namelines[i] = (None, None)
        else:
            for i in range(p.y + 1, len(self.mode.window.buffer.lines)):
                self.namelines[i + delta] = self.namelines[i]

    def _init_name_map(self):
        self.names     = {}
        self.namelines = [(None, None)] * len(self.mode.window.buffer.lines)

    def build_name_map(self):
        self._init_name_map()
        self._build_name_map(0, len(self.mode.window.buffer.lines), None, None, [])

    def _del_name(self, y, name):
        if name and name in self.names:
            del self.names[name]
        self.namelines[y] = (None, None)

    def _regen_curr(self, y):
        return self.namelines[y - 1][0]
    def _regen_last(self, y):
        return None
    def _regen_stack(self, y):
        assert y > 0
        stack = []
        curr  = self.namelines[y - 1][0]
        count = 0
        if curr:
            for part in curr.split('.'):
                stack.append([count, part])
                count += self.mode.tabwidth
        return stack
        
    def rebuild_name_map(self, y1, y2):
        for y in range(y1, y2):
            (name, info) = self.namelines[y]
            self._del_name(y, name)

        if y1 == 0:
            self._build_name_map(y1, y2, None, None, [])
        else:
            last  = self._regen_last(y1)
            curr  = self._regen_curr(y1)
            stack = self._regen_stack(y1)
            self._build_name_map(y1, y2, last, curr, stack)

    def _build_name_map(self, y1, y2, last, curr, stack):
        raise Exception, 'unimplemented'

    def get_line_name(self, y):
        if self.namelines is None:
            self.build_name_map()
        if y < len(self.namelines):
            return self.namelines[y][0]
        else:
            return None
    def get_names(self):
        if self.names is None:
            self.build_name_map()
        return self.names
    def get_name_list(self):
        return self._ordered_dict(self.get_names())
    def _ordered_dict(self, d):
        pairs = [[d[key], key] for key in d]
        pairs.sort()
        return [x[1] for x in pairs]