# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - show annotations of a page revision

    @copyright: 2010-2014 Henryk Gerlach <hgerlach@gmx.de>
    @license: GNU GPL, see COPYING for details.
"""


import difflib
from MoinMoin import log
logging = log.getLogger(__name__)

from MoinMoin import wikiutil
from MoinMoin.logfile import editlog
from MoinMoin.Page import Page
from MoinMoin.widget import html

def execute(pagename, request):
    """ 
    Handle "action=annotate". Send page with annotations.

    @param pagename: compute annotations for this page
    @param request: request object, following keywords are taken from request.values
    @keyword rev: compute annotations for this revision
    @keyword ignorews: if 1: ignore whitespace
    """
    if not request.user.may.read(pagename):
        Page(request, pagename).send_page()
        return

    try:
        rev = int(request.values.get('rev', None))
    except StandardError:
        rev = None

    page = Page(request, pagename)
    currentrev = page.current_rev()
    if rev == None or rev > currentrev:
        rev = currentrev

    # spacing flag?
    ignorews = int(request.values.get('ignorews', 0))

    _ = request.getText


    def merge_annotation(oldlines, newlines, **kw):
        """
        Find changes between oldlines and newlines.
    
        @param oldlines: list of old decoration and text lines (decoration, line)
        @param newlines: list of new decoration and text lines (decoration, line)
        @keyword ignorews: if 1: ignore whitespace
        @rtype: list
        @return: changed old lines get replaced by new lines with new decoration
        """


        false = lambda s: None
        if kw.get('ignorews', 0):
            d = difflib.Differ(false)
        else:
            d = difflib.Differ(false, false)
    
        lines = list(d.compare( map(lambda s: s[1], oldlines), map(lambda s: s[1], newlines)))
    
        result = []
        iold = inew = 0
        for l in lines:
            if l[0] == " ":
                result.append( oldlines[iold] )
                iold += 1
                inew += 1
            if l[0] == "-": 
                iold+=1
            if l[0] == "+":
                result.append( newlines[inew] )
                inew += 1
        return result

    def decorate_lines(rev):
        """
        Compute list of (decoration, lines) corresponding to revision.
        
        @param rev: the revision to decorate
        """
        page   = Page(request, pagename, rev=rev)
        log    = page.editlog_entry()
        editor = log.getEditor(request) or _('N/A'),
        date   = request.user.getFormattedDateTime(wikiutil.version2timestamp(log.ed_time_usecs)) or _('N/A')
        return map(lambda l: [(rev, editor, date), l], page.get_raw_body().split("\n"))
    
    #compute all revisions that are relevant for the annotation of the requested rev
    allrevs = []

    logs = list(editlog.EditLog(request, rootpagename=pagename))

    while logs: #fast forward to requested rev
       if int(rev) == int(logs[-1].rev): break
       logs.pop()

    while logs:
       l = logs.pop()
       allrevs.append(int(l.rev))
       if l.action in ['ATTNEW','ATTDEL']:
          allrevs.pop() #these actions are not relevant for the text 
       elif l.action in ['SAVE/REVERT']:
          #remove reverted editions
          while l.extra != logs[-1].rev:
             logs.pop()
    allrevs.reverse()

    #compute annotations
    if not allrevs:
       #The page has no revisions. Maybe a default page.
       currtext = []
    else:
       rev_iter = allrevs.pop(0)
       currtext = decorate_lines(rev_iter)
    for rev_iter in allrevs:
        oldtext = currtext
        currtext = decorate_lines(rev_iter)
        currtext = merge_annotation(oldtext, currtext, ignorews=ignorews)

    # build and send the page
    def render_action(text, query, **kw):
        kw.update(dict(rel='nofollow'))
        return page.link_to(request, text, querystr=query, **kw)

    f = request.formatter
    if rev == currentrev:
        request.theme.send_title(_('Annotate for "%s"') % (pagename, ), pagename=pagename)
    else:
        request.theme.send_title(_('Annotate for "%s" revison %d') % (pagename, rev ), pagename=pagename)

    # Start content (important for RTL support)
    request.write(request.formatter.startContent("content"))

    request.write("<table><tr><th>"+_("Line")+"</th><th>"+_("Editor")+"</th><th>"+_("Date")+"</th><th>"+_("Rev")+"</th></tr>")
    for annotation, l in currtext:
        rev, editor, date = annotation
        request.write("<tr><td>") 
        request.write(f.text(l))
        request.write("</td><td>"+ editor[0] + "</td><td>"+date+"</td>")
        request.write("<td>"+render_action(_(str(rev)), {'action': 'recall', 'rev': '%d' % rev})+"</td></tr>")

    request.write("</table>")
    request.write(request.formatter.endContent())
    request.theme.send_footer(pagename)
    request.theme.send_closing_html()
