"""
Command line tool for bulk exporting a range of TCX files from Polar Flow.

Usage is as follows:

    python polarflowexport.py <username> <password> <start_date> \
                <end_date> <output_dir>

The start_date and end_date parameters are ISO-8601 date strings (i.e.
year-month-day). An example invocation is as follows:

    python polarflowexport.py me@me.com mypassword 2015-08-01 2015-08-30 \
                        /tmp/tcxfiles

Licensed under the Apache Software License v2, see:
    http://www.apache.org/licenses/LICENSE-2.0
"""

import cookielib
import dateutil.parser
import json
import logging
import os
import sys
import time
import urllib2
import urllib

#------------------------------------------------------------------------------

class ThrottlingHandler(urllib2.BaseHandler):
    """A throttling handler which ensures that requests to a given host
    are always spaced out by at least a certain number of (floating point)
    seconds.
    """

    def __init__(self, throttleSeconds=1.0):
        self._throttleSeconds = throttleSeconds
        self._requestTimeDict = dict()

    def default_open(self, request):
        hostName = request.get_host()
        lastRequestTime = self._requestTimeDict.get(hostName, 0)
        timeSinceLast = time.time() - lastRequestTime
        
        if timeSinceLast < self._throttleSeconds:
            time.sleep(self._throttleSeconds - timeSinceLast)
        self._requestTimeDict[hostName] = time.time()


#------------------------------------------------------------------------------

class TcxFile(object):
    def __init__(self, workout_id, date_str, content):
        self.workout_id = workout_id
        self.date_str = date_str
        self.content = content


#------------------------------------------------------------------------------

class PolarFlowExporter(object):

    def __init__(self, username, password):
        self._username = username
        self._password = password
        self._logger = logging.getLogger(self.__class__.__name__)

        self._url_opener = urllib2.build_opener(
                        ThrottlingHandler(0.5),
                        urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
        self._url_opener.addheaders = [('User-Agent', 
                'https://github.com/gabrielreid/polar-flow-export')]
        self._logged_in = False

    def _execute_request(self, path, post_params=None):

        url = "https://flow.polar.com%s" % path

        self._logger.debug("Requesting '%s'" % url)

        if post_params != None:
            postData = urllib.urlencode(post_params)
        else:
            postData = None

        try:
            response = self._url_opener.open(url, postData)
            data = response.read()
        except Exception, e:
            self._logger.error("Error fetching %s: %s" % (url, e))
            raise Exception(e)
        response.close()
        return data  

    def _login(self):
        self._logger.info("Logging in user %s", self._username)
        self._execute_request('/')  # Start a new session
        self._execute_request('/login', 
            dict(returnUrl='https://flow.polar.com/', 
                    email=self._username, password=self._password))
        self._logged_in = True 
        self._logger.info("Successfully logged in")

    def get_tcx_files(self, from_date_str, to_date_str):
        """Returns an iterator of TcxFile objects.

        @param from_date_str an ISO-8601 date string
        @param to_date_str an ISO-8601 date string
        """
        self._logger.info("Fetching TCX files from %s to %s", from_date_str, 
                                                                to_date_str)
        if not self._logged_in:
            self._login()

        from_date = dateutil.parser.parse(from_date_str)
        to_date = dateutil.parser.parse(to_date_str)

        from_spec = "%s.%s.%s" % (from_date.day, from_date.month, 
                                    from_date.year)

        to_spec = "%s.%s.%s" % (to_date.day, to_date.month, 
                                    to_date.year)

        path = "/training/getCalendarEvents?start=%s&end=%s" % (
                                                        from_spec, to_spec)
        activity_refs = json.loads(self._execute_request(path))


        def get_tcx_file(activity_ref):
            self._logger.info("Retrieving workout %s" 
                                % activity_ref['listItemId'])
            return TcxFile(
                activity_ref['listItemId'],
                activity_ref['datetime'],
                self._execute_request(
                    "%s/export/tcx/false" % activity_ref['url']))

        return (get_tcx_file(activity_ref) for activity_ref in activity_refs)

#------------------------------------------------------------------------------

if __name__ == '__main__':

    logging.basicConfig(level=logging.INFO)
    try:
        (username, password, from_date_str, 
            to_date_str, output_dir) = sys.argv[1:]
    except ValueError:
        sys.stderr.write(("Usage: %s <username> <password> <from_date> "
            "<to_date> <output_dir>\n") % sys.argv[0])
        sys.exit(1)
    
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    exporter = PolarFlowExporter(username, password)
    for tcx_file in exporter.get_tcx_files(from_date_str, to_date_str):
        filename = "%s_%s.tcx" % (
                        tcx_file.date_str.replace(':', '_'),
                        tcx_file.workout_id)
        output_file = open(os.path.join(output_dir, filename), 'wb')
        output_file.write(tcx_file.content)
        output_file.close()
        print "Wrote file %s" % filename

    print "Export complete"