#!/usr/bin/env python

import logging
from datetime import datetime
logging.basicConfig(level=logging.WARNING)

import os
import urllib2, base64, json
import dateutil.parser

def from_ISO8601( str_iso8601 ):
    return dateutil.parser.parse(str_iso8601)

def to_ISO8601( timestamp ):
    return timestamp.isoformat()

def convert_time_strings(toggl_dicts):
    timestamp_fields = ['at',
                        'created_at',
                        'start',
                        'stop']
    result = []
    for tdict in toggl_dicts:
        d = tdict
        for tsf in timestamp_fields:
            if tdict.has_key(tsf):
                d[tsf] = from_ISO8601(tdict[tsf])
        result.append(d)
    return result

class Toggl:
    def __init__(self, api_token=None):
        self.log = logging.getLogger("Toggl")
        self.log.setLevel(logging.DEBUG)
        
        self.toggl_domain = "www.toggl.com"
        self.toggl_api = "https://%s/api/v8/" % self.toggl_domain
        self.report_api = "https://%s/reports/api/v2" % self.toggl_domain
        self._api_token = api_token

        # Search for an Toggl API token in a list of files
        # No validation of the collected token
        # TODO: encryption of tokenfiles could be nice
        tokenfiles = [os.path.expanduser(f) for f in ['.toggltoken', '~/.toggltoken', '~/.togglapplet/.toggltoken']]
        for tf in tokenfiles:
            if os.path.exists( tf ):
                try:
                    f = open(tf)
                    self._api_token = f.read().strip()
                    f.close()
                except:
                    self.log.exception("Could not read token from " + tf)
                    self._api_token = None
            if self._api_token: break
        
                
    def send_request( self, api_call_url ):
        ''' Send a request or command to Toggl, retrieve and parse the json response.
        returns a list of dictionary objects.
        Throws an exception if the http response is not OK (200) or if no JSON can be decoded from the response.
        '''
        request = urllib2.Request( api_call_url )
        self.log.debug("http request url = \'%s\'", request.get_full_url())

        # username:password
        # Use base64.standard_b64encode instead of replace...
        user_pass = base64.encodestring('%s:%s' % (self._api_token, 'api_token')).replace('\n', '')
        request.add_header("Authorization", "Basic %s" % user_pass)  
        opener = urllib2.build_opener(
                urllib2.HTTPHandler(),
                urllib2.HTTPSHandler(),
                urllib2.ProxyHandler({'https': 'http://wwwcache.rl.ac.uk:8080'})) 
        urllib2.install_opener(opener)
        result = urllib2.urlopen(request, timeout = 3.0) # with no data, this is a http GET.
        self.log.debug("http request result: code=%s url=\'%s\'", result.getcode(), result.geturl())
        js = json.load(result)
        #self.log.debug("JSON raw result: %s" % json.dumps(js,sort_keys=True, indent=4, separators=(',', ': ')))
        return js
    
    def get_workspaces(self):
        self.log.debug("get_workspaces()")
        js = self.send_request(self.toggl_api + "workspaces")
        js = convert_time_strings(js)
        return js
    
    def get_default_workspace(self):
        self.log.debug("get_default_workspace()")
        wid = self.get_user()['default_wid']
        js = self.send_request(self.toggl_api + "workspaces/%s"%str(wid))
        js = convert_time_strings([js['data']])
        return js[0]
    
    def get_default_workspace_id(self):
        self.log.debug("get_default_workspace_id()")
        ws = self.get_default_workspace()
        self.log.debug(ws)
        return ws['id']
    
    def get_projects(self, wid=None):
        self.log.debug("get_projects(wid=%s)"%str(wid))
        if wid:
            js = self.send_request(self.toggl_api + "workspaces/%s/projects"%str(wid))
        else:
            js = []
            for w in self.get_workspaces():
                js += self.send_request(self.toggl_api + "workspaces/%s/projects"%str(w['id']))
        js = convert_time_strings(js)
        return js
    
    def get_current_entry(self):
        '''get the currently active time entry'''
        self.log.debug("get_current_entry()")
        js = self.send_request(self.toggl_api + "time_entries/current")
        self.log.debug( js )
        js = convert_time_strings(js['data'])
        return js
        
    def get_range_entries(self, start_end=None):
        '''Get a list of entries in a range (max 1000 entries).
        If no start-end range is defined, the default is to return all entries
        from the last 9 days.
        start_end: tuple with start and end date'''
        self.log.debug("get_range_entries()")
        query = "time_entries"
        if start_end:
            start, end = start_end
            if type(start) == datetime.datetime:
                start = to_ISO8601(start)
            if type(end) == datetime.datetime:
                end = to_ISO8601(end)
            query += "?start_date=%s&end_date=%s"%(start, end)
        js = self.send_request(self.toggl_api + query)
        js = convert_time_strings(js)
        return js
            
    def get_user(self):
        self.log.debug("get_user()")
        js = self.send_request(self.toggl_api + "me")
        return js['data']

        
[((5, 0, 5, 42), 'logging.basicConfig', 'logging.basicConfig', (), '', False, 'import logging\n'), ((33, 19, 33, 45), 'logging.getLogger', 'logging.getLogger', ({(33, 37, 33, 44): '"""Toggl"""'}, {}), "('Toggl')", False, 'import logging\n'), ((62, 18, 62, 49), 'urllib2.Request', 'urllib2.Request', ({(62, 35, 62, 47): 'api_call_url'}, {}), '(api_call_url)', False, 'import urllib2, base64, json\n'), ((73, 8, 73, 38), 'urllib2.install_opener', 'urllib2.install_opener', ({(73, 31, 73, 37): 'opener'}, {}), '(opener)', False, 'import urllib2, base64, json\n'), ((74, 17, 74, 56), 'urllib2.urlopen', 'urllib2.urlopen', (), '', False, 'import urllib2, base64, json\n'), ((76, 13, 76, 30), 'json.load', 'json.load', ({(76, 23, 76, 29): 'result'}, {}), '(result)', False, 'import urllib2, base64, json\n'), ((44, 22, 44, 43), 'os.path.expanduser', 'os.path.expanduser', ({(44, 41, 44, 42): 'f'}, {}), '(f)', False, 'import os\n'), ((46, 15, 46, 35), 'os.path.exists', 'os.path.exists', ({(46, 31, 46, 33): 'tf'}, {}), '(tf)', False, 'import os\n'), ((70, 16, 70, 37), 'urllib2.HTTPHandler', 'urllib2.HTTPHandler', ({}, {}), '()', False, 'import urllib2, base64, json\n'), ((71, 16, 71, 38), 'urllib2.HTTPSHandler', 'urllib2.HTTPSHandler', ({}, {}), '()', False, 'import urllib2, base64, json\n'), ((72, 16, 72, 80), 'urllib2.ProxyHandler', 'urllib2.ProxyHandler', ({(72, 37, 72, 79): "{'https': 'http://wwwcache.rl.ac.uk:8080'}"}, {}), "({'https': 'http://wwwcache.rl.ac.uk:8080'})", False, 'import urllib2, base64, json\n'), ((67, 20, 67, 81), 'base64.encodestring', 'base64.encodestring', ({(67, 40, 67, 80): "'%s:%s' % (self._api_token, 'api_token')"}, {}), "('%s:%s' % (self._api_token, 'api_token'))", False, 'import urllib2, base64, json\n')]