from method import Method
import buffer.colors
import util
import lex

class VcException(Exception): pass

class VcBlame(Method):
    _is_method      = False
    line_re         = None
    prefix_fmt      = None
    pretest_err_msg = None
    num_fields      = 1
    def _pretest(self):
        return True
    def _filter(self, line):
        m = self.line_re.match(line)
        if not m:
            raise VcException("couldn't parse %r" % line)
        groups = m.groups()
        return {'fields': groups[:-1], 'content': groups[-1], 'tokens': []}
    def _open_pipe(self, w, **vargs):
        raise Exception('unimplemented')
    def _build_groups(self, w, **vargs):
        pipe   = self._open_pipe(w, **vargs)
        groups = []
        gsizes = [0] * self.num_fields
        for line in pipe.stdout:
            d = self._filter(line)
            for i in range(0, self.num_fields):
                gsizes[i] = max(gsizes[i], len(d['fields'][i]))
            groups.append(d)
        status = pipe.wait() >> 8
        if status != 0:
            raise Exception("There was an error (%d)" % status)
        return groups, gsizes
    def _lex_groups(self, groups, w, **vargs):
        if w.mode.grammar:
            lexer = lex.Lexer(w.mode, w.mode.grammar)
            for t in lexer.lex([d['content'] for d in groups]):
                groups[t.y]['tokens'].append(t)
    def _build_lines(self, groups, gsizes, w, **vargs):
        self._lex_groups(groups, w, **vargs)
        lines = []
        for d in groups:
            if d['tokens']:
                suffix = ''
                for t in d['tokens']:
                    code = buffer.colors.get_cbuf_code(*t.color)
                    suffix += code + util.cbuf_escape(t.string)
            else:
                suffix = d['content'] + '\n'
            tpl = tuple(util.flatzip(gsizes, d['fields']))
            lines.append(self.prefix_fmt % tpl + ' ' + suffix)
        return lines
    def _execute(self, w, **vargs):
        if not self._pretest():
            w.set_error(self.pretest_err_msg)
            return
        elif not hasattr(w.buffer, 'path'):
            w.set_error("Buffer has no corresponding file")
            return

        try:
            groups, gsizes = self._build_groups(w, **vargs)
        except Exception, e:
            w.set_error(str(e))

        data = ''.join(self._build_lines(groups, gsizes, w, **vargs))
        w.application.color_data_buffer("*Blame*", data, switch_to=True)