#!/usr/bin/env python

# Reads a page with a wiki-format table

# Basic data structure of dictionary:
#  {(year, month, day) -> [(time, duration, title)]

import sys, optparse
import re, string
import pprint, cgi
import datetime

import talks

date_pat = re.compile('^=\s+(\d{4})-(\d{2})-(\d{1,2})\s+.*\s+=')
line_pat = re.compile('[|]{2}.*[|]{2}\s*$')
talk_pat = re.compile('#(\d+)')

def parse ():
    lines = sys.stdin.readlines()
    lines = map(string.strip, lines)
    d = {}
    date = None
    
    for line in lines:
	m = date_pat.match(line)
	if m:
	    date = [int(value) for value in m.group(1,2,3)]
            date = tuple(date)
			
	m = line_pat.match(line)
	if m:
	    if date is None:
		print >>sys.stderr, "Table line before date header: %r" % line
	    else:
		L = line.split('||')
		L = map(string.strip, L)
		assert L[0] == ''
		assert L[-1] == ''
		L = L[1:-1]
		if len(L) != 4:
		    print >>sys.stderr, "Wrong number of fields in line: %r" % line
                # Skip headers
		elif L[0].lower() == 'room':
                    pass
                else:
		    event_list = d.setdefault(date, [])
                    t = canonicalize_presentation(L)
		    event_list.append(t)

    return d


time_pat = re.compile('(\d+):(\d+)')

def parse_time (S):
    """(str): (int, int)
    Parse a time into an (hour, minute) tuple.
    """
    m = time_pat.match(S)
    assert m is not None
    hour, min = int(m.group(1)), int(m.group(2))
    return hour, min


def canonicalize_presentation (L):
    """Take a 4-item list for a talk and perform various
    corrections to it.
    """
    hour, min = parse_time(L[1])
    L[1] = '%02i:%02i' % (hour, min)
    L[2] = int(L[2])
    return tuple(L)
    


#
# HTML generation functions
#

def add_time (start_time, duration):
    hour, min = parse_time(start_time)
    while duration > 60:
        hour += 1
        duration -= 60
    min += duration
    while min >= 60:
        hour += 1
        min -= 60
    return '%02i:%02i' % (hour, min)

def find_next_time (time_list, end_time):
    if len(time_list) == 0:
        return 1
    span = 0
    while (span < len(time_list) and time_list[span][0] < end_time):
        span += 1
    if span == len(time_list):
        return 1
    return span+1
    
    
def format_day (day, output):
    # Figure out unique rooms
    rooms = []
    for room, time, duration, title in day:
        # XXX change to use regex pattern
        if room.startswith('-'):
            continue
        if room not in rooms:
            rooms.append(room)
    rooms.sort()

    # Move Bent Tree to be last
    if 'Bent Tree' in rooms:
        rooms.remove('Bent Tree')
        rooms.append('Bent Tree')

    # Print room header
    print >>output,  '''<table width="80%%" border=3>
<col width="75"><col span=%i width="*">
''' % len(rooms)

    print >>output, "<thead>"
    print >>output, '<tr><td></td>',
    for room in rooms:
        print >>output,  '<th>%s</th>' % room,
    print >>output,  '</tr>'
    print >>output, "</thead>"
    
    # Sort list
    time_dict = {}
    for room, time, duration, title in day:
        d = time_dict.setdefault(time, {})
        d[room] = (duration, title)
    time_list = time_dict.items()
    time_list.sort()

    active = {}
    print '<tbody>'
    while len(time_list) > 0:
        time, room_dict = time_list.pop(0)
        print >>output,  '<tr>',
        for act_room, end_time in active.items():
            if end_time <= time:
                del active[act_room]
        print >>output,  '<th>%s</th>' % time,
        plenary = (len(room_dict) == 1)
        if plenary:
            # Plenary session of some sort
            duration, title = room_dict.values()[0]
            colspan = len(rooms)
            print >>output,  '<td align="center" colspan=%i>%s</td>' % (colspan, title),
            print >>output,  '</tr>'
            continue
        
        for room in rooms:
            # Room still occupied, so skip it
            if room in active:
                continue

            # New room
            t = room_dict.get(room)
            if t is None:
                print >>output,  '<td rowspan=1>&nbsp;</td>',
            else:
                duration, title = t
                end_time = add_time(time, duration)
                active[room] = end_time
                rowspan = find_next_time(time_list, end_time)

                # Turn talk numbers into a link with a title
                m = talk_pat.match(title)
                if m is not None:
                    talk_num = int(m.group(1))
                    title = talks.get_title(talk_num)
                else:
                    title = cgi.escape(title)
                
                print >>output,  '<td rowspan="%i">' % rowspan,
                print >>output,  title,
                print >>output,  '</td>',
        
        print >>output,  '</tr>'

    print '</tbody>'
    print >>output,  '</table>'


def output_html (d, output):
    L = d.items() ; L.sort()

    for (y, m, day), day_data in L:
        date = datetime.date(y, m, day)
        print >>output, date.strftime('<h3>%A, %B %d %Y</h3>')
        format_day(day_data, output)

    
def main ():
    parser = optparse.OptionParser(usage="usage: %prog [options] < final-schedule")
    parser.add_option('--format',
                      type='choice',
                      choices=['pickle', 'python', 'print', 'html'],
                      default='print',
                      action="store", dest="format",
                      help = "Select output format")
    options, args = parser.parse_args()

    d = parse()
    fmt = options.format
    if fmt == 'print':
        pprint.pprint(d)
    elif fmt == 'python':
        print 'schedule =',
        pprint.pprint(d)
    elif fmt == 'pickle':
        import cPickle
        cPickle.dump(d, sys.stdout)
    elif fmt == 'html':
        output_html(d, sys.stdout)
    else:
        print >>sys.stderr, "Unknown format %r" % fmt
        sys.exit(1)
        
if __name__ == '__main__':
    main()
    





