# Copyright (C) 2006 Aaron Bentley
# <aaron.bentley@utoronto.ca>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import sys
from os.path import expanduser

from bzrlib.commands import get_cmd_object
from bzrlib.patches import (hunk_from_header, InsertLine, RemoveLine,
                            ContextLine, Hunk)

import terminal

class LineParser(object):
    def parse_line(self, line):
        if line.startswith("@"):
            return hunk_from_header(line)
        elif line.startswith("+"):
            return InsertLine(line[1:])
        elif line.startswith("-"):
            return RemoveLine(line[1:])
        elif line.startswith(" "):
            return ContextLine(line[1:])
        else:
            return line


class DiffWriter(object):

    colors = {
        'metaline':    'darkyellow',
        'plain':       'darkwhite',
        'newtext':     'darkblue',
        'oldtext':     'darkred',
        'diffstuff':   'darkgreen'
    }

    def __init__(self, target):
        self.target = target
        self.lp = LineParser()
        self.chunks = []
        self._read_colordiffrc()

    def _read_colordiffrc(self):
        path = expanduser('~/.colordiffrc')
        try:
            f = open(path, 'r')
        except IOError:
            return

        for line in f.readlines():
            try:
                key, val = line.split('=')
            except ValueError:
                continue

            key = key.strip()
            val = val.strip()

            tmp = val
            if val.startswith('dark'):
                tmp = val[4:]

            if tmp not in terminal.colors:
                continue

            self.colors[key] = val

    def colorstring(self, type, string):
        color = self.colors[type]
        if color is not None:
            string = terminal.colorstring(str(string), color)
        self.target.write(string)

    def write(self, text):
        newstuff = text.split('\n')
        for newchunk in newstuff[:-1]:
            self._writeline(''.join(self.chunks + [newchunk, '\n']))
            self.chunks = []
        self.chunks = [newstuff[-1]]

    def _writeline(self, line):
        item = self.lp.parse_line(line)
        if isinstance(item, Hunk):
            line_class = 'diffstuff'
        elif isinstance(item, InsertLine):
            line_class = 'newtext'
        elif isinstance(item, RemoveLine):
            line_class = 'oldtext'
        elif isinstance(item, basestring) and item.startswith('==='):
            line_class = 'metaline'
        else:
            line_class = 'plain'
        self.colorstring(line_class, str(item))

    def flush(self):
        self.target.flush()

def colordiff(self, *args, **kwargs):
    real_stdout = sys.stdout
    sys.stdout = DiffWriter(real_stdout)
    try:
        get_cmd_object('diff').run(*args, **kwargs)
    finally:
        sys.stdout = real_stdout
