#! /usr/bin/env python
# A html with css schedule generator that looks decent.
# Written by Natan 'whatah' Zohar & chromakode
# The schedule file is in this format:

# Descriptive Text
# MTWR [8:30- 9:30] JPN 204
# TR [13:15- 14:40] LING 218J
# TR [10:05-11:30] SPAN 344
# MW [13:10-14:10] CHIN 112
# TR [16:25-17:50] AAAS 241

import random
import sys
import copy

HOURS = 24.0
DAYS = 7.0
EM_SIZE = 4.0
COLORS = ["b_butter", "b_orange", "b_chocolate", "b_chameleon", "b_skyblue", "b_plum", "b_scarletred"]

def rotate_list(l, n):
	length = len(l)
	rl = copy.copy(l)
	for i in xrange(length):
		rl[i] = l[(i+n) % length]
	return rl
		
COLORS = rotate_list(COLORS, random.randint(0, len(COLORS)-1))
avail_colors = copy.copy(COLORS)

def time_to_int(time):
    time = time.split(':')
    x = int(time[0])+int(time[1])/60.0
    return x

def int_to_time(i):
    return "%s:%02i" % (int(i), int((i%1.0) * 60.0))
    
def int_to_html_time(i):
	return """<span class="hour">%s</span><span class="minute">:%02i</span>""" % (int(i), int((i%1.0) * 60.0))

def get_color():
	global avail_colors
	#color = random.choice(avail_colors)
	color = avail_colors.pop(0)
	if not len(avail_colors): avail_colors = copy.copy(COLORS)
	return color
	

class Block:
    def __init__(self, name=None, days=None, start=None, end=None):
        self.name = name
        self.days = days
        if type(start) == str:
            self.start = time_to_int(start)
        else:
            self.start = start

        if type(end) == str:
            self.end = time_to_int(end)
        else:
            self.end = end

        self.color = get_color()
    
class Schedule:
    def __init__(self):
        self.hours = 24.0
        self.blocks = []
        self.earliest = 0
        self.latest = 24
        self.title = None

    def make_block(self, name, days, start_time, end_time):
        b = Block(name, days, start_time, end_time)
        if not len(self.blocks):
            self.earliest = int(b.start)
            self.latest = int(b.end)
        else:
            self.earliest = int(min(self.earliest, b.start))
            self.latest = int(max(self.latest, b.end))
        
        self.hours = int(self.latest - self.earliest + 1)

    def add_block(self, b):
        if len(self.blocks) == 0:
            self.earliest = int(b.start)
            self.latest = int(b.end)
        else:
            self.earliest = int(min(self.earliest, b.start))
            self.latest = int(max(self.latest, b.end))
        self.hours = int(self.latest - self.earliest + 1)+1
        
        self.blocks.append(b)

    def to_html(self):
        print \
"""
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>%s</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
body, table {
    font-family: sans-serif;
    font-size: 12px;
}

h1 {
    font-size: 2.5em;
    /*border-bottom: 2px dotted #CCC;*/
}

#grid {
    border-collapse: collapse;
    table-layout: fixed;
    background: url(bggrad.png) repeat-x;
    background-color: #DDD;
}

#grid th {
    background: white;
    padding: 20px 15px 5px 15px;
    border-bottom: 1px solid black;
    width: 7em;
}

#grid thead th.time{
    border: none;
    width: 5.5em;
}

#grid td {
    border-left: 2px solid black;
    border-right: 2px solid black;
    border-bottom: 1px solid #BBB;
    padding: 4px;
    height: 2em;
    overflow: hidden;
    vertical-align: top;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
}

#grid td.time {
    background: white;
    padding-left: 15px;
    border: none;
    vertical-align: bottom;
}

#grid tr.hour0-30 td {
    border-bottom: 1px solid #DDD;
}

#grid tr.hour0-30 td.time {
    border-bottom: none;
}

#grid tbody tr.hour30-60 td.time {
    border-bottom: 1px dotted #333;
}

#grid td.time div {
	position: relative;
	top: 3.5em;
	margin: 0;
	height: 0;
}

#grid tr.hour30-60 td.time div {
	display: none;
}

#grid td.time .hour {
	font-size: 1.5em;
	letter-spacing: -0.05em;
}

#grid td.time .minute {
	vertical-align: top;
	padding-left: 2px;
}

#grid tfoot td {
	border-bottom: 1px solid black;
}

div.eventcontainer {
    position: relative;
    height: 0;
    margin: -4px;
    top: -4px;
}

div.eventbox {
    display: block;
    position: relative;
    width: 100%%;
    height: 4em;
    color: white;
    text-align: center;
    padding: 4px;
    opacity: .95;
    filter: progid:DXImageTransform.Microsoft.Alpha(opacity=95);
    box-sizing: border-box;
    -moz-box-sizing: border-box;
}

div.event {
    display: table;
    background: url(grad.png) repeat-x;
    background-color: #999;
    filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=scale src='grad.png');
    border: 2px solid black;
    height: 100%%;
    width: 100%%;
    margin: 0;
}

div.event h2 {
    display: table-cell;
    margin: 0;
    font-size: 1.25em;
    padding-top: 4px;
    vertical-align: bottom;
    width: 100%%;
    height: 50%%;
}

div.event p {
    /* table-row makes it work. wtf? */
    display: table-row;
    margin: 0;
    font-size: 1em;
    opacity: .5;
    filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50);
}

div.b_butter div {
    background-color: #edd400;
}

div.b_orange div {
    background-color: #f57900;
}

div.b_chocolate div {
    background-color: #c17d11;
}

div.b_chameleon div {
    background-color: #8ae234;
}

div.b_skyblue div {
    background-color: #729fcf;
}

div.b_plum div {
    background-color: #ad7fa8;
}

div.b_scarletred div {
    background-color: #ef2929;
}
</style>
</head> \
""" % (self.title)
        print \
"""
<body>
<h1>%s</h1>
<table id="grid">
<thead>
<tr>
<th class="time"></th>
<th>Sunday</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
</tr>
</thead>
<tbody>""" % self.title
        for x in xrange(self.earliest-1, self.latest+1):
            # --- BEGIN HOUR ---
            print """<tr class="hour0-30">""",
            print """<td class="time"><div>%s</div></td>"""%(int_to_html_time(x+1))
            for day in xrange(int(DAYS)):
                empty = True
                x = float(x)
                print "<td>",
                for block in self.blocks:
                    if block.start >= x and block.start < x+1 and day in block.days:
                        empty = False
                        print \
"""
<div class="eventcontainer">
<div class="eventbox %s" style="top: %sem; height: %sem;">
<div class="event"> 
<h2>%s</h2>
<p>%s-%s</p>
</div>
</div>
</div> \
""" % (block.color, block.start % 1.0 * EM_SIZE, (block.end - block.start) * EM_SIZE, block.name,
        int_to_time(block.start), int_to_time(block.end))
                print "</td>" 
            print "</tr>"
            print """<tr class="hour30-60"><td class="time"><div>%s</div></td><td /><td /><td /><td /><td /><td /><td /></tr>"""%int_to_time(x+1.5)
			# --- END HOUR ---
			
# --- START FOOTER ---
        print \
""" \
</tbody>
<tfoot>
<tr class="hour0-30"><td class="time" /><td /><td /><td /><td /><td /><td /><td /></tr>
<tr class="hour30-60"><td class="time"/><td /><td /><td /><td /><td /><td /><td /></tr>
</tfoot>
</table>
</body>
</html>
"""

        
def parse_schedule(data, regex):
    import re
    blocks = []
    for line in data:
        pattern = re.compile(regex)
        result = pattern.match(line)
        if not result:
            print >> sys.stderr, "%s ^does not match the regex" % (line)
            continue
        days = result.group("days")
        stime = result.group("stime")
        etime = result.group("etime")
        name = result.group("name")

        real_days = []
        for day in days:
            real_days.append("UMTWRFS".index(day))
        blocks.append(Block(name, real_days, stime, etime))

    return blocks







if __name__ == "__main__":
    import sys
    if len(sys.argv) < 2:
        print "Usage: %s <schedule>" % sys.argv[0]
    else:
        schedfile = open(sys.argv[1])
        sc = Schedule()
        sc.title = schedfile.readline()
        regex = "\s*(?P<days>\w*)\s*\[(?P<stime>.*?)-(?P<etime>.*?)\]\s*(?P<name>.*).*"
        for block in parse_schedule(schedfile.readlines(), regex):
            sc.add_block(block)     

        sc.to_html()


