#!/usr/bin/env python
# vim: set ts=8 sw=4 sts=4 et ai:
# Walter Doekes, 2011
import datetime, locale, logging, os, sys, time
try: from cStringIO import StringIO
except ImportError: from StringIO import StringIO
try: from urlparse import parse_qs
except ImportError: from cgi import parse_qs
try: from ho import pisa
except ImportError, e: raise ImportError('%s\n\n!! Please install python-pisa (the ho.pisa html2pdf converter) !!' % (e,))

DO_PDF = True

# Needed to display e.g. font errors. The wanted VAG Round font is
# missing a Character to Glyph mapping table (cmap). The reportlab tools
# refuse to use the font without it. Next step would be to "fix" the bad
# TTF and add the proper cmap (probably constructed from the cp1252 code
# page), but that's for another day.
class PisaLogHandler(logging.Handler):
    def emit(self, record):
        print >>sys.stderr, record.exc_info
logging.getLogger("ho.pisa").addHandler(PisaLogHandler())

def generate_weeks(begin_date, weeks, first_day='mon'):
    first_weekday = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'].index(first_day)
    curdate = begin_date - datetime.timedelta(days=((7 + begin_date.weekday() - first_weekday) % 7))
    curweekno = (curdate + datetime.timedelta(days=4)).isocalendar()[1] # take week# from middle of week
    weeks_data = []
    for i in xrange(weeks):
        week_days = []
        for j in range(7):
            week_days.append(curdate)
            curdate += datetime.timedelta(days=1)
        yield {'num': curweekno, 'days': week_days}
        curweekno += 1
        if curweekno >= 52 and curdate.month == 1:
            curweekno = 1
    
def create_calendar_html(title, weeks):
    style = []
    #style.append('@font-face { font-family:"VAG Round";src:url(/usr/share/fonts/truetype/msttcorefonts/vaground.ttf); }')
    style.append('@font-face { font-family:"Comic Sans MS";src:url(/usr/share/fonts/truetype/msttcorefonts/comic.ttf); }')
    style.append('table { padding-top:36px;border-collapse:collapse; }')
    style.append('th,td { font-family:"VAG Round","Comic Sans MS","Comic Sans",sans-serif;font-size:36px; }')
    style.append('td { padding-top:12px;border-bottom:4px solid black; }')
    html = []
    html.append('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
                ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n'
                '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\n'
                '<head><title>%s</title><style type="text/css">%s</style></head>\n<body>\n' % (title, ''.join(style)))
    for i, week in enumerate(weeks):
        if i != 0:
            html.append('<pdf:nextpage/>')
        month = week['days'][0].strftime('%B')
        if week['days'][0].month != week['days'][6].month:
            month += '/%s' % (week['days'][6].strftime('%B'),)
        html.append('<table width="100%%"><tr><th align="left">#%d</th><th align="right">%s</th></tr>' % (week['num'], month))
        for day in week['days']:
            html.append('<tr><td align="left">%s</td><td align="right">%s</td></tr>' % (day.strftime('%a'), day.strftime('%e')))
        html.append('</table>')
    html.append('</body>\n</html>')
    return '\n'.join(html)

def html_to_pdf(html):
    result = StringIO()
    #pdf = pisa.pisaDocument(StringIO(html.encode('utf-8')), result)
    pdf = pisa.pisaDocument(StringIO(html), result)
    if pdf.err:
        assert False
    return result.getvalue() # mimetype='application/pdf'

if __name__ == '__main__':
    is_cgi = bool(os.environ.get('QUERY_STRING') is not None)
    if is_cgi:
        import urlparse
        try:
            args = parse_qs(os.environ['QUERY_STRING'])
        except Exception, e:
            print repr(e)
        begin_date = args.get('begin_date', [''])[0] or datetime.date.today().strftime('%Y-%m-%d')
        weeks = args.get('weeks', [''])[0] or '1'
        localestr = args.get('locale', [None])[0]
    else:
        begin_date = len(sys.argv) >= 2 and sys.argv[1] or ''
        weeks = len(sys.argv) >= 3 and sys.argv[2] or ''
        localestr = len(sys.argv) >= 4 and sys.argv[3] or os.environ.get('LC_TIME')

    try:
        begin_date = datetime.date.fromtimestamp(time.mktime(time.strptime(begin_date, '%Y-%m-%d')))
        weeks = int(weeks)
        if weeks > 200:
            raise ValueError('Too many weeks!')
        if localestr:
            locale.setlocale(locale.LC_TIME, localestr)
    except Exception, e:
        if is_cgi:
            sys.stdout.write('Status: 500 Server Error\r\nContent-Type: text/plain\r\n\r\nBad arguments! (%s)\n' % (e,))
            sys.exit(0)
        else:
            print >>sys.stderr, 'Usage: %s begin_date weeks [locale] > output.pdf' % (sys.argv[0],)
            sys.exit(1)
    else:
        html = create_calendar_html('Calendar', generate_weeks(begin_date, weeks))
        if DO_PDF:
            if is_cgi:
                sys.stdout.write('Content-Type: application/pdf\r\nContent-Disposition: attachment; filename=calendar.pdf\r\n\r\n')
            sys.stdout.write(html_to_pdf(html))
        else:
            if is_cgi:
                sys.stdout.write('Content-Type: text/html; charset="UTF-8"\r\n\r\n')
            sys.stdout.write(html)
