"""
    MoinMoin - MonthCalendarHack Macro
    
    This macro is a hack of the MonthCalendar one delivered with MoinMoin, to enable subpages titles in form
    
    = title =
    
    or 
    
    '''title'''

    You can use this macro to put a month's calendar page on a Wiki page.

    The days are links to Wiki pages following this naming convention:
    BasePageName/year-month-day

    @copyright: 2002-2005 by Thomas Waldmann <ThomasWaldmann@gmx.de>
    @copyright: 2007- by Eric Veiras Galisson 
    @license: GNU GPL - see http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt for details.

    Revisions:
    * first revision without a number (=1.0):
        * work with MoinMoin 1.5

    Usage:
        [[MonthCalendarHack(BasePage,year,month,monthoffset,monthoffset2,height6)]]

        each parameter can be empty and then defaults to currentpage or currentdate or monthoffset=0

    Samples (paste that to one of your pages for a first try):

Calendar of current month for current page:
[[MonthCalendar]]

Calendar of last month:
[[MonthCalendarHack(,,,-1)]]

Calendar of next month:
[[MonthCalendarHack(,,,+1)]]

Calendar of Page SampleUser, this years december:
[[MonthCalendarHack(SampleUser,,12)]]

Calendar of current Page, this years december:
[[MonthCalendarHack(,,12)]]

Calendar of December, 2001:
[[MonthCalendarHack(,2001,12)]]

Calendar of the month two months after December, 2001
(maybe doesn't make much sense, but is possible)
[[MonthCalendarHack(,2001,12,+2)]]

Calendar of year 2002 (every month padded to height of 6):
||||||Year 2002||
||[[MonthCalendarHack(,2002,1,,,1)]]||[[MonthCalendarHack(,2002,2,,,1)]]||[[MonthCalendarHack(,2002,3,,,1)]]||
||[[MonthCalendarHack(,2002,4,,,1)]]||[[MonthCalendarHack(,2002,5,,,1)]]||[[MonthCalendarHack(,2002,6,,,1)]]||
||[[MonthCalendarHack(,2002,7,,,1)]]||[[MonthCalendarHack(,2002,8,,,1)]]||[[MonthCalendarHack(,2002,9,,,1)]]||
||[[MonthCalendarHack(,2002,10,,,1)]]||[[MonthCalendarHack(,2002,11,,,1)]]||[[MonthCalendarHack(,2002,12,,,1)]]||

Current calendar of me, also showing entries of A and B:
[[MonthCalendarHack(MyPage*TestUserA*TestUserB)]]

SubPage calendars:
[[MonthCalendarHack(MyName/CalPrivate)]]
[[MonthCalendarHack(MyName/CalBusiness)]]
[[MonthCalendarHack(MyName/CalBusiness*MyName/CalPrivate)]]


Anniversary Calendars: (no year data)
[[MonthCalendarHack(Yearly,,,+1,,6,1)]]

This creates calendars of the format Yearly/MM-DD 
By leaving out the year, you can set birthdays, and anniversaries in this 
calendar and not have to re-enter each year.

This creates a calendar which uses MonthCalendarTemplate for directly editing
nonexisting day pages:
[[MonthCalendarHack(,,,,,,MonthCalendarTemplate)]]
"""

Dependencies = ['namespace','time']

from MoinMoin import wikiutil
from MoinMoin.Page import Page
import re, calendar, time

# The following line sets the calendar to have either Sunday or Monday as
# the first day of the week. Only SUNDAY or MONDAY (case sensitive) are
# valid here.  All other values will not make good calendars.
# If set to Sunday, the calendar is displayed at "March 2003" vs. "2003 / 3" also.
# XXX change here ----------------vvvvvv
calendar.setfirstweekday(calendar.MONDAY)

def cliprgb(r,g,b): # don't use 255!
    if r < 0:   r=0
    if r > 254: r=254
    if b < 0:   b=0
    if b > 254: b=254
    if g < 0:   g=0
    if g > 254: g=254
    return r, g, b

def yearmonthplusoffset(year, month, offset):
    month = month+offset
    # handle offset and under/overflows - quick and dirty, yes!
    while month < 1:
        month = month + 12
        year = year - 1
    while month > 12:
        month = month - 12
        year = year + 1
    return year, month

def parseargs(args, defpagename, defyear, defmonth, defoffset, defoffset2, defheight6, defanniversary, deftemplate):
    strpagename = args.group('basepage')
    if strpagename:
        parmpagename = wikiutil.unquoteWikiname(strpagename)
    else:
        parmpagename = defpagename
    # multiple pagenames separated by "*" - split into list of pagenames
    parmpagename = re.split(r'\*', parmpagename)

    stryear = args.group('year')
    if stryear:
        parmyear = int(stryear)
    else:
        parmyear = defyear

    strmonth = args.group('month')
    if strmonth:
        parmmonth = int(strmonth)
    else:
        parmmonth = defmonth
    
    stroffset = args.group('offset')
    if stroffset:
        parmoffset = int(stroffset)
    else:
        parmoffset = defoffset

    stroffset2 = args.group('offset2')
    if stroffset2:
        parmoffset2 = int(stroffset2)
    else:
        parmoffset2 = defoffset2

    strheight6 = args.group('height6')
    if strheight6:
        parmheight6 = int(strheight6)
    else:
        parmheight6 = defheight6

    stranniversary = args.group('anniversary')
    if stranniversary:
            parmanniversary = int(stranniversary)
    else:
        parmanniversary = defanniversary

    strtemplate = args.group('template')
    if strtemplate:
        parmtemplate = wikiutil.unquoteWikiname(strtemplate)
    else:
        parmtemplate = deftemplate
    return parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, parmanniversary, parmtemplate
        
# FIXME:                          vvvvvv is there a better way for matching a pagename ?
_arg_basepage = r'\s*(?P<basepage>[^, ]+)?\s*'
_arg_year = r',\s*(?P<year>\d+)?\s*'
_arg_month = r',\s*(?P<month>\d+)?\s*'
_arg_offset = r',\s*(?P<offset>[+-]?\d+)?\s*'
_arg_offset2 = r',\s*(?P<offset2>[+-]?\d+)?\s*'
_arg_height6 = r',\s*(?P<height6>[+-]?\d+)?\s*'
_arg_anniversary =  r',\s*(?P<anniversary>[+-]?\d+)?\s*'
_arg_template = r',\s*(?P<template>[^, ]+)?\s*' # XXX see basepage comment
_args_re_pattern = r'^(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?$' % \
                     (_arg_basepage,_arg_year,_arg_month, \
                      _arg_offset,_arg_offset2,_arg_height6,_arg_anniversary,_arg_template)


def execute(macro, text):
    request = macro.request
    formatter = macro.formatter
    _ = request.getText

    # return immediately if getting links for the current page
    if request.mode_getpagelinks:
        return ''

    args_re = re.compile(_args_re_pattern)
    
    currentyear, currentmonth, currentday, h, m, s, wd, yd, ds = request.user.getTime(time.time())
    thispage = formatter.page.page_name
    # does the url have calendar params (= somebody has clicked on prev/next links in calendar) ?
    if macro.form.has_key('calparms'):
        text2 = macro.form['calparms'][0]
        args2 = args_re.match(text2)
        if not args2:
            return ('<p><strong class="error">%s</strong></p>' % _('Invalid MonthCalendar calparms "%s"!')) % (text2,)
        else:
            has_calparms = 1 # yes!
            cparmpagename, cparmyear, cparmmonth, cparmoffset, cparmoffset2, cparmheight6, cparmanniversary, cparmtemplate = \
                parseargs(args2, thispage, currentyear, currentmonth, 0, 0, 0, 0, '')
    else:
        has_calparms = 0

    if text is None: # macro call without parameters
        parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, anniversary, parmtemplate = \
            [thispage], currentyear, currentmonth, 0, 0, 0, 0, ''
    else:
        # parse and check arguments
        args = args_re.match(text)
        if not args:
            return ('<p><strong class="error">%s</strong></p>' % _('Invalid MonthCalendar arguments "%s"!')) % (text,)
        else:
            parmpagename, parmyear, parmmonth, parmoffset, parmoffset2, parmheight6, anniversary, parmtemplate = \
                parseargs(args, thispage, currentyear, currentmonth, 0, 0, 0, 0, '')

    # does url have calendar params and is THIS the right calendar to modify (we can have multiple
    # calendars on the same page)?
    #if has_calparms and (cparmpagename,cparmyear,cparmmonth,cparmoffset) == (parmpagename,parmyear,parmmonth,parmoffset):
    
    # move all calendars when using the navigation:
    if has_calparms and cparmpagename == parmpagename:
        year,month = yearmonthplusoffset(parmyear, parmmonth, parmoffset + cparmoffset2)
        parmoffset2 = cparmoffset2
        parmtemplate = cparmtemplate
    else:
        year,month = yearmonthplusoffset(parmyear, parmmonth, parmoffset)

    # get the calendar
    monthcal = calendar.monthcalendar(year, month)

    # european / US differences
    months = ('January','February','March','April','May','June','July','August','September','October','November','December')
    # Set things up for Monday or Sunday as the first day of the week
    if calendar.firstweekday() == calendar.MONDAY:
        wkend = (5, 6)
        wkdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
    if calendar.firstweekday() == calendar.SUNDAY:
        wkend = (0, 6)
        wkdays = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')

    colorstep = 85
    p = Page(request, thispage)
    qpagenames = '*'.join(map(wikiutil.quoteWikinameURL, parmpagename))
    qtemplate = wikiutil.quoteWikinameURL(parmtemplate)
    querystr = "calparms=%%s,%d,%d,%d,%%d,%%s" % (parmyear, parmmonth, parmoffset)
    prevlink  = p.url(request, querystr % (qpagenames, parmoffset2 - 1, qtemplate), 0)
    nextlink  = p.url(request, querystr % (qpagenames, parmoffset2 + 1, qtemplate), 0)
    prevylink = p.url(request, querystr % (qpagenames, parmoffset2 - 12, qtemplate), 0)
    nextylink = p.url(request, querystr % (qpagenames, parmoffset2 + 12, qtemplate), 0)
    prevmonth = formatter.url(1, prevlink, 'cal-link') + '&lt;' + formatter.url(0)
    nextmonth = formatter.url(1, nextlink, 'cal-link') + '&gt;' + formatter.url(0)
    prevyear  = formatter.url(1, prevylink, 'cal-link') + '&lt;&lt;' + formatter.url(0)
    nextyear  = formatter.url(1, nextylink, 'cal-link') + '&gt;&gt;' + formatter.url(0)
    
    if parmpagename != [thispage]:
        pagelinks = ''
        r, g, b = (255, 0, 0)
        l = len(parmpagename[0])
        steps = len(parmpagename)
        maxsteps = (255 / colorstep)
        if steps > maxsteps:
            steps = maxsteps
        chstep = int(l / steps)
        st = 0
        while st < l:
            ch = parmpagename[0][st:st+chstep]
            r, g, b = cliprgb(r, g, b)
            pagelinks = pagelinks + '<a style="%s" href="%s">%s</a>' % \
                ('background-color:#%02x%02x%02x;color:#000000;text-decoration:none' % \
                    (r,g,b), Page(request, parmpagename[0]).url(request), ch)
            r, g, b = (r, g+colorstep, b)
            st = st + chstep
        r, g, b = (255-colorstep, 255, 255-colorstep)
        for page in parmpagename[1:]:
            pagelinks = pagelinks + '*<a style="%s" href="%s">%s</a>' % \
                            ('background-color:#%02x%02x%02x;color:#000000;text-decoration:none' % \
                                (r,g,b), Page(request, page).url(request), page)
        showpagename = '   %s<BR>\n' % pagelinks
    else:
        showpagename = ''
    if calendar.firstweekday() == calendar.SUNDAY:
        resth1 = '  <th colspan="7" class="cal-header">\n' \
                 '%s' \
                 '   %s&nbsp;%s&nbsp;<b>&nbsp;%s&nbsp;%s</b>&nbsp;%s\n&nbsp;%s\n' \
                 '  </th>\n' % (showpagename, prevyear, prevmonth, months[month-1], str(year), nextmonth, nextyear)
    if calendar.firstweekday() == calendar.MONDAY:
        resth1 = '  <th colspan="7" class="cal-header">\n' \
                 '%s' \
                 '   %s&nbsp;%s&nbsp;<b>&nbsp;%s&nbsp;/&nbsp;%s</b>&nbsp;%s\n&nbsp;%s\n' \
                 '  </th>\n' % (showpagename, prevyear, prevmonth, str(year), month, nextmonth, nextyear)
    restr1 = ' <tr>\n%s </tr>\n' % resth1

    r7 = range(7)
    restd2 = []
    for wkday in r7:
        wday = _(wkdays[wkday])
        if wkday in wkend:
            cssday = "cal-weekend"
        else:
            cssday = "cal-workday"
        restd2.append('  <td class="%s" width="14%%">%s</td>\n' % (cssday, wday))
    restr2 = ' <tr>\n%s </tr>\n' % "".join(restd2)
 
    if parmheight6:
        while len(monthcal) < 6:
            monthcal = monthcal + [[0,0,0,0,0,0,0]]

    maketip_js = []
    restrn = []
    for week in monthcal:
        restdn = []
        for wkday in r7:
            day = week[wkday]
            if not day:
                restdn.append('  <td class="cal-invalidday">&nbsp;</td>\n')
            else:
                page = parmpagename[0]
                if anniversary:
                    link = "%s/%02d-%02d" % (page, month, day)
                else:
                    link = "%s/%4d-%02d-%02d" % (page, year, month, day)
                daypage = Page(request, link)
                if daypage.exists() and request.user.may.read(link):
                    csslink = "cal-usedday"
                    query = {}
                    r, g, b, u = (255, 0, 0, 1)
                    daycontent = daypage.get_raw_body()
                    header1_re = re.compile(r"^\s*('''\s*(.*)\s*'''|=\s+(.*)\s+=)\s*$", re.MULTILINE) # re.UNICODE
                    titletext = []
                    for match in header1_re.finditer(daycontent):
                        if match:
                            if match.group(2) == None:
                		        title = match.group(3)
                            else:
                                title = match.group(2)
                            title = wikiutil.escape(title).replace("'","\\'")
                            titletext.append(title)
                    tipname = link
                    tiptitle = link
                    tiptext = '<br>'.join(titletext)
                    maketip_js.append("maketip('%s','%s','%s');" % (tipname, tiptitle, tiptext))
                    onmouse = {'onMouseOver': "tip('%s')" % tipname,
                               'onMouseOut':  "untip()"}
                else:
                    csslink = "cal-emptyday"
                    if parmtemplate:
                        query = {'action': 'edit', 'template': parmtemplate}
                    else:
                        query = {}
                    r, g, b, u = (255, 255, 255, 0)
                    if wkday in wkend:
                        csslink = "cal-weekend"
                    onmouse = {}
                for otherpage in parmpagename[1:]:
                    otherlink = "%s/%4d-%02d-%02d" % (otherpage, year, month, day)
                    otherdaypage = Page(request, otherlink)
                    if otherdaypage.exists():
                        csslink = "cal-usedday"
                        if u == 0:
                            r, g, b = (r-colorstep, g, b-colorstep)
                        else:
                            r, g, b = (r, g+colorstep, b)
                r, g, b = cliprgb(r, g, b)
                style = 'background-color:#%02x%02x%02x' % (r, g, b)
                fmtlink = formatter.url(1, daypage.url(request, query), csslink, **onmouse) + str(day) + formatter.url(0)
                if day == currentday and month == currentmonth and year == currentyear:
                    cssday = "cal-today"
                    fmtlink = "<b>%s</b>" % fmtlink # for browser with CSS probs
                else:
                    cssday = "cal-nottoday"
                restdn.append('  <td style="%s" class="%s">%s</td>\n' % (style, cssday, fmtlink))
        restrn.append(' <tr>\n%s </tr>\n' % "".join(restdn))

    restable = '<table border="2" cellspacing="2" cellpadding="2">\n%s%s%s</table>\n'
    restable = restable % (restr1, restr2, "".join(restrn))

    result = """\
<script language="JavaScript" type="text/javascript" src="%s/common/js/infobox.js"></script>
<div id="infodiv" style="position:absolute; visibility:hidden; z-index:20; top:-999em; left:0px;"></div>
<script language="JavaScript" type="text/javascript">
<!--
%s
// -->
</script>
%s
""" % (request.cfg.url_prefix, "\n".join(maketip_js), restable)
    return formatter.rawHTML(result)

# EOF

