from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals


# The interactions with the Concept2 logbook API
# All C2 related functions should be defined here
# (There is still some stuff defined directly in views.py. Need to
# move that here.)

from rowers.imports import *
import datetime
from requests import Request, Session
import rowers.mytypes as mytypes
from rowers.mytypes import otwtypes
from rowers.rower_rules import is_workout_user,ispromember
from iso8601 import ParseError

import numpy
import json
from json.decoder import JSONDecodeError

from rowsandall_app.settings import (
    C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET
    )

from rowers.tasks import handle_c2_import_stroke_data, handle_c2_sync
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
from rowers.utils import myqueue
from rowers.models import C2WorldClassAgePerformance

from django.core.exceptions import PermissionDenied

def getagegrouprecord(age,sex='male',weightcategory='hwt',
                      distance=2000,duration=None,indf=pd.DataFrame()):

    if not indf.empty:
        if not duration:
            df = indf[indf['distance'] == distance]
        else:
            duration = 60*int(duration)
            df = indf[indf['duration'] == duration]
    else:
        if not duration:
            df = pd.DataFrame(
                list(
                    C2WorldClassAgePerformance.objects.filter(
                        distance=distance,
                        sex=sex,
                        weightcategory=weightcategory
                    ).values()
                )
            )
        else:
            duration=60*int(duration)
            df = pd.DataFrame(
                list(
                    C2WorldClassAgePerformance.objects.filter(
                        duration=duration,
                        sex=sex,
                        weightcategory=weightcategory
                    ).values()
                )
            )

    if not df.empty:
        ages = df['age']
        powers = df['power']

        #poly_coefficients = np.polyfit(ages,powers,6)
        fitfunc = lambda pars, x: np.abs(pars[0])*(1-x/max(120,pars[1]))-np.abs(pars[2])*np.exp(-x/np.abs(pars[3]))+np.abs(pars[4])*(np.sin(np.pi*x/max(50,pars[5])))
        errfunc = lambda pars, x,y: fitfunc(pars,x)-y

        p0 = [700,120,700,10,100,100]

        try:
            p1, success = optimize.leastsq(errfunc,p0[:],
                                       args = (ages,powers))
        except:
            p1 = p0
            success = 0

        if success:
            power = fitfunc(p1, float(age))

            #power = np.polyval(poly_coefficients,age)

            power = 0.5*(np.abs(power)+power)
        else:
            power = 0
    else:
        power = 0

    return power


oauth_data = {
    'client_id': C2_CLIENT_ID,
    'client_secret': C2_CLIENT_SECRET,
    'redirect_uri': C2_REDIRECT_URI,
    'autorization_uri': "https://log.concept2.com/oauth/authorize",
    'content_type': 'application/x-www-form-urlencoded',
    'tokenname': 'c2token',
    'refreshtokenname': 'c2refreshtoken',
    'expirydatename': 'tokenexpirydate',
    'bearer_auth': True,
    'base_url': "https://log.concept2.com/oauth/access_token",
    'scope':'write',
    }


# Checks if user has Concept2 tokens, resets tokens if they are
# expired.
def c2_open(user):
    r = Rower.objects.get(user=user)
    if (r.c2token == '') or (r.c2token is None):
        s = "Token doesn't exist. Need to authorize"
        raise NoTokenError("User has no token")
    else:
        if (timezone.now()>r.tokenexpirydate):
            res = rower_c2_token_refresh(user)
            if res == None:
                raise NoTokenError("User has no token")
            if res[0] != None:
                thetoken = res[0]
            else:
                raise NoTokenError("User has no token")
        else:
            thetoken = r.c2token

    return thetoken

def add_stroke_data(user,c2id,workoutid,startdatetime,csvfilename,
                    workouttype='rower'):
    r = Rower.objects.get(user=user)
    if (r.c2token == '') or (r.c2token is None):
        return custom_exception_handler(401,s)
        s = "Token doesn't exist. Need to authorize"
    elif (timezone.now()>r.tokenexpirydate):
        s = "Token expired. Needs to refresh."
        return custom_exception_handler(401,s)
    else:
        starttimeunix = arrow.get(startdatetime).timestamp

        job = myqueue(queue,
                      handle_c2_import_stroke_data,
                      r.c2token,
                      c2id,
                      workoutid,
                      starttimeunix,
                      csvfilename,workouttype=workouttype)

    return 1

def get_c2_workouts(rower):

    if not ispromember(rower.user):
        return 0

    try:
        thetoken = c2_open(rower.user)
    except NoTokenError:
        return 0

    res = get_c2_workout_list(rower.user,page=1)

    if (res.status_code != 200):
        return 0
    else:
        c2ids = [item['id'] for item in res.json()['data']]
        alldata = {}
        for item in res.json()['data']:
            alldata[item['id']] = item

        knownc2ids = [
            w.uploadedtoc2 for w in Workout.objects.filter(user=rower)
        ]

        tombstones = [
            t.uploadedtoc2 for t in TombStone.objects.filter(user=rower)
        ]

        knownc2ids = uniqify(knownc2ids+tombstones)

        newids = [c2id for c2id in c2ids if not c2id in knownc2ids]

        for c2id in newids:
            workoutid = create_async_workout(alldata,
                                             rower.user,c2id)

    return 1

# get workout metrics, then relay stroke data to an asynchronous task
def create_async_workout(alldata,user,c2id):
    data = alldata[c2id]
    splitdata = None

    distance = data['distance']
    c2id = data['id']
    workouttype = data['type']
    verified = data['verified']
    startdatetime = iso8601.parse_date(data['date'])
    weightclass = data['weight_class']
    weightcategory = 'hwt'
    if weightclass == "L":
        weightcategory = 'lwt'

    # Create CSV file name and save data to CSV file
    csvfilename ='media/Import_'+str(c2id)+'.csv.gz'

    totaltime = data['time']/10.
    duration = dataprep.totaltime_sec_to_string(totaltime)

    try:
        timezone_str = tz(data['timezone'])
    except:
        timezone_str = 'UTC'

    workoutdate = startdatetime.astimezone(
        pytz.timezone(timezone_str)
    ).strftime('%Y-%m-%d')
    starttime = startdatetime.astimezone(
        pytz.timezone(timezone_str)
    ).strftime('%H:%M:%S')

    r = Rower.objects.get(user=user)


    w = Workout(
        user=r,
        workouttype = workouttype,
        name = 'C2 Import Workout from {startdatetime}'.format(startdatetime=startdatetime),
        date = workoutdate,
        starttime = starttime,
        startdatetime = startdatetime,
        timezone = timezone_str,
        duration = duration,
        distance=distance,
        weightcategory = weightcategory,
        uploadedtoc2 = c2id,
        csvfilename = csvfilename,
        notes = 'imported from Concept2 log'
    )

    w.save()

    # Check if workout has stroke data, and get the stroke data

    result = add_stroke_data(user,c2id,w.id,startdatetime,csvfilename,
                             workouttype = w.workouttype)

    return w.id

# convert datetime object to seconds
def makeseconds(t):
    seconds = t.hour*3600.+t.minute*60.+t.second+0.1*int(t.microsecond/1.e5)
    return seconds

# convert our weight class code to Concept2 weight class code
def c2wc(weightclass):
    if (weightclass=="lwt"):
        res = "L"
    else:
        res = "H"

    return res

# Concept2 logbook sends over split data for each interval
# We use it here to generate a custom summary
# Some users complained about small differences
def summaryfromsplitdata(splitdata,data,filename,sep='|'):

    totaldist = data['distance']
    totaltime = data['time']/10.
    try:
        spm = data['stroke_rate']
    except KeyError:
        spm = 0
    try:
        resttime = data['rest_time']/10.
    except KeyError:
        resttime = 0
    try:
        restdistance = data['rest_distance']
    except KeyError:
        restdistance = 0
    try:
        avghr = data['heart_rate']['average']
    except KeyError:
        avghr = 0
    try:
        maxhr = data['heart_rate']['max']
    except KeyError:
        maxhr = 0

    try:
        avgpace = 500.*totaltime/totaldist
    except (ZeroDivisionError,OverflowError):
        avgpace = 0.

    try:
        restpace = 500.*resttime/restdistance
    except (ZeroDivisionError,OverflowError):
        restpace = 0.

    velo = totaldist/totaltime
    avgpower = 2.8*velo**(3.0)

    try:
        restvelo = restdistance/resttime
    except (ZeroDivisionError,OverflowError):
        restvelo = 0

    restpower = 2.8*restvelo**(3.0)

    try:
        avgdps = totaldist/data['stroke_count']
    except (ZeroDivisionError,OverflowError,KeyError):
        avgdps = 0

    from rowingdata import summarystring,workstring,interval_string


    sums = summarystring(totaldist,totaltime,avgpace,spm,avghr,maxhr,
                         avgdps,avgpower,readFile=filename,
                         separator=sep)

    sums += workstring(totaldist,totaltime,avgpace,spm,avghr,maxhr,
                       avgdps,avgpower,separator=sep,symbol='W')

    sums += workstring(restdistance,resttime,restpace,0,0,0,0,restpower,
                       separator=sep,
                       symbol='R')

    sums += '\nWorkout Details\n'
    sums += '#-{sep}SDist{sep}-Split-{sep}-SPace-{sep}-Pwr-{sep}SPM-{sep}AvgHR{sep}MaxHR{sep}DPS-\n'.format(
        sep=sep
        )

    intervalnr=0
    sa = []
    results = []

    try:
        timebased = data['workout_type'] in ['FixedTimeSplits','FixedTimeInterval']
    except KeyError:
        timebased = False

    for interval in splitdata:
        try:
            idist = interval['distance']
        except KeyError:
            idist = 0

        try:
            itime = interval['time']/10.
        except KeyError:
            itime = 0
        try:
            ipace = 500.*itime/idist
        except (ZeroDivisionError,OverflowError):
            ipace = 180.

        try:
            ispm = interval['stroke_rate']
        except KeyError:
            ispm = 0
        try:
            irest_time = interval['rest_time']/10.
        except KeyError:
            irest_time = 0
        try:
            iavghr = interval['heart_rate']['average']
        except KeyError:
            iavghr = 0
        try:
            imaxhr = interval['heart_rate']['average']
        except KeyError:
            imaxhr = 0

        # create interval values
        iarr = [idist,'meters','work']
        resarr = [itime]
        if timebased:
            iarr = [itime,'seconds','work']
            resarr = [idist]

        if irest_time > 0:
            iarr += [irest_time,'seconds','rest']
            try:
                resarr += [interval['rest_distance']]
            except KeyError:
                resarr += [np.nan]

        sa += iarr
        results += resarr

        if itime != 0:
            ivelo = idist/itime
            ipower = 2.8*ivelo**(3.0)
        else:
            ivelo = 0
            ipower = 0

        sums += interval_string(intervalnr,idist,itime,ipace,ispm,
                                iavghr,imaxhr,0,ipower,separator=sep)
        intervalnr+=1

    return sums,sa,results

# Not used now. Could be used to add workout split data to Concept2
# logbook but needs to be reviewed.
def createc2workoutdata_as_splits(w):
    filename = w.csvfilename
    row = rowingdata(csvfile=filename)

    # resize per minute
    df = row.df.groupby(lambda x:x/60).mean()

    averagehr = int(df[' HRCur (bpm)'].mean())
    maxhr = int(df[' HRCur (bpm)'].max())

    # adding diff, trying to see if this is valid
    t = 10*df.loc[:,' ElapsedTime (sec)'].diff().values
    t[0] = t[1]
    d = df.loc[:,' Horizontal (meters)'].diff().values
    d[0] = d[1]
    p = 10*df.loc[:,' Stroke500mPace (sec/500m)'].values
    t = t.astype(int)
    d = d.astype(int)
    p = p.astype(int)
    spm = df[' Cadence (stokes/min)'].astype(int)
    spm[0] = spm[1]
    hr = df[' HRCur (bpm)'].astype(int)
    split_data = []
    for i in range(len(t)):
        thisrecord = {"time":t[i],"distance":d[i],"stroke_rate":spm[i],
                      "heart_rate":{
                          "average:":hr[i]
                          }
                      }
        split_data.append(thisrecord)

    try:
        durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f")
    except ValueError:
        durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S")

    try:
        newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
    except TypeError:
        newnotes = 'from '+w.workoutsource+' via rowsandall.com'

    wtype = w.workouttype
    if wtype in otwtypes:
        wtype = 'water'

    data = {
        "type": wtype,
        "date": w.startdatetime.isoformat(),
        "distance": int(w.distance),
        "time": int(10*makeseconds(durationstr)),
        "timezone": w.timezone,
        "weight_class": c2wc(w.weightcategory),
        "comments": newnotes,
        "heart_rate": {
            "average": averagehr,
            "max": maxhr,
            },
        "splits": split_data,
        }


    return data

# Create the Data object for the stroke data to be sent to Concept2 logbook
# API
def createc2workoutdata(w):
    filename = w.csvfilename
    try:
        row = rowingdata(csvfile=filename)
    except IOError:
        return 0

    try:
        averagehr = int(row.df[' HRCur (bpm)'].mean())
        maxhr = int(row.df[' HRCur (bpm)'].max())
    except ValueError:
        averagehr = 0
        maxhr = 0

    # Calculate intervalstats
    itime, idist, itype = row.intervalstats_values()
    lapnames = row.df[' lapIdx'].unique()
    nrintervals = len(itime)
    if len(lapnames != nrintervals):
        newlapnames = []
        for name in lapnames:
            newlapnames += [name,name]
        lapnames = newlapnames
    intervaldata = []
    for i in range(nrintervals):
        if itime[i]>0:
            mask = (row.df[' lapIdx'] == lapnames[i]) & (row.df[' WorkoutState'] == itype[i])
            spmav = int(row.df[' Cadence (stokes/min)'][mask].mean().astype(int))
            hrav = int(row.df[' HRCur (bpm)'][mask].mean().astype(int))
            intervaldict = {
            'type': 'distance',
            'time': int(10*itime[i]),
            'distance': int(idist[i]),
            'heart_rate': {
               'average':hrav,
                          },
            'stroke_rate': spmav,
            }
            intervaldata.append(intervaldict)

    # adding diff, trying to see if this is valid
    t = 10*row.df.loc[:,'TimeStamp (sec)'].values-10*row.df.loc[:,'TimeStamp (sec)'].iloc[0]
    try:
        t[0] = t[1]
    except IndexError:
        pass

    d = 10*row.df.loc[:,' Horizontal (meters)'].values
    try:
        d[0] = d[1]
    except IndexError:
        pass

    p = abs(10*row.df.loc[:,' Stroke500mPace (sec/500m)'].values)
    p = np.clip(p,0,3600)
    if w.workouttype == 'bike':
        p = 2.0*p

    t = t.astype(int)
    d = d.astype(int)
    p = p.astype(int)
    spm = row.df[' Cadence (stokes/min)'].astype(int)

    try:
        spm[0] = spm[1]
    except (KeyError,IndexError):
        spm = 0*t
    try:
        hr = row.df[' HRCur (bpm)'].astype(int)
    except ValueError:
        hr = 0*d
    stroke_data = []

    t = t.tolist()
    d = d.tolist()
    p = p.tolist()
    spm = spm.tolist()
    hr = hr.tolist()

    for i in range(len(t)):
        thisrecord = {"t":t[i],
                      "d":d[i],
                      "p":p[i],
                      "spm":spm[i],
                      "hr":hr[i]}
        stroke_data.append(thisrecord)

    try:
        durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f")
    except ValueError:
        durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S")

    workouttype = w.workouttype
    if workouttype in otwtypes:
        workouttype = 'water'

    try:
        startdatetime = w.startdatetime.isoformat()
    except AttributeError:
        startdate = datetime.datetime.combine(w.date,datetime.time())

    data = {
        "type": mytypes.c2mapping[workouttype],
        "date": w.startdatetime.isoformat(),
        "stroke_count": int(row.stroke_count),
        "timezone": w.timezone,
        "distance": int(w.distance),
        "time": int(10*makeseconds(durationstr)),
        "weight_class": c2wc(w.weightcategory),
        "comments": w.notes,
        "stroke_count": int(row.stroke_count),
        'stroke_rate': int(row.df[' Cadence (stokes/min)'].mean()),
        'drag_factor': int(row.dragfactor),
        "heart_rate": {
            "average": averagehr,
            "max": maxhr,
            },
        "stroke_data": stroke_data,
        'workout': {
            'splits': intervaldata,
            }
        }

    return data

# Refresh Concept2 authorization token
def do_refresh_token(refreshtoken):
    scope = "results:write,user:read"
    client_auth = requests.auth.HTTPBasicAuth(C2_CLIENT_ID, C2_CLIENT_SECRET)
    post_data = {"grant_type": "refresh_token",
                 "client_secret": C2_CLIENT_SECRET,
                 "client_id":C2_CLIENT_ID,
                 "refresh_token": refreshtoken,
                 }
    headers = {'user-agent': 'sanderroosendaal'}
    url = "https://log.concept2.com/oauth/access_token"
    s = Session()
    req = Request('POST',url, data=post_data, headers=headers)

    prepped = req.prepare()
    prepped.body+="&scope="
    prepped.body+=scope

    response = s.send(prepped)

    try:
        token_json = response.json()
    except JSONDecodeError:
        return [None,None,None]

    try:
        thetoken = token_json['access_token']
        expires_in = token_json['expires_in']
        refresh_token = token_json['refresh_token']
    except:
        with open("media/c2errors.log","a") as errorlog:
            errorstring = str(sys.exc_info()[0])
            timestr = time.strftime("%Y%m%d-%H%M%S")
            errorlog.write(timestr+errorstring+"\r\n")
            errorlog.write(str(token_json)+"\r\n")
        thetoken = None
        expires_in = None
        refresh_token = None

    return [thetoken,expires_in,refresh_token]

# Exchange authorization code for authorization token
def get_token(code):
    messg=''
    scope = "user:read,results:write"
    client_auth = requests.auth.HTTPBasicAuth(C2_CLIENT_ID, C2_CLIENT_SECRET)
    post_data = {"grant_type": "authorization_code",
                 "code": code,
                 "redirect_uri": C2_REDIRECT_URI,
                 "client_secret": C2_CLIENT_SECRET,
                 "client_id":C2_CLIENT_ID,
                 }
    headers = {'user-agent': 'sanderroosendaal'}
    url = "https://log.concept2.com/oauth/access_token"
    s = Session()
    req = Request('POST',url, data=post_data, headers=headers)

    prepped = req.prepare()
    prepped.body+="&scope="
    prepped.body+=scope

    response = s.send(prepped)

    token_json = response.json()

    try:
        status_code = response.status_code
        # status_code = token_json['status_code']
    except AttributeError:
    # except KeyError:
        return (0,response.text)
        try:
            status_code = token_json.status_code
        except AttributeError:
            return (0,'Attribute Error on c2_get_token')

    if status_code == 200:
        thetoken = token_json['access_token']
        expires_in = token_json['expires_in']
        refresh_token = token_json['refresh_token']
    else:
        return (0,token_json['message'])

    return (thetoken,expires_in,refresh_token,messg)

# Make URL for authorization and load it
def make_authorization_url(request):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks
    from uuid import uuid4
    state = str(uuid4())
    scope = "user:read,results:write"

    params = {"client_id": C2_CLIENT_ID,
              "response_type": "code",
              "redirect_uri": C2_REDIRECT_URI}
    url = "https://log.concept2.com/oauth/authorize?"+ urllib.parse.urlencode(params)
    url += "&scope="+scope

    return HttpResponseRedirect(url)

# Get workout from C2 ID
def get_workout(user,c2id):
    r = Rower.objects.get(user=user)
    if (r.c2token == '') or (r.c2token is None):
        s = "Token doesn't exist. Need to authorize"
        return custom_exception_handler(401,s)  ,0
    elif (timezone.now()>r.tokenexpirydate):
        s = "Token expired. Needs to refresh."
        return custom_exception_handler(401,s),0
    else:
        # ready to fetch. Hurray
        authorizationstring = str('Bearer ' + r.c2token)
        headers = {'Authorization': authorizationstring,
                   'user-agent': 'sanderroosendaal',
                   'Content-Type': 'application/json'}
        url = "https://log.concept2.com/api/users/me/results/"+str(c2id)
        s = requests.get(url,headers=headers)

        if s.status_code != 200:
            if s.status_code == 404:
                raise PermissionDenied("You have no access to this resource")
            else:
                s = "Something went wrong with the import"
                return custom_exception_handler(401,s), 0

    data = s.json()['data']
    splitdata = None

    if 'workout' in data:
        if 'splits' in data['workout']:
            splitdata = data['workout']['splits']
        elif 'intervals' in data['workout']:
            splitdata = data['workout']['intervals']
        else:
            splitdata = None

    # Check if workout has stroke data, and get the stroke data

    if data['stroke_data']:
        res2 = get_c2_workout_strokes(user,c2id)
        if res2.status_code == 200:
            strokedata = pd.DataFrame.from_dict(res2.json()['data'])
        else:
            strokedata = pd.DataFrame()
    else:
        strokedata = pd.DataFrame()

    return data,strokedata

# Get stroke data belonging to C2 ID
def get_c2_workout_strokes(user,c2id):
    r = Rower.objects.get(user=user)
    if (r.c2token == '') or (r.c2token is None):
        return custom_exception_handler(401,s)
        s = "Token doesn't exist. Need to authorize"
    elif (timezone.now()>r.tokenexpirydate):
        s = "Token expired. Needs to refresh."
        return custom_exception_handler(401,s)
    else:
        # ready to fetch. Hurray
        authorizationstring = str('Bearer ' + r.c2token)
        headers = {'Authorization': authorizationstring,
                   'user-agent': 'sanderroosendaal',
                   'Content-Type': 'application/json'}
        url = "https://log.concept2.com/api/users/me/results/"+str(c2id)+"/strokes"
        s = requests.get(url,headers=headers)

    return s

# Get list of C2 workouts. We load only the first page,
# assuming that users don't want to import their old workouts
def get_c2_workout_list(user,page=1):
    r = Rower.objects.get(user=user)
    if (r.c2token == '') or (r.c2token is None):
        s = "Token doesn't exist. Need to authorize"
        return custom_exception_handler(401,s)
    elif (timezone.now()>r.tokenexpirydate):
        s = "Token expired. Needs to refresh."
        return custom_exception_handler(401,s)
    else:
        # ready to fetch. Hurray
        authorizationstring = str('Bearer ' + r.c2token)
        headers = {'Authorization': authorizationstring,
                   'user-agent': 'sanderroosendaal',
                   'Content-Type': 'application/json'}
        url = "https://log.concept2.com/api/users/me/results"
        url += "?page={page}".format(page=page)

        s = requests.get(url,headers=headers)

    return s


# Get username, having access token.
# Handy for checking if the API access is working
def get_username(access_token):
    authorizationstring = str('Bearer ' + access_token)
    headers = {'Authorization': authorizationstring,
               'user-agent': 'sanderroosendaal',
               'Content-Type': 'application/json'}
    import urllib
    url = "https://log.concept2.com/api/users/me"
    response = requests.get(url,headers=headers)


    me_json = response.json()

    try:
        res =  me_json['data']['username']
        id = me_json['data']['id']
    except KeyError:
        res = None

    return res

# Get user id, having access token
# Handy for checking if the API access is working
def get_userid(access_token):
    authorizationstring = str('Bearer ' + access_token)
    headers = {'Authorization': authorizationstring,
               'user-agent': 'sanderroosendaal',
               'Content-Type': 'application/json'}
    import urllib
    url = "https://log.concept2.com/api/users/me"
    try:
        response = requests.get(url,headers=headers)
    except:
        return 0


    try:
        me_json = response.json()
    except JSONDecodeError:
        return 0
    try:
        res = me_json['data']['id']
    except KeyError:
        res = 0

    return res

# For debugging purposes
def process_callback(request):
    # need error handling

    code = request.GET['code']

    access_token = get_token(code)

    username,id = get_username(access_token)

    return HttpResponse("got a user name: %s" % username)

def default(o):
    if isinstance(o, numpy.int64): return int(o)
    raise TypeError

# Uploading workout
def workout_c2_upload(user,w,asynchron=False):
    message = 'trying C2 upload'
    try:
        if mytypes.c2mapping[w.workouttype] is None:
            return "This workout type cannot be uploaded to Concept2",0
    except KeyError:
        return "This workout type cannot be uploaded to Concept2",0

    thetoken = c2_open(user)

    r = Rower.objects.get(user=user)

    # ready to upload. Hurray
    if (is_workout_user(user,w)):
        c2userid = get_userid(r.c2token)
        if not c2userid:
            raise NoTokenError("User has no token")

        data = createc2workoutdata(w)

        if data == 0:
            return "Error: No data file. Contact info@rowsandall.com if the problem persists",0

        authorizationstring = str('Bearer ' + r.c2token)
        headers = {'Authorization': authorizationstring,
                   'user-agent': 'sanderroosendaal',
                   'Content-Type': 'application/json'}
        import urllib
        url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
        if not asynchron:
            response = requests.post(url,headers=headers,data=json.dumps(data,default=default))


            if (response.status_code == 409 ):
                message = "Concept2 Duplicate error"
                w.uploadedtoc2 = -1
                c2id = -1
                w.save()
            elif (response.status_code == 201 or response.status_code == 200):
                #               s= json.loads(response.text)
                s = response.json()
                c2id = s['data']['id']
                w.uploadedtoc2 = c2id
                w.save()
                message = "Upload to Concept2 was successful"
            else:
                message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text
                c2id = 0
        else:
            job = myqueue(queue,
                          handle_c2_sync,
                          w.id,
                          url,
                          headers,
                          json.dumps(data,default=default))
            c2id = 0

    return message,c2id

# This is token refresh. Looks for tokens in our database, then refreshes
def rower_c2_token_refresh(user):
    r = Rower.objects.get(user=user)
    res = do_refresh_token(r.c2refreshtoken)
    if res[0]:
        access_token = res[0]
        expires_in = res[1]
        refresh_token = res[2]
        expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)

        r = Rower.objects.get(user=user)
        r.c2token = access_token
        r.tokenexpirydate = expirydatetime
        r.c2refreshtoken = refresh_token

        r.save()
        return r.c2token
    else:
        return None

# Create workout data from Strava or Concept2
# data and create the associated Workout object and save it
def add_workout_from_data(user,importid,data,strokedata,
                          source='c2',splitdata=None,
                          workoutsource='concept2'):
    try:
        workouttype = mytypes.c2mappinginv[data['type']]
    except KeyError:
        workouttype = 'rower'

    if workouttype not in [x[0] for x in Workout.workouttypes]:
        workouttype = 'other'
    try:
        comments = data['comments']
    except:
        comments = ' '

    try:
        thetimezone = tz(data['timezone'])
    except:
        thetimezone = 'UTC'

    r = Rower.objects.get(user=user)
    try:
        rowdatetime = iso8601.parse_date(data['date_utc'])
    except KeyError:
        rowdatetime = iso8601.parse_date(data['start_date'])
    except ParseError:
        rowdatetime = iso8601.parse_date(data['date'])


    try:
        c2intervaltype = data['workout_type']

    except KeyError:
        c2intervaltype = ''

    try:
        title = data['name']
    except KeyError:
        title = ""
        try:
            t = data['comments'].split('\n', 1)[0]
            title += t[:20]
        except:
            title = 'Imported'

    starttimeunix = arrow.get(rowdatetime).timestamp

    res = make_cumvalues(0.1*strokedata['t'])
    cum_time = res[0]
    lapidx = res[1]

    unixtime = cum_time+starttimeunix
    # unixtime[0] = starttimeunix
    seconds = 0.1*strokedata.loc[:,'t']

    nr_rows = len(unixtime)

    try:
        latcoord = strokedata.loc[:,'lat']
        loncoord = strokedata.loc[:,'lon']
    except:
        latcoord = np.zeros(nr_rows)
        loncoord = np.zeros(nr_rows)


    try:
        strokelength = strokedata.loc[:,'strokelength']
    except:
        strokelength = np.zeros(nr_rows)

    dist2 = 0.1*strokedata.loc[:,'d']

    try:
        spm = strokedata.loc[:,'spm']
    except KeyError:
        spm = 0*dist2

    try:
        hr = strokedata.loc[:,'hr']
    except KeyError:
        hr = 0*spm
    pace = strokedata.loc[:,'p']/10.
    pace = np.clip(pace,0,1e4)
    pace = pace.replace(0,300)

    velo = 500./pace
    power = 2.8*velo**3
    if workouttype == 'bike':
        velo = 1000./pace
        pace = 500./velo


    # save csv
    # Create data frame with all necessary data to write to csv
    df = pd.DataFrame({'TimeStamp (sec)':unixtime,
                       ' Horizontal (meters)': dist2,
                       ' Cadence (stokes/min)':spm,
                       ' HRCur (bpm)':hr,
                       ' longitude':loncoord,
                       ' latitude':latcoord,
                       ' Stroke500mPace (sec/500m)':pace,
                       ' Power (watts)':power,
                       ' DragFactor':np.zeros(nr_rows),
                       ' DriveLength (meters)':np.zeros(nr_rows),
                       ' StrokeDistance (meters)':strokelength,
                       ' DriveTime (ms)':np.zeros(nr_rows),
                       ' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
                       ' AverageDriveForce (lbs)':np.zeros(nr_rows),
                       ' PeakDriveForce (lbs)':np.zeros(nr_rows),
                       ' lapIdx':lapidx,
                       ' WorkoutState': 4,
                       ' ElapsedTime (sec)':seconds
                       })


    df.sort_values(by='TimeStamp (sec)',ascending=True)

    timestr = strftime("%Y%m%d-%H%M%S")


    # Create CSV file name and save data to CSV file
    csvfilename ='media/{code}_{importid}.csv'.format(
        importid=importid,
        code = uuid4().hex[:16]
        )

    res =  df.to_csv(csvfilename+'.gz',index_label='index',
                     compression='gzip')


    # with Concept2
    if source=='c2':
        try:
            totaldist = data['distance']
            totaltime = data['time']/10.
        except KeyError:
            totaldist = 0
            totaltime = 0
    else:
        totaldist = 0
        totaltime = 0

    id,message = dataprep.save_workout_database(
        csvfilename,r,
        workouttype=workouttype,
        title=title,notes=comments,
        workoutsource=workoutsource,
        dosummary=True,dosmooth=False,
    )

    w = Workout.objects.get(id=id)
    w.duration = dataprep.totaltime_sec_to_string(totaltime)
    w.distance = totaldist
    w.save()


    return id,message
