from __future__ import division
import re
import time
import cairo
import math
import yaml
import os

def get_scale(cr):
  '''for one pixel lines etc'''
  tmp = cr.user_to_device(1,1)
  scale = (tmp[0] + tmp[1]) / 2.
  return scale

category_colors = {"net":"red",
                  "sleep":"blue",
                  "food":"green",
                  "chat":"yellow",
                  "nothing":"magenta",
                  "domestics":"darkgreen",
                  "act":"darkorange",
                  "watch":"cyan",
                  #those below i'm not so sure about 
                  "setup":"darkcyan",
                  "code":"darkyellow",
                  "garden":"darkgreen",
                  "play":"orange",
                  "clean":"darkcyan",
                  "driving":"darkred",
                  "shoppin":"darkorange",
                  "science":"darkblue",
                  "read":"darkmagenta"
                  }

rgb_map = {"red":     (1, 0, 0),
          "green":    (0, 1, 0),
          "blue":     (0, 0, 1),
          "yellow":   (1, 1, 0),
          "magenta":  (1, 0, 1),
          "cyan":     (0, 1, 1),
          "orange":   (1, 0.5, 0),
          "darkgreen":(0, 0.5, 0),
          "darkblue": (0, 0, 0.5),
          "darkyellow":(0.5, 0.5, 0),
          "darkcyan": (0, 0.5, 0.5),
          "darkorange":(0.5, 0.25, 0),
          "darkred":  (0.5, 0, 0),
          "darkmagenta":(0.5, 0, 0.5)
          }


class Table:
  def __init__(self):
    global root
    self.dirname = root + '/'
    if not os.path.isdir(self.dirname):
      os.mkdir(self.dirname)
  #  self.row_width, self.row_height = 613, 20
  def get_num_rows(self):
    try:
      num_rows = len(self.days)
    except AttributeError:
      num_rows = 1
    return num_rows
  def resize(self):
    self.width, self.height = self.row_width, self.row_height*self.get_num_rows()
  def init_cairo(self, filename=None):
    if filename == None: filename = self.filename
    self.resize()
    self.surface = cairo.SVGSurface(filename + '.svg', self.width, self.height)
    cr = self.cr = cairo.Context(self.surface)
    cr.translate(0.5, 0.5)
    cr.set_source_rgba(1,1,1,1)
    cr.rectangle(0,0,self.width, self.height)
    cr.fill()  
  def write_png(self, filename=None):
    if filename == None: filename = self.filename
    self.surface.write_to_png(filename + '.png')

class Month(Table):
  '''date is a human readable filename string, start is unix timestamp at midnight'''
  def __init__(self, date, start):
    Table.__init__(self)
    self.filename = self.dirname + date
    self.date, self.start = date, start
    self.days = []
  def draw(self, cr):
    self.resize()
    cr.save()
    for day in self.days:
      day.row_width, day.row_height = self.row_width, self.row_height
      day.draw(cr)
      cr.translate(0,  self.row_height)
    cr.restore()


class Day(Table):
  '''date is a human readable filename string, start is unix timestamp at midnight'''
  def __init__(self, date, start):
    Table.__init__(self)
    self.dirname = self.dirname + yyyy_mm(start) + '/'
    if not os.path.isdir(self.dirname):
      os.mkdir(self.dirname)
    self.filename = self.dirname + date
    self.date, self.start = date, start
    self.intervals = []
  def draw(self, cr):
    self.resize()
    width, height = self.width, self.height
    cr.save()
    cr.scale(width, height)
    aspect = width/height
    cr.set_line_width(1./get_scale(cr))
    cr.set_source_rgba(1, 1, 1, 0.1)
    #cr.fill()
    cr.set_source_rgba(0, 0, 0, 0.5)
    #underscore
    cr.move_to(0, 0.98)
    cr.line_to(1, 0.98)
    cr.stroke()

    #24 ruler
    for n in range(0, 24):
      x, y = (n/24, 0.98)
      ##tic marks
      #cr.move_to(x, y)
      #cr.line_to(x, 0.7)
      #cr.stroke()
      label = str(n)
      cr.move_to(x, y)
      cr.save()
      cr.identity_matrix()
      cr.set_font_size(width/(24*2))
      cr.show_text(label)
      cr.fill()
      cr.restore()
    for i in self.intervals:
      i.draw(cr, width, height)
    cr.restore()


class Interval:
  def __init__(self, start, end, location=None):
    self.start, self.end = start, end
    self.actions = []
    
    start_date = yyyy_mm_dd(self.start)
    end_date   = yyyy_mm_dd(self.end)
    if start_date != end_date:
      print "interval %d %d crosses date boundary!" % (start, end)
    self.date = yyyy_mm_dd(self.start)

  def draw(self, cr, width, height):
    '''draws a gantt-charty-thing to a cairo context, with overlapping colored rectangles'''
    aspect = width/height
    day_secs = 24*60*60
    day_start = days[self.date].start
    for action in self.actions:
      try:
        color = rgb_map[category_colors[action.category]]
        cr.set_source_rgba(color[0], color[1], color[2], 0.65)
      except KeyError:
        cr.set_source_rgba(0, 0, 0, 0.2)
      cr.rectangle((self.start-day_start)/day_secs, 0, ((self.end - self.start )/day_secs), 0.95)
      cr.fill_preserve()
      cr.set_source_rgba(0, 0, 0, 1)
      cr.save()
      cr.set_line_width(1)
      cr.identity_matrix()
      cr.stroke()
      cr.restore()

def yyyy_mm_dd(timestamp):
  '''don't forget to set your timezone properly'''
  return "%04d_%02d_%02d" % (time.localtime(timestamp)[0:3])

def yyyy_mm(timestamp):
  '''don't forget to set your timezone properly'''
  return "%04d_%02d" % (time.localtime(timestamp)[0:2])

class Action:
  def __init__(self, interval, category, string=None, comment=None):
    self.interval, self.category, self.string, self.comment = \
      interval, category, string, comment

days = {}
months = {}
categories = {}

def parse(filename):
  '''each line looks like this:
  1341 1514 work do-this do-that do-the-other, food carrot 2pc pie'''
  f = open(filename)
  line = "hi!"
  global days
  linenum = 0
  category, string, comment = None, None, None
  year, month, day = 0,0,0
  last_month = 0
  starthour, startmin, endhour, endmin, actions = 0,0,0,0,0
  startepoch, laststart, endepoch, lastend = 0,0,0,0
  
  while line:
    linenum += 1
    line = f.readline()
    d_match = re.match('^date (\d{4}) (\d{2}) (\d{2})', line)
    if d_match:
      year, month, day = (int(i) for i in d_match.groups())
      start = time.mktime((year, month, day, 0, 0, 0, 0, 0, -1))
      date = yyyy_mm_dd(start)
      days[date] = Day(date, start) #the filename yyyy_mm_dd (date) is the dict key
      monte = yyyy_mm(start) #like date for months instead of days
      if month != last_month:
        months[monte] = Month(monte, start)
        last_month = month
      months[monte].days.append(days[date])
    i_match = re.match('^(\d{2})(\d{2}) (\d{2})(\d{2})(.*)', line)
    if i_match:
      starthour, startmin, endhour, endmin = (int(i) for i in i_match.group(1,2,3,4))
      actions = i_match.groups()[-1]
      #print "%d %02d %02d %d%d %d%d %s" % (year, month, day, starthour, startmin, endhour, endmin, actions)
      laststart, lastend = startepoch, endepoch
      startepoch = time.mktime((year, month, day, starthour, startmin, 0, 0, 0, -1))
      endepoch =   time.mktime((year, month, day, endhour, endmin, 0, 0, 0, -1))
      if (startepoch > endepoch) or (lastend > startepoch):
        print "time discrepancy!", line
      a_match = re.match('\s(\w+)\s?(.*)', actions)
      if a_match:
        category, string = a_match.groups()
        global categories
        try:
          categories[category] += 1
        except KeyError:
          categories[category] = 0
      c_match = re.match('\(.*\)', actions)
      if c_match:
        comment = a_match.groups()
      #pack it into our object
      interval = Interval(startepoch, endepoch)
      #TODO one per action, not just a string...
      interval.actions.append(Action(interval, category, string=string, comment = comment))
      interval.line = line.strip('\n')
      if interval.date != date:
        print "date discrepancy! %s %s" % (date, interval.date)

      days[date].intervals.append(interval)


root = 'sleepz'
parse("pda_db.txt")
#maybe i should explicitly create the dir here?
html_m = open(root + "/test.html", "w")
html_m.write('<html>\n')
keys = months.keys()
keys.sort()
for monte in keys:
  month = months[monte]
  month.row_width, month.row_height = 200, 5
  month.init_cairo() 
  month.draw(month.cr)
  print month.filename
  month.write_png()
  relative_d = '/'.join(month.filename.split('/')[1:])
  html_m.write('<a href="' + relative_d + '.html">\n')
  html_m.write('<img src="' + relative_d + '.png"><br>')
  html_m.write('</a>\n')
  html_d = open(month.filename + '.html', 'w')
  html_d.write('<html>\n')
  for day in month.days:
    day.row_width, day.row_height = 613, 20
    day.init_cairo()
    day.draw(day.cr)
    day.write_png()
    relative_d = '/'.join(day.filename.split('/')[1:])
    html_d.write('<img src="' + relative_d + '.png"><br>\n')
  html_d.write('</html>')
  html_d.close()
  #print yaml.dump(day)
html_m.write('</html>')
html_m.close()

#sort by value
list = sorted(categories.iteritems(), key=lambda (k,v): v, reverse=True)
print "Categories:" + '\n', list

