from mercurial import cmdutil, commands, hg, util
from mercurial.i18n import _
from mercurial.node import hex, nullid, nullrev, short

def dump_section(data, start, stop, indent):
    start -= 3
    if start < 0:
        start = 0

    stop += 3
    if stop > len(data):
        stop = len(data)

    print '@@ %d,%d @@' % (start + 1, stop)
    for i in xrange(start, stop):
        line,user,skip = data[i]

        if skip:
            user = ''
        else:
            user += '>'

        print '%*s %s' % (indent + 1, user, line)

def dump_lines(data, indent):
    skip_count = 0
    start = None
    stop = None
    for i,datum in enumerate(data):
        line,luser,skip = datum

        if skip:
            skip_count += 1
        else:
            skip_count = 0

        if skip_count > 6:
            if start is None or stop is None:
                continue

            dump_section(data, start, stop, indent)
            start = None
            stop = None

        if start is None:
            if skip:
                continue
            start = i

        if skip:
            if stop is None:
                stop = i

    if start is not None:
        dump_section(data, start, len(data), indent)
    
def stats(ui, repo, *pats, **opts):
    '''Get user statistics
    '''
    get = util.cachefunc(lambda r: repo.changectx(r).changeset())
    changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)

    usermap = {}
    if opts['map']:
        for item in opts['map']:
            try:
                name,aliases = item.split(':')
                aliases = aliases.split(',')
            except ValueError:
                raise util.Abort(_('invalid map argument: %s') % item)

            for alias in aliases:
                if alias in usermap:
                    raise util.Abort(_('alias "%s" already specified') % alias)
                usermap[alias] = name

    df = None
    if opts['date']:
        df = util.matchdate(opts['date'])

    if not pats:
        pats = [ 'relglob:*' ]

    username = opts['user']
    threshold = opts['threshold']

    files = {}

    rev = repo.changelog.tip()
    ctx = repo.changectx(None)

    for src,abs,rel,exact in cmdutil.walk(repo, pats, opts, node=ctx.node()):
        fctx = ctx.filectx(abs)
        if util.binary(fctx.data()):
            continue

        lines = fctx.annotate(follow=True)

        data = {}
        for lctx, line in lines:
            user = util.shortuser(lctx.user())
            user = usermap.get(user, user)
            if username and user != username:
                continue

            if df and not df(lctx.date()[0]):
                continue

            if user not in data:
                data[user] = 0
            data[user] += 1

        for user, count in data.iteritems():
            if count > threshold:
                if user not in files:
                    files[user] = []
                files[user].append(fctx)

    users = files.keys()
    users.sort()

    if ui.quiet:
        for user in users:
            print user
        return

    indent = 0
    for user in users:
        if len(user) > indent:
            indent = len(user)
    
    for user in users:
        print '> %s' % user
        if ui.quiet:
            continue

        for fctx in files[user]:
            print '--- %s' % fctx.path()
            print '=' * 72
            if not ui.verbose:
                continue

            data = []
            for lctx,line in fctx.annotate(follow=True):
                line = line.rstrip()
                luser = util.shortuser(lctx.user())
                luser = usermap.get(luser, luser)
                skip = df and not df(lctx.date()[0]) or luser != user

                data.append((line,luser,skip))

            dump_lines(data, indent)

cmdtable = {
   '^stats' :
   ( stats,
     [ ('d', 'date', '', _('show revs matching date spec')),
       ('m', 'map', [], _('user-name map')),
       ('r', 'rev', [], _('show the specified revision or range')),
       ('t', 'threshold', 25, _('line threshold')),
       ('u', 'user', '', _('User name to gather stats on'))],
     _('hg stats'))
}
