import datetime
import time
from dateutil import parser as du_parser
import gtimelog
from templess import templess
import math
import py

def format_date(d):
    return d.strftime('%A, %Y-%m-%d (week %W)')

def format_datetime(dt):
    return dt.strftime('%Y-%m-%d %H:%M')

def format_time(t):
    return t.strftime('%H:%M')

def format_duration(td, always_show_hours=False):
    ret = []
    seconds = td.seconds + (td.days * 3600 * 24)
    if td.seconds > 3600:
        hours = int(math.floor(seconds / 3600))
        seconds = seconds % 3600
        ret.append('%s h' % (hours,))
    elif always_show_hours:
        ret.append('0 h')
    ret.append('%s min' % (int(math.floor(seconds / 60)),))
    return ' '.join(ret)

class HTTTimeLog(object):
    def __init__(self, form, logdir, templatedir):
        self._form = form

        self._logpath = logpath = self._init_path(logdir)
        self._timelogfile = str(logpath / 'timelog.txt')
        self._tasksfile = tasksfile = str(logpath / 'tasks.txt')
        self._settingsfile = settingsfile = str(logpath / 'gtimelogrc')

        self._templatedirpath = self._init_path(templatedir)

        # init Settings on self.settings
        self.settings = settings = gtimelog.Settings()
        settings.load(settingsfile)

        # calculate start and end of view
        lt = time.localtime()
        vm = (settings.virtual_midnight.hour, 
                settings.virtual_midnight.second)
        last_midnight = lt[:3] + vm
        coming_midnight = lt[:2] + (lt[2] + 1,) + vm
        self._min = self._get_date_from_form('min', 
                                        datetime.datetime(*last_midnight))
        self._max = self._get_date_from_form('max', 
                                        datetime.datetime(*coming_midnight))

        # load self.tasklist, self.timelog and self.timewindow
        self.load()

    def render(self):
        view_type = self._form.getvalue('view_type', 'chronological')
        
        contenttemplatepath = self._templatedirpath / ('%s.html' % 
                                                        (view_type,))
        template = templess.template(contenttemplatepath.open())
        rendered = template.render(self.get_template_context(view_type))
        content = rendered.xpath('//body/*')

        taskstemplatepath = self._templatedirpath / 'tasks.html'
        template = templess.template(taskstemplatepath.open())
        rendered = template.render(self.get_tasks_context())
        tasks = rendered.xpath('//body/*')

        macropath = self._templatedirpath / 'macro.html'
        macro = templess.template(macropath.open())
        return macro.render_to_string(
                self.get_macro_context(content, tasks, view_type))
        
    def get_macro_context(self, content, tasks, view_type):
        totals_tw = self.timewindow.totals()
        weekwindow = self.weekly_window()
        totals_week = weekwindow.totals()
        work_days_this_week = weekwindow.count_days()
        last_time = self.timewindow.last_time()
        now = datetime.datetime(*time.localtime()[:-2])
        time_left = (self.timewindow.count_days() == 1 and
                        (datetime.timedelta(0, self.settings.hours * 3600) - 
                            totals_tw[0] - (now - last_time)) or 0)
        context = {
            'content': content,
            'tasks': tasks,
            'date': format_date(self._min),
            'min': format_datetime(self._min),
            'max': format_datetime(self._max),
            'view_type': view_type,
            'is_chronological': view_type == 'chronological',
            'is_grouped': view_type == 'grouped',
            'total_work_tw': format_duration(totals_tw[0]),
            'total_slack_tw': format_duration(totals_tw[1]),
            'total_work_week': format_duration(totals_week[0]),
            'total_slack_week': format_duration(totals_week[1]),
            'has_work_days': not not work_days_this_week,
            'total_work_per_day': (work_days_this_week and 
                    format_duration(totals_week[0] / work_days_this_week) or
                    ''),
            'total_slack_per_day': (work_days_this_week and 
                    format_duration(totals_week[1] / work_days_this_week) or
                    ''),
            'time_left': format_duration(time_left),
            'until': format_time(now + time_left),
            'have_last_time': not not last_time,
            'currduration': (last_time and 
                                format_duration(now - last_time, True) or 
                                '0 h 0 min'),
            'comment': (self._form.getvalue('task', '') or 
                        (self._form.has_key('reload') and 
                            self._form.getvalue('comment', ''))),
        }
        return context

    def get_template_context(self, view_type):
        context = {
        }
        if view_type == 'chronological':
            context['entries'] = [
                {'start': format_datetime(e[0]),
                    'starttime': format_time(e[0]),
                    'end': format_datetime(e[1]),
                    'endtime': format_time(e[1]),
                    'duration': gtimelog.format_duration(e[2]),
                    'text': e[3],
                    'entryclass': (e[3].strip().endswith('**') and 
                                    'slack' or 'work'),
                } for e in self.timewindow.all_entries()
            ]
        else:
            context['groups'] = [
                {'data': [{'start': format_datetime(e[0]),
                            'starttime': format_time(e[0]),
                            'text': e[1],
                            'duration': gtimelog.format_duration(e[2]),
                            'is_work': not e[1].strip().endswith('**'),
                        } for e in g
                    ]
                } for g in self.timewindow.grouped_entries()
            ]
        return context

    def get_tasks_context(self):
        context = {
            'groups': [{
                'title': g[0],
                'id': '%s: ' % (g[0],),
                'subtasks': [{
                    'title': st,
                    'id': (g[0] == 'Other' and st or '%s: %s' % (g[0], st)),
                } for st in g[1]],
            } for g in self.tasklist.groups],
        }
        return context

    def append_from_form(self):
        comment = self._form.getvalue('comment')
        if self._form.getvalue('add') and comment:
            self.timelog.append(comment)
            self.load()

    def render_timelog_editor(self):
        templatepath = self._templatedirpath / 'timelog_editor.html'
        template = templess.template(templatepath.open())
        return template.render_to_string(self.get_timelog_editor_context())

    def get_timelog_editor_context(self):
        context = {
            'timelog': (self._logpath / 'timelog.txt').read(),
        }
        return context

    def save_timelog_from_form(self):
        timelog = self._form.getvalue('timelog')
        if timelog:
            (self._logpath / 'timelog.txt').write(timelog)
            self.load()

    def render_tasks_editor(self):
        templatepath = self._templatedirpath / 'tasks_editor.html'
        template = templess.template(templatepath.open())
        return template.render_to_string(self.get_tasks_editor_context())

    def get_tasks_editor_context(self):
        context = {
            'tasks': (self._logpath / 'tasks.txt').read(),
        }
        return context

    def save_tasks_from_form(self):
        tasks = self._form.getvalue('tasks')
        if tasks:
            (self._logpath / 'tasks.txt').write(timelog)
            self.load()

    def weekly_window(self, day=None):
        # XXX copied from GTimeLog... some refactoring (or perhaps some hack
        # here?) would be nice
        if not day:
            day = self.timelog.day
        monday = day - datetime.timedelta(day.weekday())
        min = datetime.datetime.combine(monday,
                        self.timelog.virtual_midnight)
        max = min + datetime.timedelta(7)
        window = self.timelog.window_for(min, max)
        return window

    def _init_path(self, filename):
        if filename.startswith('/'):
            fpath = py.path.local(filename)
        else:
            fpath = py.magic.autopath().dirpath() / filename
        return fpath

    def _get_date_from_form(self, key, default):
        value = self._form.getvalue(key)
        if value is not None:
            try:
                # XXX we should really use the date parsing stuff from 
                # gtimelog
                value = du_parser.parse(value)
            except ValueError:
                value = None
        return value or default

    def load(self):
        self.tasklist = gtimelog.TaskList(self._tasksfile)
        self.timelog = tl = gtimelog.TimeLog(self._timelogfile, 
                                        self.settings.virtual_midnight)
        self.timewindow = tl.window_for(self._min, self._max)

