
import time
import colorsys
import timestring
import zipfile
import bleach
import arrow
import pytz
import operator
import warnings
import urllib
import yaml
from PIL import Image
from numbers import Number
from django.views.generic.base import TemplateView
from django.contrib.auth import views as auth_views
from django.db.models import Q
from django import template
from django.db import IntegrityError, transaction
from django.views.decorators.csrf import csrf_exempt
from matplotlib.backends.backend_agg import FigureCanvas
import gc
from pyparsing import ParseException
from uuid import uuid4
import codecs
import isodate

from django.shortcuts import render
from django.http import (
    HttpResponse, HttpResponseRedirect,
    HttpResponseForbidden, HttpResponseNotAllowed,
    HttpResponseNotFound,Http404
    )
from django.contrib.auth import authenticate, login, logout
from rowers.forms import (
    LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm,
    TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
    WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
    LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm,
    PlannedSessionTeamForm,PlannedSessionTeamMemberForm,
    VirtualRaceSelectForm,WorkoutRaceSelectForm,CourseSelectForm,
    RaceResultFilterForm,PowerIntervalUpdateForm
    )
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
from django.template import RequestContext
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.conf import settings
from django.utils.datastructures import MultiValueDictKeyError
from django.utils import timezone,translation
from django.core.mail import send_mail, BadHeaderError
from rowers.forms import (
    SummaryStringForm,IntervalUpdateForm,StrokeDataForm,
    StatsOptionsForm,PredictedPieceForm,DateRangeForm,DeltaDaysForm,
    FitnessMetricForm,
    EmailForm, RegistrationForm, RegistrationFormTermsOfService,
    RegistrationFormUniqueEmail,RegistrationFormSex,
    CNsummaryForm,UpdateWindForm,
    UpdateStreamForm,WorkoutMultipleCompareForm,ChartParamChoiceForm,
    FusionMetricChoiceForm,BoxPlotChoiceForm,MultiFlexChoiceForm,
    TrendFlexModalForm,WorkoutSplitForm,WorkoutJoinParamForm,
    PlannedSessionMultipleCloneForm,SessionDateShiftForm,
    )
from rowers.models import (
    Workout, User, Rower, WorkoutForm,FavoriteChart,
    PlannedSession, DeactivateUserForm,DeleteUserForm
    )
from rowers.models import (
    RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
    RowerPowerZonesForm,AccountRowerForm,UserForm,StrokeData,
    Team,TeamForm,TeamInviteForm,TeamInvite,TeamRequest,
    WorkoutComment,WorkoutCommentForm,RowerExportForm,
    CalcAgePerformance,PowerTimeFitnessMetric,PlannedSessionForm,
    PlannedSessionFormSmall,GeoCourseEditForm,VirtualRace,
    VirtualRaceForm,VirtualRaceResultForm,RowerImportExportForm
    )
from rowers.models import (
    FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement,BasePlannedSessionFormSet
    )
from rowers.metrics import rowingmetrics,defaultfavoritecharts
from rowers import metrics
from rowers import courses
import rowers.uploads as uploads
from django.forms.formsets import formset_factory
from django.forms import modelformset_factory
import StringIO
from django.contrib.auth.decorators import login_required,user_passes_test
from time import strftime,strptime,mktime,time,daylight
import os,sys
import datetime
import iso8601
import c2stuff
from c2stuff import C2NoTokenError,c2_open
from runkeeperstuff import RunKeeperNoTokenError,runkeeper_open
from sporttracksstuff import SportTracksNoTokenError,sporttracks_open
from tpstuff import TPNoTokenError,tp_open
from iso8601 import ParseError
import stravastuff
import polarstuff
from polarstuff import PolarNoTokenError
from stravastuff import StravaNoTokenError
import sporttracksstuff
import underarmourstuff
from underarmourstuff import UnderArmourNoTokenError,underarmour_open
import tpstuff
import runkeeperstuff
import ownapistuff
from ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI
from rowsandall_app.settings import (
    C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
    STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
    POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET,
    SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI,
    SPORTTRACKS_CLIENT_SECRET,
    UNDERARMOUR_CLIENT_ID, UNDERARMOUR_REDIRECT_URI,
    UNDERARMOUR_CLIENT_SECRET,UNDERARMOUR_CLIENT_KEY,
    RUNKEEPER_CLIENT_ID,RUNKEEPER_REDIRECT_URI,RUNKEEPER_CLIENT_SECRET,
    TP_CLIENT_ID,TP_REDIRECT_URI,TP_CLIENT_KEY,TP_CLIENT_SECRET,
    )

from rowers.tasks_standalone import addcomment2
from django.contrib import messages
from async_messages import messages as a_messages

import requests
import json
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from rowers.rows import handle_uploaded_file,handle_uploaded_image
from rowers.plannedsessions import *
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
from rowers.tasks import (
    handle_sendemail_unrecognized,handle_sendemailnewcomment,
    handle_sendemailsummary,
    handle_sendemailkml,
    handle_sendemailnewresponse, handle_updatedps,
    handle_updatecp,long_test_task,long_test_task2,
    handle_zip_file,handle_getagegrouprecords,
    handle_updatefitnessmetric,
    handle_update_empower,
    handle_sendemail_userdeleted,
    )

from scipy.signal import savgol_filter
from django.shortcuts import render_to_response
from Cookie import SimpleCookie
from shutil import copyfile,move
import types
from rowingdata import rower as rrower
from rowingdata import main as rmain
from rowingdata import rowingdata as rrdata
from rowingdata import make_cumvalues
from rowingdata import summarydata
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from rowers.emails import send_template_email

from pytz import timezone as tz,utc
from timezonefinder import TimezoneFinder
import dateutil
import mpld3
from mpld3 import plugins
import stravalib
from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
from weather import get_wind_data,get_airport_code,get_metar_data

from oauth2_provider.models import Application,Grant,AccessToken

import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')

import redis
import threading
from redis import StrictRedis,Redis
from rq.exceptions import NoSuchJobError
from rq.registry import StartedJobRegistry
from rq import Queue,cancel_job

from django.core.cache import cache
from django_mailbox.models import Message,Mailbox,MessageAttachment


# Utility to get stroke data in a JSON response
class JSONResponse(HttpResponse):
    def __init__(self, data, **kwargs):
        content = JSONRenderer().render(data)
        kwargs['content_type'] = 'application/json'
        super(JSONResponse, self).__init__(content, **kwargs)

def getrequestrower(request,rowerid=0,userid=0,notpermanent=False):

    if notpermanent == False:
        if rowerid == 0 and 'rowerid' in request.session:
            rowerid = request.session['rowerid']
            
        if userid != 0:
            rowerid = 0
        
    try:
        
        if rowerid != 0:
            r = Rower.objects.get(id=rowerid)
        elif userid != 0:
            u = User.objects.get(id=userid)
            r = getrower(u)
        else:
	    r = getrower(request.user)
            
    except Rower.DoesNotExist:
        raise Http404("Rower doesn't exist")

    if not checkaccessuser(request.user,r):
        raise PermissionDenied("You have no access to this user")

    if notpermanent == False:
        request.session['rowerid'] = r.id

    return r
    

def getrower(user):
    try:
        r = Rower.objects.get(user=user)
    except Rower.DoesNotExist:
        r = Rower(user=user)
        r.save()

    return r


def get_workout(id):
    try:
        w = Workout.objects.get(id=id)
    except Workout.DoesNotExist:
        raise Http404("Workout doesn't exist")

    return w

def get_workout_permitted(user,id):
    w = get_workout(id)
    
    if (checkworkoutuser(user,w)==False):
        raise PermissionDenied("Access denied")
    
    return w
        
def getvalue(data):
    perc = 0
    total = 1
    done = 0
    id = 0
    session_key = 'noot'
    for i in data.iteritems():
        if i[0] == 'total':
            total = float(i[1])
        if i[0] == 'done':
            done = float(i[1])
        if i[0] == 'id':
            id = i[1]
        if i[0] == 'session_key':
            session_key = i[1]

    return total,done,id,session_key

class SessionTaskListener(threading.Thread):
    def __init__(self, r, channels):
        threading.Thread.__init__(self)
        self.redis = r
        self.pubsub = self.redis.pubsub()
        self.pubsub.subscribe(channels)
    
    def work(self, item):

        try:
            data =  json.loads(item['data'])
            total,done,id,session_key = getvalue(data)
            perc = int(100.*done/total)
            cache.set(id,perc,3600)
            
        except TypeError:
            pass
            
    def run(self):
        for item in self.pubsub.listen():
            if item['data'] == "KILL":
                self.pubsub.unsubscribe()
                print self, "unsubscribed and finished"
                break
            else:
                self.work(item)


queuefailed = Queue("failed",connection=Redis())
redis_connection = StrictRedis()
r = Redis()

# this doesn't yet work on production
#if settings.DEBUG:
#    client = SessionTaskListener(r,['tasks'])
#    client.start()


rq_registry = StartedJobRegistry(queue.name,connection=redis_connection)
rq_registryhigh = StartedJobRegistry(queuehigh.name,connection=redis_connection)
rq_registrylow = StartedJobRegistry(queuelow.name,connection=redis_connection)

from rq.job import Job

from rest_framework_swagger.views import get_swagger_view
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from rowers.serializers import RowerSerializer,WorkoutSerializer
from rest_framework import status,permissions,generics
from rest_framework.decorators import api_view, renderer_classes

from permissions import IsOwnerOrNot

import plots
import mailprocessing

from io import BytesIO
from scipy.special import lambertw

from dataprep import timedeltaconv
from dataprep import getsmallrowdata_db

from scipy.interpolate import griddata

#LOCALTIMEZONE = tz('Etc/UTC')
USER_LANGUAGE = 'en-US'

from interactiveplots import *
from rowers.celery import result as celery_result

# Define the API documentation
schema_view = get_swagger_view(title='Rowsandall API')

def remove_asynctask(request,id):
    try:
        oldtasks = request.session['async_tasks']
    except KeyError:
        oldtasks = []
        
    newtasks = []
    for task in oldtasks:
        if id not in task[0]:
            newtasks += [(task[0],task[1])]

    request.session['async_tasks'] = newtasks
            
def get_job_result(jobid):
    if settings.DEBUG:
        result = celery_result.AsyncResult(jobid).result
    else:
        running_job_ids = rq_registry.get_job_ids()
        if len(running_job_ids) and jobid in running_job_ids:
            # job is running
            return None
        else:
            # job is ready
            try:
                job = Job.fetch(jobid,connection=redis_connection)
                result = job.result
            except NoSuchJobError:
                return None
                
    return result

verbose_job_status = {
    'updatecp': 'Critical Power Calculation for Ergometer Workouts',
    'updatecpwater': 'Critical Power Calculation for OTW Workouts',
    'otwsetpower': 'Rowing Physics OTW Power Calculation',
    'agegrouprecords': 'Calculate age group records',
    'make_plot': 'Create static chart',
    'long_test_task': 'Long Test Task',
    'long_test_task2': 'Long Test Task 2',
    'update_empower': 'Correct Empower Inflated Power Bug',
    'submit_race': 'Checking Race Course Result',
    }

def get_job_status(jobid):
    if settings.DEBUG:
        job = celery_result.AsyncResult(jobid)
        jobresult = job.result
        
        if 'fail' in job.status.lower():
            jobresult = '0'
        summary = {
            'status': job.status,
            'result': jobresult,
        }
    else:
        try:
            job = Job.fetch(jobid,connection=redis_connection)
            summary = {
                'status':job.status,
                'result':job.result,
            }
        except NoSuchJobError:
            summary = {
                'status': 'success',
                'result': 1,
            }

    try:
        if 'fail' in summary['status'].lower():
            summary['failed'] = True
        else:
            summary['failed'] = False

        if 'success' in summary['status'].lower():
            summary['finished'] = True
        elif 'finished' in summary['status'].lower():
            summary['finished'] = True
        else:
            summary['finished'] = False
    except AttributeError:
        summary = {
            'status': 'failed',
            'result': 0,
            'finished': True,
            'failed': True
            }

    return summary

def kill_async_job(request,id='aap'):
    if settings.DEBUG:
        job = celery_result.AsyncResult(id)
        job.revoke()
    else:
        try:
            cancel_job(id,connection=redis_connection)
        except NoSuchJobError:
            pass
            
    remove_asynctask(request,id)
    cache.delete(id)
    url = reverse(session_jobs_status)

    return HttpResponseRedirect(url)

@login_required()
def raise_500(request):
    if request.user.is_superuser:
        raise ValueError
    else:
        return HttpResponse("invalid")

@login_required()
def test_job_view(request,aantal=100):

    session_key = request.session._session_key

    job = myqueue(queuehigh,long_test_task,int(aantal),
                  session_key=session_key)


    try:
        request.session['async_tasks'] += [(job.id,'long_test_task')]
    except KeyError:
        request.session['async_tasks'] = [(job.id,'long_test_task')]     

    url = reverse(session_jobs_status)

    return HttpResponseRedirect(url)

@login_required()
def test_job_view2(request,aantal=100):


    job = myqueue(queuehigh,long_test_task2,int(aantal),
                  secret=settings.PROGRESS_CACHE_SECRET)


    try:
        request.session['async_tasks'] += [(job.id,'long_test_task2')]
    except KeyError:
        request.session['async_tasks'] = [(job.id,'long_test_task2')]     

    url = reverse(session_jobs_status)

    return HttpResponseRedirect(url)

@csrf_exempt
def post_progress(request,id=None,value=0):
    if request.method == 'POST':
        try:
            secret = request.POST['secret']
        except KeyError:
            return HttpResponse('Access Denied',status=401)
        if secret == settings.PROGRESS_CACHE_SECRET:
            if not id:
                try:
                    id = request.POST['id']
                except KeyError:
                    return HttpResponse('Invalid request',400)
            try:
                value = request.POST['value']
            except KeyError:
                pass

            cache.set(id,value,3600)
            # test
            result = cache.get(id)

            return HttpResponse('progress cached '+str(result),
                                status=201)
        else: # secret not given
            return HttpResponse('access denied',status=401)

    else: # request method is not POST
        return HttpResponse('GET method not allowed',status=405)
    
def get_all_queued_jobs(userid=0):
    r = StrictRedis()

    jobs = []

    celerykeys = r.keys('celery*')
    for key in celerykeys:
        id= key[17:]
        job = celery_result.AsyncResult(id)
        jobresult = job.result
        if 'fail' in job.status.lower():
            jobresult = '0'
        jobs.append(
            (id,{
                'status':job.status,
                'result':jobresult,
                'function':'',
                'meta':job.info,
                }))
    
    ids = [j.id for j in queue.jobs]
    ids += [j.id for j in queuehigh.jobs]
    ids += [j.id for j in queuelow.jobs]
    ids += [j.id for j in queuefailed.jobs]

    
    for id in ids:
        job = Job.fetch(id,connection=redis_connection)
        jobs.append(
            (id,{
                'status':job.get_status(),
                'result':job.result,
                'function':job.func_name,
                'meta':job.meta,
                }))

    return jobs

def get_stored_tasks_status(request):
    try:
        taskids = request.session['async_tasks']
    except KeyError:
        taskids = []

    taskstatus = []
    for id,func_name in reversed(taskids):
        progress = 0
        cached_progress = cache.get(id)
        finished = get_job_status(id)['finished']
        if finished:
            cache.set(id,100)
            progress = 100
        elif cached_progress>0:
            progress = cached_progress
        else:
            progress = 0

        this_task_status = {
            'id':id,
            'status':get_job_status(id)['status'],
            'failed':get_job_status(id)['failed'],
            'finished':get_job_status(id)['finished'],
            'func_name':func_name,
            'verbose': verbose_job_status[func_name],
            'progress': progress,
        }

        taskstatus.append(this_task_status)

    
    return taskstatus

@login_required()
def get_thumbnails(request,id):
    row = get_workout_permitted(request.user,id)

    
    r = getrower(request.user)
    result = request.user.is_authenticated() and ispromember(request.user)
    if result:
	promember=1
    if request.user == row.user.user:
	mayedit=1

    comments = WorkoutComment.objects.filter(workout=row)

    aantalcomments = len(comments)

    workouttype = 'ote'
    if row.workouttype in types.otwtypes:
        workouttype = 'otw'

    try:
        favorites = FavoriteChart.objects.filter(user=r,
                                           workouttype__in=[workouttype,'both']).order_by("id")
        maxfav = len(favorites)-1
    except:
        favorites = None
        maxfav = 0

    charts = []
    
    charts = thumbnails_set(r,id,favorites)
    try:
        if charts[0]['script'] == '': 
            charts = []
    except IndexError:
        charts = []

        
    return JSONResponse(charts)

@login_required()
def deactivate_user(request):
    pk = request.user.id
    user = User.objects.get(pk=pk)
    user_form = DeactivateUserForm(instance=user)
    if request.user.is_authenticated() and request.user.id == user.id:
        if request.method == "POST":
            user_form = DeactivateUserForm(request.POST, instance=user)
            if user_form.is_valid():
                deactivate_user = user_form.save(commit=False)
                user.is_active = False
                deactivate_user.save()
                url = reverse(auth_views.logout_then_login)
                return HttpResponseRedirect(url)
        return render(request, "userprofile_deactivate.html", {
            "user_form": user_form,
        })
    else:
        raise PermissionDenied    

@login_required()
def user_gdpr_optin(request):
    r = getrower(request.user)
    r.gdproptin = False
    r.gdproptindate = None
    r.save()
    nexturl = request.GET.get('next','/rowers/list-workouts/')
    if r.gdproptin:
        return HttpResponseRedirect(nexturl)

    return render(request,'gdpr_optin.html',{
        "next": nexturl
        })

@login_required()
def user_gdpr_confirm(request):
    r = getrower(request.user)
    r.gdproptin = True
    r.gdproptindate = timezone.now()
    r.save()

    nexturl = request.GET.get('next','/rowers/list-workouts/')

    return HttpResponseRedirect(nexturl)
                  
        
    
@login_required()
def remove_user(request):
    pk = request.user.id
    user = User.objects.get(pk=pk)
    user_form = DeleteUserForm(instance=user)
    if request.user.is_authenticated() and request.user.id == user.id:
        if request.method == "POST":
            user_form = DeleteUserForm(request.POST,instance=user)
            if user_form.is_valid():
                cd = user_form.cleaned_data
                name = user.first_name+' '+user.last_name
                email = user.email

                
                if cd['delete_user']:
                    user.delete()
                    res = myqueue(queuehigh,
                                  handle_sendemail_userdeleted,
                                  name, email)

                    url = reverse(auth_views.logout_then_login)
                    return HttpResponseRedirect(url)
        return render(request, "userprofile_delete.html", {
            "user_form": user_form,
            })
    else:
        raise PermissionDenied
    

@login_required()
def get_testscript(request,id):
    row = get_workout_permitted(request.user,id)
    r = getrower(request.user)

    object = {
        "script":"""
<div id="id_script">
    <script>alert("hi")</script>
</div>
        """,
        "div":"""
<div id="id_div">
Hoi
</div>
"""
        }

        
    return JSONResponse([object,object])

@login_required()
def session_jobs_view(request):
    taskstatus = get_stored_tasks_status(request)

    return HttpResponse(json.dumps(taskstatus))

@login_required()
def session_jobs_status(request):
    taskstatus = get_stored_tasks_status(request)

    return render(request,
                  'async_tasks.html',
                  {'taskstatus':taskstatus})

# Test if row data include candidates
def rowhascoordinates(row):
    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)
    rowdata = rdata(f1)
    hascoordinates = 1
    if rowdata != 0:
        try:
            latitude = rowdata.df[' latitude']

            if not latitude.std():
                hascoordinates = 0
        except KeyError,AttributeError:
            hascoordinates = 0

    else:
        hascoordinates = 0

    return hascoordinates

# Custom error pages with Rowsandall headers
def error500_view(request):
    response = render_to_response('500.html', {},
				  context_instance = RequestContext(request))

    response.status_code = 500
    return response

def error404_view(request):
    response = render_to_response('404.html', {},
				  context_instance = RequestContext(request))

    response.status_code = 404
    return response

def error400_view(request):
    response = render_to_response('400.html', {},
				  context_instance = RequestContext(request))

    response.status_code = 400
    return response

def error403_view(request):
    response = render_to_response('403.html', {},
				  context_instance = RequestContext(request))

    response.status_code = 403
    return response

# Wrapper around the rowingdata call to catch some exceptions
# Checks for CSV file, then for gzipped CSV file, and if all fails, returns 0
def rdata(file,rower=rrower()):
    try:
	res = rrdata(csvfile=file,rower=rower)
    except IOError, IndexError:
        try:
            res = rrdata(csvfile=file+'.gz',rower=rower)
        except IOError, IndexError:
            res = 0

    return res

# Query to get teams managed and member of
def get_my_teams(user):
    try:
        therower = Rower.objects.get(user=user)
        teams1 = therower.team.all()
        teams2 = Team.objects.filter(manager=user)
        teams = list(set(teams1).union(set(teams2)))
    except TypeError:
        teams = []

    return teams

# Used for the interval editor - translates seconds to a time object
def get_time(second):
    if (second<=0) or (second>1e9):
	hours = 0
	minutes=0
	sec=0
	microsecond = 0
    elif math.isnan(second):
	hours = 0
	minutes=0
	sec=0
	microsecond = 0
    else:
	days = int(second/(24.*3600.)) % (24*3600)
	hours = int((second-24.*3600.*days)/3600.) % 24
	minutes = int((second-3600.*(hours+24.*days))/60.) % 60
	sec = int(second-3600.*(hours+24.*days)-60.*minutes) % 60
	microsecond = int(1.0e6*(second-3600.*(hours+24.*days)-60.*minutes-sec)) 
    return datetime.time(hours,minutes,sec,microsecond)

	
# get the workout ID from the SportTracks URI
def getidfromsturi(uri,length=8):
    return uri[len(uri)-length:]

def splituadata(lijst):
    t = []
    y = []
    for d in lijst:
        t.append(d[0])
        y.append(d[1])

    return np.array(t),np.array(y)

def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
    t = []
    lat = []
    lon = []
    for d in lijst:
        t.append(d[tname])
        lat.append(d[latname])
        lon.append(d[lonname])

    return [np.array(t),np.array(lat),np.array(lon)]

def splitrunkeeperdata(lijst,xname,yname):
    x = []
    y = []
    for d in lijst:
        x.append(d[xname])
        y.append(d[yname])

    return [np.array(x),np.array(y)]

# Splits SportTracks data which is one long sequence of
# [t,[lat,lon],t2,[lat2,lon2] ...]
# to [t,t2,t3, ...], [[lat,long],[lat2,long2],...
def splitstdata(lijst):
    t = []
    latlong = []
    while len(lijst)>=2:
	t.append(lijst[0])
	latlong.append(lijst[1])
	lijst = lijst[2:]

    return [np.array(t),np.array(latlong)]
	
from utils import (
    geo_distance,serialize_list,deserialize_list,uniqify,
    str2bool,range_to_color_hex,absolute,myqueue,get_call,
    calculate_age,rankingdistances,rankingdurations,
    is_ranking_piece,my_dict_from_instance,wavg
    )

import datautils

from rowers.models import checkworkoutuser,checkaccessuser

# Check if a user is a Coach member
def iscoachmember(user):
    if not user.is_anonymous():
        try:
            r = Rower.objects.get(user=user)
        except Rower.DoesNotExist:
            r = Rower(user=user)
            r.save()
            
        result = user.is_authenticated() and (r.rowerplan=='coach')
    else:
        result = False
        
    return result

# Check if a user can create planned sessions
def hasplannedsessions(user):
    if not user.is_anonymous():
        try:
            r = Rower.objects.get(user=user)
        except Rower.DoesNotExist:
            r = Rower(user=user)
            r.save()

        result = user.is_authenticated() and (r.rowerplan=='coach' or r.rowerplan=='plan')
        if not result and r.plantrialexpires:
            result = user.is_authenticaded() and r.rowerplan=='basic' and r.plantrialexpires >= datetime.date.today()
    else:
        result = False

    return result

from rowers.utils import isprorower

# Check if a user is a Pro member
def ispromember(user):
    if not user.is_anonymous():
        try:
            r = Rower.objects.get(user=user)
        except Rower.DoesNotExists:
            r = Rower(user=user)
            r.save()

        result = user.is_authenticated() and isprorower(r)
    else:
        result = False
    return result

# More User/Rower utils
def add_defaultfavorites(r):
    for c in defaultfavoritecharts:
        f = FavoriteChart(user=r,
                          yparam1=c['yparam1'],
                          yparam2=c['yparam2'],
                          xparam=c['xparam'],
                          plottype=c['plottype'],
                          workouttype=c['workouttype'],
                          reststrokes=c['reststrokes'],
                          notes=c['notes'])

        f.save()
    return 1


# User registration
def rower_register_view(request):
    if request.method == 'POST':
	#form = RegistrationFormUniqueEmail(request.POST)
	form = RegistrationFormSex(request.POST)
	if form.is_valid():
	    first_name = form.cleaned_data['first_name']
	    last_name = form.cleaned_data['last_name']
	    email = form.cleaned_data['email']
	    password = form.cleaned_data['password1']
	    username = form.cleaned_data['username']
            sex = form.cleaned_data['sex']
            birthdate = form.cleaned_data['birthdate']
            weightcategory = form.cleaned_data['weightcategory']
	    theuser = User.objects.create_user(username,password=password)
	    theuser.first_name = first_name
	    theuser.last_name = last_name
	    theuser.email = email
	    theuser.save()

	    therower = Rower(user=theuser,sex=sex,birthdate=birthdate,
                             weightcategory=weightcategory)

	    therower.save()

            # create default favorite charts
            add_defaultfavorites(therower)

            # Create Sample workout
            f = 'media/testdata.csv.gz'
            timestr = strftime("%Y%m%d-%H%M%S")
            f2 = f[:-7]+timestr+'.csv.gz'
            copyfile(f,f2)
                        
            response = dataprep.new_workout_from_file(therower,f2,
                                                      title='New User Sample Data',
                                                      notes='This is an example workout to get you started')
            newworkoutid = response[0]
            w = Workout.objects.get(id=newworkoutid)
            w.startdatetime = timezone.now()
            w.save()
            
            # Create and send email
	    fullemail = first_name + " " + last_name + " " + "<" + email + ">"
	    subject = "Thank you for registering on rowsandall.com"
            from_address = 'Sander Roosendaal <info@rowsandall.com>'

            d = {'first_name':theuser.first_name}
            
            send_template_email(from_address,[fullemail],
                                subject,'registeremail.html',d)
            

	    subject2 = "New User"
	    message2 = "New user registered.\n"
	    message2 += fullemail + "\n"
	    message2 += "User name: "+username

	    send_mail(subject2, message2,
		      'Rowsandall Server <info@rowsandall.com>',
		      ['roosendaalsander@gmail.com'])

	    return HttpResponseRedirect('/rowers/register/thankyou/')

	else:
	    return render(request,
			  "registration_form.html",
			  {'form':form})
    else:
	form =  RegistrationFormSex()
	return render(request,
		      "registration_form.html",
		      {'form':form,})

# Shows email form and sends it if submitted
def sendmail(request):
    if request.method == 'POST':
        form = EmailForm(request.POST)
        if form.is_valid():
	    firstname = form.cleaned_data['firstname']
	    lastname = form.cleaned_data['lastname']
	    email = form.cleaned_data['email']
	    subject = form.cleaned_data['subject']
	    botcheck = form.cleaned_data['botcheck'].lower()
	    message = form.cleaned_data['message']
	    if botcheck == 'yes':
		try:
		    fullemail = firstname + " " + lastname + " " + "<" + email + ">"
		    send_mail(subject, message, fullemail, ['info@rowsandall.com'])
		    return HttpResponseRedirect('/rowers/email/thankyou/')
		except:
		    return HttpResponseRedirect('/rowers/email/')
	    else:
                messages.error(request,'You have to answer YES to the question')
		return HttpResponseRedirect('/rowers/email/')
	else:
	    return HttpResponseRedirect('/rowers/email/')  
    else:
        return HttpResponseRedirect('/rowers/email/')

@login_required()
def start_trial_view(request):
    r = getrower(request.user)

    if r.protrialexpires is not None:
        messages.error(request,'You do not qualify for a trial')
        url = '/rowers/promembership'
        return HttpResponseRedirect(url)
    
    r.protrialexpires = datetime.date.today()+datetime.timedelta(13)
    r.save()

    url = reverse(workouts_view)

    messages.info(request,'We have started your 14 day trial period')
    
    subject2 = "User started Pro Trial"
    message2 = "User Started Pro Trial.\n"
    message2 += request.user.email + "\n"
    message2 += "User name: "+request.user.username
    
    send_mail(subject2, message2,
	      'Rowsandall Server <info@rowsandall.com>',
	      ['roosendaalsander@gmail.com'])
    
    return HttpResponseRedirect(url)

@login_required()
def start_plantrial_view(request):
    r = getrower(request.user)

    if r.plantrialexpires is not None:
        messages.error(request,'You do not qualify for a trial')
        url = '/rowers/promembership'
        return HttpResponseRedirect(url)
    
    r.plantrialexpires = datetime.date.today()+datetime.timedelta(13)
    r.protrialexpires = datetime.date.today()+datetime.timedelta(13)
    r.save()

    url = reverse(workouts_view)

    messages.info(request,'We have started your 14 day trial period')
    
    subject2 = "User started Plan Trial"
    message2 = "User Started Plan Trial.\n"
    message2 += request.user.email + "\n"
    message2 += "User name: "+request.user.username
    
    send_mail(subject2, message2,
	      'Rowsandall Server <info@rowsandall.com>',
	      ['roosendaalsander@gmail.com'])
    
    return HttpResponseRedirect(url)


# Create workout data from Strava or Concept2
# data and create the associated Workout object and save it
def add_workout_from_strokedata(user,importid,data,strokedata,
                                source='c2',splitdata=None,
                                workoutsource='concept2'):
    try:
        workouttype = 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 = ' '

#    comments = "Imported data \n %s" % comments
#    comments = "Imported data \n"+comments  # str(comments)
    try:
	thetimezone = tz(data['timezone'])
    except:
	thetimezone = 'UTC'

    r = getrower(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.ix[:,'t']

    nr_rows = len(unixtime)

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


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

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

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

    velo = 500./pace

    power = 2.8*velo**3
    
    # 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,
		       ' 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,
#        totaldist=totaldist,
#        totaltime=totaltime,
        workoutsource=workoutsource,
        dosummary=True
    )

            

    return id,message

# Create workout from RunKeeper Data
def add_workout_from_runkeeperdata(user,importid,data):
    # To Do - add utcoffset to time
    workouttype = data['type']
    if workouttype not in [x[0] for x in Workout.workouttypes]:
	workouttype = 'other'
    try:
	comments = data['notes']
    except:
	comments = ''
    
    try:
	utcoffset = tz(data['utcoffset'])
    except:
	utcoffset = 0

    r = getrower(user)

    try:
	rowdatetime = iso8601.parse_date(data['start_time'])
    except iso8601.ParseError:
	try:
	    rowdatetime = datetime.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
	    rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
	except:
	    try:
		rowdatetime = dateutil.parser.parse(data['start_time'])
		#rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
	    except:
		rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
		rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
    starttimeunix = arrow.get(rowdatetime).timestamp
    #starttimeunix = mktime(rowdatetime.utctimetuple())
    starttimeunix += utcoffset*3600
    
	
    try:
	title = data['name']
    except:
	title = "Imported data"



    res = splitrunkeeperdata(data['distance'],'timestamp','distance')

    distance = res[1]
    times_distance = res[0]

    try:
	l = data['path']
    
	res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude')
	times_location = res[0]
	latcoord = res[1]
	loncoord = res[2]

    except:
	times_location = times_distance
	latcoord = np.zeros(len(times_distance))
	loncoord = np.zeros(len(times_distance))
        if workouttype in types.otwtypes:
            workouttype = 'rower'
	
    try:
	res = splitrunkeeperdata(data['cadence'],'timestamp','cadence')
	times_spm = res[0]
	spm = res[1]
    except KeyError:
	times_spm = times_distance
	spm = 0*times_distance
    
    try:
	res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate')
	hr = res[1]
	times_hr = res[0]
    except KeyError:
	times_hr = times_distance
	hr = 0*times_distance


    # create data series and remove duplicates
    distseries = pd.Series(distance,index=times_distance)
    distseries = distseries.groupby(distseries.index).first()
    latseries = pd.Series(latcoord,index=times_location)
    try:
        latseries = latseries.groupby(latseries.index).first()
    except TypeError:
        latseries = 0.0*distseries
        
    lonseries = pd.Series(loncoord,index=times_location)
    try:
        lonseries = lonseries.groupby(lonseries.index).first()
    except TypeError:
        lonseries = 0.0*distseries
        
    spmseries = pd.Series(spm,index=times_spm)
    spmseries = spmseries.groupby(spmseries.index).first()
    hrseries = pd.Series(hr,index=times_hr)
    try:
        hrseries = hrseries.groupby(hrseries.index).first()
    except TypeError:
        hrseries = 0*distseries


    # Create dicts and big dataframe
    d = {
	' Horizontal (meters)': distseries,
	' latitude': latseries,
	' longitude': lonseries,
	' Cadence (stokes/min)': spmseries,
	' HRCur (bpm)' : hrseries,
	}

    

    df = pd.DataFrame(d)

    df = df.groupby(level=0).last()

    cum_time = df.index.values
    df[' ElapsedTime (sec)'] = cum_time

    velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff()
    
    df[' Power (watts)'] = 0.0*velo

    nr_rows = len(velo.values)

    df[' DriveLength (meters)'] = np.zeros(nr_rows)
    df[' StrokeDistance (meters)'] = np.zeros(nr_rows)
    df[' DriveTime (ms)'] = np.zeros(nr_rows)
    df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows)
    df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows)
    df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows)
    df[' lapIdx'] = np.zeros(nr_rows)



    unixtime = cum_time+starttimeunix
    unixtime[0] = starttimeunix
 
    df['TimeStamp (sec)'] = unixtime

 
    dt = np.diff(cum_time).mean()
    wsize = round(5./dt)

    # velo2 = stravastuff.ewmovingaverage(velo,wsize)

    # df[' Stroke500mPace (sec/500m)'] = 500./velo2


    df = df.fillna(0)

    df.sort_values(by='TimeStamp (sec)',ascending=True)
	
    timestr = strftime("%Y%m%d-%H%M%S")

#    csvfilename ='media/Import_'+str(importid)+'.csv'
    csvfilename ='media/{code}_{importid}.csv'.format(
        importid=importid,
        code = uuid4().hex[:16]
        )

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

    id,message = dataprep.save_workout_database(csvfilename,r,
                                                workouttype=workouttype,
                                                workoutsource='runkeeper',
                                                title=title,
                                                notes=comments)

    return (id,message)

    

# Create workout from SportTracks Data, which are slightly different
# than Strava or Concept2 data
def add_workout_from_stdata(user,importid,data):
    workouttype = data['type']
    if workouttype not in [x[0] for x in Workout.workouttypes]:
	workouttype = 'other'
    try:
	comments = data['comments']
    except:
	comments = ''

        
    r = getrower(user)
    try:
	rowdatetime = iso8601.parse_date(data['start_time'])
    except iso8601.ParseError:
	try:
	    rowdatetime = datetime.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
	    rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
	except:
	    try:
		rowdatetime = dateutil.parser.parse(data['start_time'])
		rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
	    except:
		rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
		rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
    starttimeunix = arrow.get(rowdatetime).timestamp

    try:
	title = data['name']
    except:
	title = "Imported data"

    try:
        res = splitstdata(data['distance'])
        distance = res[1]
        times_distance = res[0]
    except KeyError:
        try:
            res = splitstdata(data['heartrate'])
            times_distance = res[0]
            distance = 0*times_distance
        except KeyError:
            return (0,"No distance or heart rate data in the workout")


    try:
	l = data['location']
    
	res = splitstdata(l)
	times_location = res[0]
	latlong = res[1]
	latcoord = []
	loncoord = []

	for coord in latlong:
	    lat = coord[0]
	    lon = coord[1]
	    latcoord.append(lat)
	    loncoord.append(lon)
    except:
	times_location = times_distance
	latcoord = np.zeros(len(times_distance))
	loncoord = np.zeros(len(times_distance))
        if workouttype in types.otwtypes:
            workouttype = 'rower'
	
    try:
	res = splitstdata(data['cadence'])
	times_spm = res[0]
	spm = res[1]
    except KeyError:
	times_spm = times_distance
	spm = 0*times_distance
    
    try:
	res = splitstdata(data['heartrate'])
	hr = res[1]
	times_hr = res[0]
    except KeyError:
	times_hr = times_distance
	hr = 0*times_distance


    # create data series and remove duplicates
    distseries = pd.Series(distance,index=times_distance)
    distseries = distseries.groupby(distseries.index).first()
    latseries = pd.Series(latcoord,index=times_location)
    latseries = latseries.groupby(latseries.index).first()
    lonseries = pd.Series(loncoord,index=times_location)
    lonseries = lonseries.groupby(lonseries.index).first()
    spmseries = pd.Series(spm,index=times_spm)
    spmseries = spmseries.groupby(spmseries.index).first()
    hrseries = pd.Series(hr,index=times_hr)
    hrseries = hrseries.groupby(hrseries.index).first()


    # Create dicts and big dataframe
    d = {
	' Horizontal (meters)': distseries,
	' latitude': latseries,
	' longitude': lonseries,
	' Cadence (stokes/min)': spmseries,
	' HRCur (bpm)' : hrseries,
	}

    

    df = pd.DataFrame(d)

    df = df.groupby(level=0).last()

    cum_time = df.index.values
    df[' ElapsedTime (sec)'] = cum_time

    velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff()
    
    df[' Power (watts)'] = 0.0*velo

    nr_rows = len(velo.values)

    df[' DriveLength (meters)'] = np.zeros(nr_rows)
    df[' StrokeDistance (meters)'] = np.zeros(nr_rows)
    df[' DriveTime (ms)'] = np.zeros(nr_rows)
    df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows)
    df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows)
    df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows)
    df[' lapIdx'] = np.zeros(nr_rows)



    unixtime = cum_time+starttimeunix
    unixtime[0] = starttimeunix
 
    df['TimeStamp (sec)'] = unixtime

 
    dt = np.diff(cum_time).mean()
    wsize = round(5./dt)

    velo2 = stravastuff.ewmovingaverage(velo,wsize)

    df[' Stroke500mPace (sec/500m)'] = 500./velo2


    df = df.fillna(0)

    df.sort_values(by='TimeStamp (sec)',ascending=True)
	
    timestr = strftime("%Y%m%d-%H%M%S")

#    csvfilename ='media/Import_'+str(importid)+'.csv'
    csvfilename ='media/{code}_{importid}.csv'.format(
        importid=importid,
        code = uuid4().hex[:16]
        )

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

    id,message = dataprep.save_workout_database(csvfilename,r,
                                                workouttype=workouttype,
                                                title=title,
                                                notes=comments,
                                                workoutsource='sporttracks')

    return (id,message)

# Create workout from SportTracks Data, which are slightly different
# than Strava or Concept2 data
def add_workout_from_underarmourdata(user,importid,data):
    workouttype = 'water'

    try:
	comments = data['notes']
    except:
	comments = ''
    
    try:
	thetimezone = tz(data['start_locale_timezone'])
    except:
	thetimezone = 'UTC'

    r = getrower(user)
    try:
	rowdatetime = iso8601.parse_date(data['start_datetime'])
    except iso8601.ParseError:
	try:
	    rowdatetime = datetime.datetime.strptime(data['start_datetime'],"%Y-%m-%d %H:%M:%S")
	    rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
	except:
	    try:
		rowdatetime = dateutil.parser.parse(data['start_datetime'])
		rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
	    except:
		rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
		rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
    starttimeunix = arrow.get(rowdatetime).timestamp
    #starttimeunix = mktime(rowdatetime.utctimetuple())
        
	
    try:
	title = data['name']
    except:
	title = "Imported data"

    timeseries = data['time_series']

    # position, distance, speed, cadence, power, 
    
    res = splituadata(timeseries['distance'])

    distance = res[1]

    times_distance = res[0]


    try:
	l = timeseries['position']
    
	res = splituadata(l)
	times_location = res[0]
	latlong = res[1]
	latcoord = []
	loncoord = []

	for coord in latlong:
	    lat = coord['lat']
	    lon = coord['lng']
	    latcoord.append(lat)
	    loncoord.append(lon)
    except:
	times_location = times_distance
	latcoord = np.zeros(len(times_distance))
	loncoord = np.zeros(len(times_distance))
        if workouttype in types.otwtypes:
            workouttype = 'rower'
	
    try:
	res = splituadata(timeseries['cadence'])
	times_spm = res[0]
	spm = res[1]
    except KeyError:
	times_spm = times_distance
	spm = 0*times_distance
    
    try:
	res = splituadata(timeseries['heartrate'])
	hr = res[1]
	times_hr = res[0]
    except KeyError:
	times_hr = times_distance
	hr = 0*times_distance


    # create data series and remove duplicates
    distseries = pd.Series(distance,index=times_distance)
    distseries = distseries.groupby(distseries.index).first()
    latseries = pd.Series(latcoord,index=times_location)
    latseries = latseries.groupby(latseries.index).first()
    lonseries = pd.Series(loncoord,index=times_location)
    lonseries = lonseries.groupby(lonseries.index).first()
    spmseries = pd.Series(spm,index=times_spm)
    spmseries = spmseries.groupby(spmseries.index).first()
    hrseries = pd.Series(hr,index=times_hr)
    hrseries = hrseries.groupby(hrseries.index).first()


    # Create dicts and big dataframe
    d = {
	' Horizontal (meters)': distseries,
	' latitude': latseries,
	' longitude': lonseries,
	' Cadence (stokes/min)': spmseries,
	' HRCur (bpm)' : hrseries,
	}

    

    df = pd.DataFrame(d)

    df = df.groupby(level=0).last()

    cum_time = df.index.values
    df[' ElapsedTime (sec)'] = cum_time

    velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff()
    
    df[' Power (watts)'] = 0.0*velo

    nr_rows = len(velo.values)

    df[' DriveLength (meters)'] = np.zeros(nr_rows)
    df[' StrokeDistance (meters)'] = np.zeros(nr_rows)
    df[' DriveTime (ms)'] = np.zeros(nr_rows)
    df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows)
    df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows)
    df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows)
    df[' lapIdx'] = np.zeros(nr_rows)



    unixtime = cum_time+starttimeunix
    unixtime[0] = starttimeunix
 
    df['TimeStamp (sec)'] = unixtime

 
    dt = np.diff(cum_time).mean()
    wsize = round(5./dt)

    # velo2 = stravastuff.ewmovingaverage(velo,wsize)

    # df[' Stroke500mPace (sec/500m)'] = 500./velo2


    df = df.fillna(0)

    df.sort_values(by='TimeStamp (sec)',ascending=True)
	
    timestr = strftime("%Y%m%d-%H%M%S")

#    csvfilename ='media/Import_'+str(importid)+'.csv'
    csvfilename ='media/{code}_{importid}.csv'.format(
        importid=importid,
        code = uuid4().hex[:16]
        )

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

    id,message = dataprep.save_workout_database(csvfilename,r,
                                                workouttype=workouttype,
                                                workoutsource='mapmyfitness',
                                                title=title,
                                                notes=comments)

    return (id,message)

    



# Export workout to TCX and send to user's email address
@login_required()
def workout_tcxemail_view(request,id=0):
    message = ""
    successmessage = ""
    r = getrower(request.user)
    w = get_workout(id)
    if (checkworkoutuser(request.user,w)):
        if r.emailbounced:
            message = "Please check your email address first. Email to this address bounced."
            messages.error(request, message)
            return HttpResponseRedirect(
                reverse(workout_export_view,
		      kwargs = {
			  'id':str(w.id),
		      })
                )


        tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w,dozip=False)
        if tcxfile == 0:
            message = "Something went wrong (TCX export) "+tcxmessg
            messages.error(request,message)
            url = reverse(workout_export_view,
                          kwargs = {
                              'id':str(w.id),
                          })
            return HttpResponseRedirect(url)
        if tcxfile:
            res = myqueue(queuehigh,handle_sendemailtcx,
                          r.user.first_name,
                          r.user.last_name,
                          r.user.email,
                          tcxfile,
                          emailbounced = r.emailbounced
            )

	    successmessage = "The TCX file was sent to you per email"
            messages.info(request,successmessage)

            
	url = reverse(workout_export_view,
		      kwargs = {
			  'id':str(w.id),
		      })
	response = HttpResponseRedirect(url)

    else:
	message = "You are not allowed to export this workout"
        messages.error(request,message)
	url = reverse(workout_export_view,
		      kwargs = {
			  'id':str(w.id),
			  })
	response = HttpResponseRedirect(url)
		      
    return response

@login_required()
def course_kmlemail_view(request,id=0):
    r = getrower(request.user)
    if r.emailbounced:
        message = "Please check your email address first. Email to this address bounced."
        messages.error(request,message)
        return HttpResponseRedirect(
            reverse(course_view,
                    kwargs = {
                        'id':str(id),
                        })
            )

    course = GeoCourse.objects.get(id=id)

    kmlstring = courses.coursetokml(course)

    kmlfilename = 'course_{id}.kml'.format(id=id)

    with codecs.open(kmlfilename,'w','utf-8') as fop:
        fop.write(kmlstring)

    res = myqueue(queuehigh,handle_sendemailkml,
                  r.user.first_name,
		  r.user.last_name,
		  r.user.email,kmlfilename,
                  emailbounced = r.emailbounced
    )
 

    successmessage = "The KML file was sent to you per email"
    messages.info(request,successmessage)
    url = reverse(course_view,
		  kwargs = {
		      'id':str(id),
		  })

    response = HttpResponseRedirect(url)

    return response


# Export workout to GPX and send to user's email address
@login_required()
def workout_gpxemail_view(request,id=0):
    message = ""
    successmessage = ""
    r = Rower.objects.get(user=request.user)
    if r.emailbounced:
        message = "Please check your email address first. Email to this address bounced."
        messages.error(request, message)
        return HttpResponseRedirect(
            reverse(workout_export_view,
		    kwargs = {
			'id':str(w.id),
		    })
        )
    
    w = get_workout(id)

    if (checkworkoutuser(request.user,w)):
	filename = w.csvfilename
        row = rdata(filename)
        gpxfilename = filename[:-4]+'.gpx'
        row.exporttogpx(gpxfilename)
        res = myqueue(queuehigh,handle_sendemailtcx,
                      r.user.first_name,
		      r.user.last_name,
		      r.user.email,gpxfilename,
                      emailbounced = r.emailbounced
        )
 

	successmessage = "The GPX file was sent to you per email"
        messages.info(request,successmessage)
	url = reverse(workout_export_view,
		      kwargs = {
			  'id':str(w.id),
		      })

	response = HttpResponseRedirect(url)

    else:
	message = "You are not allowed to export this workout"
        messages.error(request,message)
	url = reverse(workout_export_view,
		      kwargs = {
			  'id':str(w.id),
			  })
	response = HttpResponseRedirect(url)
		      
    return response

# Get Workout summary CSV file
@login_required()
def workouts_summaries_email_view(request):
    r = getrower(request.user)
    if r.emailbounced:
        message = "Please check your email address first. Email to this address bounced."
        messages.error(request, message)
        return HttpResponseRedirect(
            reverse(workout_export_view,
		    kwargs = {
			'id':str(w.id),
		    })
        )

    if request.method == 'POST':
        form = DateRangeForm(request.POST)
        if form.is_valid():
            startdate = form.cleaned_data['startdate']
            enddate = form.cleaned_data['enddate']
            filename = 'rowsandall_workouts_{first}_{last}.csv'.format(
                first=startdate,
                last=enddate
                )
            df = dataprep.workout_summary_to_df(r,startdate=startdate,enddate=enddate)
            df.to_csv(filename,encoding='utf-8')
            res = myqueue(queuehigh,handle_sendemailsummary,
                          r.user.first_name,
                          r.user.last_name,
                          r.user.email,
                          filename,
                          emailbounced = r.emailbounced
            )
            messages.info(request,'The summary CSV file was sent to you per email')
    else:
        form = DateRangeForm()

    return render(request,"export_workouts.html",
                  {
                      'form':form
                      })
    

# Get Workout CSV file and send it to user's email address
@login_required()
def workout_csvemail_view(request,id=0):
    message = ""
    r = getrower(request.user)
    if r.emailbounced:
        message = "Please check your email address first. Email to this address bounced."
        messages.error(request, message)
        return HttpResponseRedirect(
            reverse(workout_export_view,
		    kwargs = {
			'id':str(w.id),
		    })
        )

    w = get_workout(id)

    if (checkworkoutuser(request.user,w)):
	csvfile = w.csvfilename
        res = myqueue(queuehigh,handle_sendemailcsv,r.user.first_name,
		      r.user.last_name,
		      r.user.email,csvfile,
                      emailbounced = r.emailbounced
           )

	successmessage = "The CSV file was sent to you per email"
        messages.info(request,successmessage)
	url = reverse(workout_export_view,
		      kwargs = {
			  'id':str(w.id),
			  })
	response = HttpResponseRedirect(url)

    else:
	message = "You are not allowed to export this workout"
        messages.error(request,message)
	url = reverse(workout_export_view,
		      kwargs = {
			  'id':str(w.id),
			  })
	response = HttpResponseRedirect(url)
		      
    return response

# Get Workout CSV file and send it to user's email address
@login_required()
def workout_csvtoadmin_view(request,id=0):
    message = ""
    r = getrower(request.user)
    w = get_workout(id)


    csvfile = w.csvfilename
    res = myqueue(queuehigh,
                  handle_sendemailcsv,
                  'Sander',
                  'Roosendaal',
                  'roosendaalsander@gmail.com',
                  csvfile)

    successmessage = "The CSV file was sent to the site admin per email"
    messages.info(request,successmessage)
    url = reverse(workout_view,
		  kwargs = {
		      'id':str(w.id),
		  })
    response = HttpResponseRedirect(url)

    return response

# Send workout to TP
@login_required()
def workout_tp_upload_view(request,id=0):
    
    message = ""
    r = getrower(request.user)
    res = -1
    try:
        thetoken = tp_open(r.user)
    except TPNoTokenError:
        return HttpResponseRedirect("/rowers/me/tpauthorize/")

    # ready to upload. Hurray
    w = get_workout_permitted(request.user,id)
    r = w.user

    if (checkworkoutuser(request.user,w)):
        tcxfile = tpstuff.createtpworkoutdata(w)
        if tcxfile:
            res,reason,status_code,headers = tpstuff.uploadactivity(
                r.tptoken,tcxfile,
                name=w.name
            )
            if res == 0:
                message = "Upload to TrainingPeaks failed with status code "+str(status_code)+": "+reason
                try:
                    os.remove(tcxfile)
                except WindowsError:
                    pass

                messages.error(request,message)

            else: # res != 0
                w.uploadedtotp = res
                w.save()
                os.remove(tcxfile)
                messages.info(request,'Uploaded to TrainingPeaks')

        else: # no tcxfile
            message = "Upload to TrainingPeaks failed"
            w.uploadedtotp = -1
            w.save()
            messages.error(request,message)

    else: # not allowed to upload
        message = "You are not allowed to export this workout to TP"
        messages.error(request,message)

    url = reverse(workout_export_view,
                  kwargs = {
                      'id':str(w.id),
                  })
                
    return HttpResponseRedirect(url)
                                      
                                
# Send workout to Strava
# abundance of error logging here because there were/are some bugs
@login_required()
def workout_strava_upload_view(request,id=0):
    message = ""
    r = getrower(request.user)
    res = -1
    if (r.stravatoken == '') or (r.stravatoken is None):
	s = "Token doesn't exist. Need to authorize"
	return HttpResponseRedirect("/rowers/me/stravaauthorize/")
    else:
	# ready to upload. Hurray
        w = get_workout_permitted(request.user,id)
        r = w.user
	if (checkworkoutuser(request.user,w)):
            try:
	        tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w)
                if tcxfile:
		    with open(tcxfile,'rb') as f:
                        try:
                            newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
                        except TypeError:
                            newnotes = 'from '+w.workoutsource+' via rowsandall.com'
                        activity_type = r.stravaexportas
		        res,mes = stravastuff.handle_stravaexport(f,w.name,
							      r.stravatoken,
							          description=newnotes,
                                                                  activity_type=activity_type)
                        if res==0:
                            messages.error(request,mes)
		            w.uploadedtostrava = -1
		            w.save()
                            try:
		                os.remove(tcxfile)
                            except WindowsError:
                                pass
		            url = reverse(workout_export_view,
			                  kwargs = {
				              'id':str(w.id),
				          })
		            response = HttpResponseRedirect(url)
                            return response
                                
                        try:
        	            w.uploadedtostrava = res
		            w.save()
                            try:
		                os.remove(tcxfile)
                            except WindowsError:
                                pass
		            url = "/rowers/workout/"+str(w.id)+"/edit"

                            messages.info(request,mes)
	                except:
                            with open("media/stravaerrors.log","a") as errorlog:
                                errorstring = str(sys.exc_info()[0])
                                timestr = strftime("%Y%m%d-%H%M%S")
                                errorlog.write(timestr+errorstring+"\r\n")
                                errorlog.write("views.py line 826\r\n")
                                message = 'Error: '+errorstring
                                messages.error(request,message)
                else: # No tcxfile
                    message = "Strava Data error "+tcxmessg
                    messages.error(request,message)
                    w.uploadedtostrava = -1
                    w.save()
		    url = reverse(workout_export_view,
			          kwargs = {
				      'id':str(w.id),
				  })
		    response = HttpResponseRedirect(url)


		url = reverse(workout_export_view,
			      kwargs = {
				  'id':str(w.id),
				  }
			      )
		response = HttpResponseRedirect(url)
	    except ActivityUploadFailed as e:
		message = "Strava Upload error: %s" % e
                messages.error(request,message)
		w.uploadedtostrava = -1
		w.save()
		os.remove(tcxfile)
		url = reverse(workout_export_view,
			      kwargs = {
				  'id':str(w.id),
				  })
		response = HttpResponseRedirect(url)

	return response
	  
# Upload workout to Concept2 logbook
@login_required()
def workout_c2_upload_view(request,id=0):
    message = ""
    # ready to upload. Hurray
    w = get_workout(id)
    r = w.user
    

    try:
        message,c2id = c2stuff.workout_c2_upload(request.user,w)
    except C2NoTokenError:
        return HttpResponseRedirect("/rowers/me/c2authorize/")

    if message and c2id <=0:
        messages.error(request,message)
    elif message:
        messages.info(request,message)


    url = reverse(workout_export_view,
		  kwargs = {
		      'id':str(w.id),
		  })

    return HttpResponseRedirect(url)

# Upload workout to RunKeeper
@login_required()
def workout_runkeeper_upload_view(request,id=0):
    message = ""
    w = get_workout(id)
    r = w.user

    try:
	thetoken = runkeeper_open(r.user)
    except RunKeeperNoTokenError:
	return HttpResponseRedirect("/rowers/me/runkeeperauthorize/")

    # ready to upload. Hurray

    if (checkworkoutuser(request.user,w)):
	data = runkeeperstuff.createrunkeeperworkoutdata(w)
        if not data:
            message = "Data error"
            messages.error(request,message)
            url = reverse(workout_export_view,
		          kwargs = {
		              'id':str(w.id),
		          })
            return HttpResponseRedirect(url)
        
	authorizationstring = str('Bearer ' + thetoken)
	headers = {'Authorization': authorizationstring,
		   'user-agent': 'sanderroosendaal',
		   'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json',
                   'Content-Length':'nnn'}

	url = "https://api.runkeeper.com/fitnessActivities"
	response = requests.post(url,headers=headers,data=json.dumps(data))

	# check for duplicate error first
	if (response.status_code == 409 ):
	    message = "Duplicate error"
            messages.error(request,message)
	    w.uploadedtorunkeeper = -1
	    w.save()
	elif (response.status_code == 201 or response.status_code==200):
	    runkeeperid = runkeeperstuff.getidfromresponse(response)
	    w.uploadedtorunkeeper = runkeeperid
	    w.save()
	    url = "/rowers/workout/"+str(w.id)+"/export"
	    return HttpResponseRedirect(url)
	else:
	    s = response
	    message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text)
            messages.error(request,message)
		
    else:
	message = "You are not authorized to upload this workout"
        messages.error(request,message)

    url = reverse(workout_export_view,
		  kwargs = {
		      'id':str(w.id),
	      })

    return HttpResponseRedirect(url)

# Upload workout to Underarmour
@login_required()
def workout_underarmour_upload_view(request,id=0):
    message = ""
    w = get_workout(id)
    r = w.user

    try:
	thetoken = underarmour_open(r.user)
    except UnderArmourNoTokenError:
	return HttpResponseRedirect("/rowers/me/underarmourauthorize/")

    # ready to upload. Hurray

    if (checkworkoutuser(request.user,w)):
	data = underarmourstuff.createunderarmourworkoutdata(w)
        if not data:
            message = "Data error"
            messages.error(request,message)
            url = reverse(workout_export_view,
		          kwargs = {
		              'id':str(w.id),
		          })
            return HttpResponseRedirect(url)
        
	authorizationstring = str('Bearer ' + thetoken)
	headers = {'Authorization': authorizationstring,
                   'Api-Key': UNDERARMOUR_CLIENT_KEY,
		   'user-agent': 'sanderroosendaal',
		   'Content-Type': 'application/json',
                   }

	url = "https://api.ua.com/v7.1/workout/"
	response = requests.post(url,headers=headers,data=json.dumps(data))

        
	# check for duplicate error first
	if (response.status_code == 409 ):
	    message = "Duplicate error"
            messages.error(request,message)
	    w.uploadedtounderarmour = -1
	    w.save()
	elif (response.status_code == 201 or response.status_code==200):
	    underarmourid = underarmourstuff.getidfromresponse(response)
	    w.uploadedtounderarmour = underarmourid
	    w.save()
	    url = "/rowers/workout/"+str(w.id)+"/export"
	    return HttpResponseRedirect(url)
	else:
	    s = response
	    message = "Something went wrong in workout_underarmour_upload_view: %s " % s.reason
	    messages.error(request,message)
    else:
	message = "You are not authorized to upload this workout"
        messages.error(request,message)
        
    url = reverse(workout_export_view,
		  kwargs = {
		      'id':str(w.id),
	      })

    return HttpResponseRedirect(url)

# Upload workout to SportTracks
@login_required()
def workout_sporttracks_upload_view(request,id=0):
    message = ""
    # ready to upload. Hurray
    w = get_workout(id)
    r = w.user

    try:
	thetoken = sporttracks_open(r.user)
    except SportTracksNoTokenError:
	return HttpResponseRedirect("/rowers/me/sporttracksauthorize/")


    if (checkworkoutuser(request.user,w)):
	data = sporttracksstuff.createsporttracksworkoutdata(w)
        if not data:
            message = "Data error"
            messages.error(request,message)
            url = reverse(workout_export_view,
		          kwargs = {
		              'id':str(w.id),
		          })
            return HttpResponseRedirect(url)
        
	authorizationstring = str('Bearer ' + thetoken)
	headers = {'Authorization': authorizationstring,
		   'user-agent': 'sanderroosendaal',
		   'Content-Type': 'application/json'}

	url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
	response = requests.post(url,headers=headers,data=json.dumps(data))

	# check for duplicate error first
	if (response.status_code == 409 ):
	    message = "Duplicate error"
            messages.error(request,message)
	    w.uploadedtosporttracks = -1
	    w.save()
	elif (response.status_code == 201 or response.status_code==200):
	    s= json.loads(response.text)
	    sporttracksid = sporttracksstuff.getidfromresponse(response)
	    w.uploadedtosporttracks = sporttracksid
	    w.save()
            message = "Upload to SportTracks was successful"
            messages.info(request,message)
	    url = "/rowers/workout/"+str(w.id)+"/export"
	    return HttpResponseRedirect(url)
	else:
	    s = response
	    message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason
	    messages.error(request,message)
    else:
	message = "You are not authorized to upload this workout"
        messages.error(request,message)
        
    url = reverse(workout_export_view,
		  kwargs = {
		      'id':str(w.id),
		      })

    return HttpResponseRedirect(url)

# Concept2 authorization 	  
@login_required()
def rower_c2_authorize(request):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks

    state = str(uuid4())
    scope = "user:read,results:write"
    params = {"client_id": C2_CLIENT_ID,
              "response_type": "code",
              "redirect_uri": C2_REDIRECT_URI}
    url = "http://log.concept2.com/oauth/authorize?"+ urllib.urlencode(params)
    url += "&scope="+scope
    return HttpResponseRedirect(url)

# Strava Authorization
@login_required()
def rower_strava_authorize(request):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks

    state = str(uuid4())

    params = {"client_id": STRAVA_CLIENT_ID,
              "response_type": "code",
              "redirect_uri": STRAVA_REDIRECT_URI,
	      "scope": "write"}

    url = "https://www.strava.com/oauth/authorize?"+ urllib.urlencode(params)

    return HttpResponseRedirect(url)

# Polar Authorization
@login_required()
def rower_polar_authorize(request):

    state = str(uuid4())

    params = {"client_id": POLAR_CLIENT_ID,
              "response_type": "code",
              "redirect_uri": POLAR_REDIRECT_URI,
              "state": state,
#	      "scope":"accesslink.read_all"
    }
    url = "https://flow.polar.com/oauth2/authorization?" +urllib.urlencode(params)
    
    return HttpResponseRedirect(url)

    

# Runkeeper authorization
@login_required()
def rower_runkeeper_authorize(request):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks

    state = str(uuid4())

    params = {"client_id": RUNKEEPER_CLIENT_ID,
              "response_type": "code",
	      "state": state,
              "redirect_uri": RUNKEEPER_REDIRECT_URI}

    url = "https://runkeeper.com/apps/authorize?"+ urllib.urlencode(params)


    return HttpResponseRedirect(url)

# SportTracks Authorization
@login_required()
def rower_sporttracks_authorize(request):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks

    state = str(uuid4())

    params = {"client_id": SPORTTRACKS_CLIENT_ID,
              "response_type": "code",
	      "state": state,
              "redirect_uri": SPORTTRACKS_REDIRECT_URI}

    url = "https://api.sporttracks.mobi/oauth2/authorize?"+ urllib.urlencode(params)


    return HttpResponseRedirect(url)

# Underarmour Authorization
@login_required()
def rower_underarmour_authorize(request):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks

    state = str(uuid4())

    redirect_uri = UNDERARMOUR_REDIRECT_URI
    
    url = 'https://www.mapmyfitness.com/v7.1/oauth2/authorize/?' \
                'client_id={0}&response_type=code&redirect_uri={1}'.format(
                    UNDERARMOUR_CLIENT_KEY, redirect_uri
                )

    return HttpResponseRedirect(url)

# Underarmour Authorization
@login_required()
def rower_tp_authorize(request):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks

    state = str(uuid4())
    params = {"client_id": TP_CLIENT_KEY,
              "response_type": "code",
              "redirect_uri": TP_REDIRECT_URI,
              "scope": "file:write",
	      }
    url = "https://oauth.trainingpeaks.com/oauth/authorize/?" +urllib.urlencode(params)

    return HttpResponseRedirect(url)


# Concept2 token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_c2_token_refresh(request):
    r = getrower(request.user)
    res = c2stuff.do_refresh_token(r.c2refreshtoken)
    if res[0] != None:
        access_token = res[0]
        expires_in = res[1]
        refresh_token = res[2]
        expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
        r = getrower(request.user)
        r.c2token = access_token
        r.tokenexpirydate = expirydatetime
        r.c2refreshtoken = refresh_token

        r.save()

        successmessage = "Tokens refreshed. Good to go"
        messages.info(request,successmessage)
    else:
        message = "Something went wrong (refreshing tokens). Please reauthorize:"
        messages.error(request,successmessage)
        
    return imports_view(request)

# Underarmour token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_underarmour_token_refresh(request):
    r = getrower(request.user)
    res = underarmourstuff.do_refresh_token(
        r.underarmourrefreshtoken,
        r.underarmourtoken
    )
    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)

    r = getrower(request.user)
    r.underarmourtoken = access_token
    r.underarmourtokenexpirydate = expirydatetime
    r.underarmourrefreshtoken = refresh_token

    r.save()

    successmessage = "Tokens refreshed. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)


# TrainingPeaks token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_tp_token_refresh(request):
    r = getrower(request.user)
    res = tpstuff.do_refresh_token(
        r.tprefreshtoken,
    )
    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)

    r = getrower(request.user)
    r.tptoken = access_token
    r.tptokenexpirydate = expirydatetime
    r.tprefreshtoken = refresh_token

    r.save()

    successmessage = "Tokens refreshed. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)


# SportTracks token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_sporttracks_token_refresh(request):
    r = getrower(request.user)
    res = sporttracksstuff.do_refresh_token(
        r.sporttracksrefreshtoken,
        )
    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)

    r = getrower(request.user)
    r.sporttrackstoken = access_token
    r.sporttrackstokenexpirydate = expirydatetime
    r.sporttracksrefreshtoken = refresh_token

    r.save()

    successmessage = "Tokens refreshed. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)


# Concept2 Callback
@login_required()
def rower_process_callback(request):
    try:
	code = request.GET['code']
	res = c2stuff.get_token(code)
    except MultiValueDictKeyError:
	message = "The resource owner or authorization server denied the request"
        messages.error(request,message)
	return imports_view(request)
	
    access_token = res[0]
    if access_token == 0:
        message = res[1]
        message += ' Contact info@rowsandall.com if this behavior persists.'
        messages.error(request,message)
        return imports_view(request)
        
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)

    r = getrower(request.user)
    r.c2token = access_token
    r.tokenexpirydate = expirydatetime
    r.c2refreshtoken = refresh_token

    r.save()

    successmessage = "Tokens stored. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)

# The imports page
@login_required()
def imports_view(request):

    r = getrower(request.user)

    if request.method == 'POST':
        form = RowerImportExportForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data

            for attr, value in cd.items():
                setattr(r,attr,value)

            r.save()
            
    else:
        form = RowerImportExportForm(instance=r)

    
    return render(request,"imports.html",
		  {
                      'teams':get_my_teams(request.user),
                      'form':form,
		   })

# Just for testing purposes
@login_required()
def test_reverse_view(request):
    successmessage = "Tokens stored. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)

# dummy 
@login_required()
def rower_process_twittercallback(request):
    return "dummy"

# Process Polar Callback
@login_required()
def rower_process_polarcallback(request):
    try:
        code = request.GET['code']
    except MultiValueDictKeyError:
        try:
            message = request.GET['error']
        except MultiValueDictKeyError:
            message = "access error"

        messages.error(request,message)
        return imports_view(request)

    access_token, expires_in, user_id = polarstuff.get_token(code)

    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
    
    r = getrower(request.user)
    r.polartoken = access_token
    r.polartokenexpirydate = expirydatetime
    r.polaruserid = user_id

    r.save()

    successmessage = "Tokens stored. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)


# Process Strava Callback
@login_required()
def rower_process_stravacallback(request):
    try:
        code = request.GET['code']
    except MultiValueDictKeyError:
        try:
            message = request.GET['error']
        except MultiValueDictKeyError:
            message = "access error"

        messages.error(request,message)
        return imports_view(request)
            
    res = stravastuff.get_token(code)

    if res[0]:
        access_token = res[0]
	      
        r = getrower(request.user)
        r.stravatoken = access_token

        r.save()

        successmessage = "Tokens stored. Good to go"
        messages.info(request,successmessage)
        return imports_view(request)
    else:
        message = "Something went wrong with the Strava authorization"
        messages.error(request,message)
        return imports_view(request)

# Process Runkeeper callback
@login_required()
def rower_process_runkeepercallback(request):
    code = request.GET['code']
    access_token = runkeeperstuff.get_token(code)

    r = getrower(request.user)
    r.runkeepertoken = access_token

    r.save()

    successmessage = "Tokens stored. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)

# Process SportTracks callback
@login_required()
def rower_process_sporttrackscallback(request):
    code = request.GET['code']
    res = sporttracksstuff.get_token(code)


    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]

    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
    
    r = getrower(request.user)
    r.sporttrackstoken = access_token
    r.sporttrackstokenexpirydate = expirydatetime
    r.sporttracksrefreshtoken = refresh_token

    r.save()

    successmessage = "Tokens stored. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)

# Process Underarmour callback
@login_required()
def rower_process_underarmourcallback(request):
    code = request.GET['code']
    res = underarmourstuff.get_token(code)


    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
    
    r = getrower(request.user)
    r.underarmourtoken = access_token
    r.underarmourtokenexpirydate = expirydatetime
    r.underarmourrefreshtoken = refresh_token

    r.save()

    successmessage = "Tokens stored. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)

# Process TrainingPeaks callback
@login_required()
def rower_process_tpcallback(request):
    code = request.GET['code']
    res = tpstuff.get_token(code)


    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
    
    r = getrower(request.user)
    r.tptoken = access_token
    r.tptokenexpirydate = expirydatetime
    r.tprefreshtoken = refresh_token

    r.save()

    successmessage = "Tokens stored. Good to go"
    messages.info(request,successmessage)
    return imports_view(request)

# Process Own API callback - for API testing purposes
@login_required()
def rower_process_testcallback(request):
    code = request.GET['code']
    res = ownapistuff.get_token(code)


    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)

    text = "Access Token:\n"
    text += access_token

    text += "\n\nRefresh Token:\n"
    text += refresh_token
    
    return HttpResponse(text)

# View around the Histogram of all strokes. Not implemented in UI
@login_required()
def histo_all(request,theuser=0,
	      startdate=timezone.now()-datetime.timedelta(days=10),
	      enddate=timezone.now(),
	      deltadays=-1,
	      startdatestring="",
	      enddatestring="",
              options={
                  'includereststrokes':False,
                  'workouttypes':[i[0] for i in types.workouttypes],
                  'waterboattype':types.waterboattype
              }):
    
    if 'options' in request.session:
        options = request.session['options']

    workouttypes = options['workouttypes']
    includereststrokes = options['includereststrokes']
    waterboattype = options['waterboattype']
    workstrokesonly = not includereststrokes


#    checktypes = ['water','rower','dynamic','slides','skierg',
#                  'paddle','snow','coastal','other']

    
    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))

    if startdatestring != "":
	startdate = iso8601.parse_date(startdatestring)

    if enddatestring != "":
	enddate = iso8601.parse_date(enddatestring)


    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    promember=0
    if theuser == 0:
	theuser = request.user.id

    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    if not promember:
	return HttpResponseRedirect("/rowers/about/")
	
    # get all indoor rows of past 12 months
    ayearago = timezone.now()-datetime.timedelta(days=365)
    try:
	r2 = getrower(theuser)
	allergworkouts = Workout.objects.filter(user=r2,
						workouttype__in=['rower','dynamic','slides'],
						startdatetime__gte=ayearago)
    except Rower.DoesNotExist:
	allergworkouts = []
	r2=0

    try:
	u = User.objects.get(id=theuser)
    except User.DoesNotExist:
	u = ''

    if allergworkouts:
	res = interactive_histoall(allergworkouts)
	script = res[0]
	div = res[1]
    else:
	script = ''
	div = '<p>No erg pieces uploaded yet.</p>'

    return render(request, 'histoall.html',
		  {'interactiveplot':script,
		   'the_div':div,
		   'id':theuser,
		   'theuser':u,
                   'teams':get_my_teams(request.user),
		   })

# The Flex plot for a large selection of workouts
@login_required()
def cum_flex_data(
        request,
        options={
            'includereststrokes':False,
            'rankingonly':False,
            'workouttypes':[i[0] for i in types.workouttypes],
            'waterboattype':types.waterboattype,
            'theuser':0,
            'xparam':'spm',
            'yparam1':'power',
            'yparam2':'None',
            'enddatestring':'',
            'startdatestring':'',
            'deltadays':-1,
        }):

    def_options = options

    if 'options' in request.session:
        options = request.session['options']

    try:
        workouttypes = options['workouttypes']
        rankingonly = options['rankingonly']
        includereststrokes = options['includereststrokes']
        waterboattype = options['waterboattype']
        workstrokesonly = not includereststrokes
        theuser = options['theuser']
        xparam = options['xparam']
        yparam1 = options['yparam1']
        yparam2 = options['yparam2']
        startdatestring = options['startdatestring']
        enddatestring = options['enddatestring']
        deltadays = options['deltadays']
    except KeyError:
        workouttypes = def_options['workouttypes']
        rankingonly = def_options['rankingonly']
        includereststrokes = def_options['includereststrokes']
        waterboattype = def_options['waterboattype']
        workstrokesonly = not includereststrokes
        theuser = def_options['theuser']
        xparam = def_options['xparam']
        yparam1 = def_options['yparam1']
        yparam2 = def_options['yparam2']
        startdatestring = def_options['startdatestring']
        enddatestring = def_options['enddatestring']
        deltadays = def_options['deltadays']
        request.session['options'] = def_options
        

    
    try:
        startdate = iso8601.parse_date(startdatestring)
    except ParseError:
        startdate = timezone.now()-datetime.timedelta(days=7)

    try:
        enddate = iso8601.parse_date(enddatestring)
    except ParseError:
        enddate = timezone.now()

    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))


    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    promember=0
    if theuser == 0:
	theuser = request.user.id

    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    r2 = getrower(theuser)

    if rankingonly:
        rankingpiece = [True,]
    else:
        rankingpiece = [True,False]
        
    allworkouts = Workout.objects.filter(user=r2,
					 workouttype__in=workouttypes,
                                         boattype__in=waterboattype,
					 startdatetime__gte=startdate,
					 startdatetime__lte=enddate,
                                         rankingpiece__in=rankingpiece)
       
    if allworkouts:
	res = interactive_cum_flex_chart2(allworkouts,xparam=xparam,
					  yparam1=yparam1,
					  yparam2=yparam2,
					  promember=promember,
                                          workstrokesonly=workstrokesonly,
        )
	script = res[0]
	div = res[1]
    else:
	script = ''
	div = '<p>No pieces uploaded for this date range.</p>'

    scripta = script.split('\n')[2:-1]
    script = ''.join(scripta)
    
    data = {
        "script":script,
        "div":div,
        }
        
    return JSONResponse(data)




@login_required()
def cum_flex(request,theuser=0,
	     xparam='spm',
	     yparam1='power',
	     yparam2='None',
	     startdate=timezone.now()-datetime.timedelta(days=10),
	     enddate=timezone.now(),
	     deltadays=-1,
	     startdatestring="",
	     enddatestring="",
             options={
                 'includereststrokes':False,
                 'workouttypes':[i[0] for i in types.workouttypes],
                 'waterboattype':types.waterboattype,
                 'rankingonly':False,
             }):

    if 'options' in request.session:
        options = request.session['options']

    try:
        workouttypes = options['workouttypes']
    except KeyError:
        workouttypes = [i[0] for i in types.workouttypes]

    try:
        includereststrokes = options['includereststrokes']
    except KeyError:
        includereststrokes = False

    try:
        rankingonly = options['rankingonly']
    except KeyError:
        rankingonly = False
        
    try:
        waterboattype = options['waterboattype']
    except KeyError:
        waterboattype = types.waterboattype
        
    workstrokesonly = not includereststrokes

    
    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))

    if startdatestring != "":
	startdate = iso8601.parse_date(startdatestring)

    if enddatestring != "":
	enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    promember=0
    if theuser == 0:
        if 'rowerid' in request.session:
            try:
                r = Rower.objects.get(id=request.session['rowerid'])
                theuser = r.user.id
            except Rower.DoesNotExist:
                theuser = request.user.id
        else:
	    theuser = request.user.id


    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

	
    # get all indoor rows of in date range
    
    # process form
    if request.method == 'POST' and "daterange" in request.POST:
	form = DateRangeForm(request.POST)
	deltaform = DeltaDaysForm(request.POST)
        optionsform = StatsOptionsForm()
	if form.is_valid():
	    startdate = form.cleaned_data['startdate']
	    enddate = form.cleaned_data['enddate']
	    if startdate > enddate:
		s = enddate
		enddate = startdate
		startdate = s
    elif request.method == 'POST' and "datedelta" in request.POST:
	deltaform = DeltaDaysForm(request.POST)
        optionsform = StatsOptionsForm()
	if deltaform.is_valid():
	    deltadays = deltaform.cleaned_data['deltadays']
	    if deltadays != 0 and isinstance(deltadays, Number):
		enddate = timezone.now()
		startdate = enddate-datetime.timedelta(days=deltadays)
		if startdate > enddate:
		    s = enddate
		    enddate = startdate
		    startdate = s
		form = DateRangeForm(initial={
		    'startdate': startdate,
		    'enddate': enddate,
		    })
            else:
                form = DateRangeForm()
                optionsform = StatsOptionsForm()
    elif request.method == 'POST' and 'options' in request.POST:
        optionsform = StatsOptionsForm(request.POST)
        if optionsform.is_valid():
            includereststrokes = optionsform.cleaned_data['includereststrokes']
            rankingonly = optionsform.cleaned_data['rankingonly']
            workstrokesonly = not includereststrokes
            waterboattype = optionsform.cleaned_data['waterboattype']
            workouttypes = []
            for type in types.checktypes:
                if optionsform.cleaned_data[type]:
                    workouttypes.append(type)
                    
                    
            options = {
                'includereststrokes':includereststrokes,
                'workouttypes':workouttypes,
                'waterboattype':waterboattype,
                'rankingonly':rankingonly,
                }
            request.session['options'] = options
            form = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
            deltaform = DeltaDaysForm()
        else:
            form = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
            deltaform = DeltaDaysForm()
    else:
	form = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
	deltaform = DeltaDaysForm()
        optionsform = StatsOptionsForm()

    script = ''
    div = get_call()
    js_resources = ''
    css_resources = ''

    axchoicesbasic = {ax[0]:ax[1] for ax in axes if ax[4]=='basic'}
    axchoicespro = {ax[0]:ax[1] for ax in axes if ax[4]=='pro'}
    noylist = ["time","distance"]
    axchoicesbasic.pop("cumdist")

    # set options form correctly
    initial = {}
    initial['includereststrokes'] = includereststrokes
    initial['rankingonly'] = rankingonly
    initial['waterboattype'] = waterboattype

    for wtype in types.checktypes:
        if wtype in workouttypes:
            initial[wtype] = True
        else:
            initial[wtype] = False


    try:
	u = User.objects.get(id=theuser)
    except User.DoesNotExist:
	u = ''

    optionsform = StatsOptionsForm(initial=initial)
        

    options['includereststrokes'] = includereststrokes
    options['rankingonly'] = includereststrokes
    options['workouttypes'] =workouttypes
    options['waterboattype'] =waterboattype
    options['theuser'] =theuser
    options['rankingonly'] = rankingonly
    options['xparam'] =xparam
    options['yparam1'] =yparam1
    options['yparam2'] =yparam2
    options['startdatestring'] = startdatestring
    options['enddatestring'] =enddatestring
    options['deltadays'] =deltadays


    request.session['options'] = options

    return render(request, 'cum_flex.html',
		  {'interactiveplot':script,
		   'the_div':div,
		   'js_res': js_resources,
		   'css_res':css_resources,
		   'id':theuser,
		   'theuser':u,
		   'startdate':startdate,
		   'enddate':enddate,
		   'form':form,
                   'optionsform':optionsform,
		   'deltaform':deltaform,
		   'xparam':xparam,
		   'yparam1':yparam1,
		   'yparam2':yparam2,
		   'promember':promember,
                   'teams':get_my_teams(request.user),
                   'axchoicesbasic':axchoicesbasic,
                   'axchoicespro':axchoicespro,
                   'noylist':noylist,
		   })


@user_passes_test(hasplannedsessions,login_url="/",redirect_field_name=None)
def fitnessmetric_view(request,id=0,mode='rower',
                       startdate=timezone.now()-timezone.timedelta(days=365),
                       enddate=timezone.now()):

    therower = getrequestrower(request,userid=id)
    theuser = therower.user


    if request.method == 'POST':
        form = FitnessMetricForm(request.POST)
        if form.is_valid():
            startdate = form.cleaned_data['startdate']
            enddate = form.cleaned_data['enddate']
            mode = form.cleaned_data['mode']
    else:
        form = FitnessMetricForm()

    fitnessmetrics = PowerTimeFitnessMetric.objects.filter(
        user=theuser,
        date__gte=startdate,
        date__lte=enddate)

    script,thediv = fitnessmetric_chart(
        fitnessmetrics,theuser,
        workoutmode=mode
    )

    return render(request,'fitnessmetric.html',
                  {
                      'therower':therower,
                      'chartscript':script,
                      'the_div':thediv,
                      'mode':mode,
                      'form':form,
                      })
    

# Show the EMpower Oarlock generated Stroke Profile
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_forcecurve_view(request,id=0,workstrokesonly=False):
    row = get_workout(id)

    promember=0
    mayedit=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1
	if request.user == row.user.user:
	    mayedit=1

    if not promember:
	return HttpResponseRedirect("/rowers/about/")

    if request.method == 'POST' and 'workstrokesonly' in request.POST:
        workstrokesonly = request.POST['workstrokesonly']
	if workstrokesonly == 'True':
	    workstrokesonly = True
	else:
	    workstrokesonly = False
            
    script,div,js_resources,css_resources = interactive_forcecurve([row],
                                                                   workstrokesonly=workstrokesonly)

    return render(request,
                  'forcecurve_single.html',
                  {
                      'the_script':script,
                      'the_div':div,
		      'js_res': js_resources,
		      'css_res':css_resources,
                      'id':int(id),
                      'mayedit':mayedit,
                      'workstrokesonly': not workstrokesonly,
                      'teams':get_my_teams(request.user),
                  })

# Test asynchronous tasking and messaging
@login_required()
def workout_test_task_view(request,id=0):
    row = Workout.objects.get(id=id)
    res = myqueue(queuehigh,addcomment2,request.user.id,row.id)


    url = reverse(workout_edit_view,
                  kwargs = {
                      'id':int(id),
                  })
    return HttpResponseRedirect(url)

# Show Stroke power histogram for a workout
@login_required()
def workout_histo_view(request,id=0):
    row = get_workout(id)

    promember=0
    mayedit=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1
	    if request.user == row.user.user:
		mayedit=1

    if not promember:
	return HttpResponseRedirect("/rowers/about/")
        
    res = interactive_histoall([row])
    script = res[0]
    div = res[1]

    return render(request,
                  'histo_single.html',
		  {'interactiveplot':script,
		   'the_div':div,
                   'id':int(id),
                   'mayedit':mayedit,
                   'teams':get_my_teams(request.user),
		   })



# Histogram for a date/time range
@login_required()
def histo(request,theuser=0,
	  startdate=timezone.now()-datetime.timedelta(days=365),
	  enddate=timezone.now(),
	  deltadays=-1,
	  startdatestring="",
	  enddatestring="",
             options={
                 'includereststrokes':False,
                 'workouttypes':[i[0] for i in types.workouttypes],
                 'waterboattype':types.waterboattype
             }):

    if 'options' in request.session:
        options = request.session['options']

    try:
        workouttypes = options['workouttypes']
        includereststrokes = options['includereststrokes']
        waterboattype = options['waterboattype']
    except KeyError:
        workouttypes = [i[0] for i in types.workouttypes]
        waterboattype = types.waterboattype
        includereststrokes = False
        
    workstrokesonly = not includereststrokes


#    checktypes = ['water','rower','dynamic','slides','skierg',
#                  'paddle','snow','coastal','other']

    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))

    if startdatestring != "":
	startdate = iso8601.parse_date(startdatestring)

    if enddatestring != "":
	enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    promember=0
    r = getrequestrower(request,userid=theuser)
    theuser = r.user.id


    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    if not promember:
	return HttpResponseRedirect("/rowers/promembership/")
	
    # get all indoor rows of in date range
    
    # process form
    if request.method == 'POST' and "daterange" in request.POST:
	form = DateRangeForm(request.POST)
	deltaform = DeltaDaysForm(request.POST)
        optionsform = StatsOptionsForm()
	if form.is_valid():
	    startdate = form.cleaned_data['startdate']
	    enddate = form.cleaned_data['enddate']
	    if startdate > enddate:
		s = enddate
		enddate = startdate
		startdate = s
    elif request.method == 'POST' and "datedelta" in request.POST:
	deltaform = DeltaDaysForm(request.POST)
        optionsform = StatsOptionsForm()
	if deltaform.is_valid():
	    deltadays = deltaform.cleaned_data['deltadays']
	    if deltadays != 0 and deltadays != None:
		enddate = timezone.now()
		startdate = enddate-datetime.timedelta(days=deltadays)
		if startdate > enddate:
		    s = enddate
		    enddate = startdate
		    startdate = s
		form = DateRangeForm(initial={
		    'startdate': startdate,
		    'enddate': enddate,
		    })
            else:
                form = DateRangeForm()
                optionsform = StatsOptionsForm()
    elif request.method == 'POST' and 'options' in request.POST:
        optionsform = StatsOptionsForm(request.POST)
        if optionsform.is_valid():
            includereststrokes = optionsform.cleaned_data['includereststrokes']
            workstrokesonly = not includereststrokes
            waterboattype = optionsform.cleaned_data['waterboattype']
            workouttypes = []
            for type in types.checktypes:
                if optionsform.cleaned_data[type]:
                    workouttypes.append(type)
                    
                    
            options = {
                'includereststrokes':includereststrokes,
                'workouttypes':workouttypes,
                'waterboattype':waterboattype,
                }
            request.session['options'] = options
            form = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
            deltaform = DeltaDaysForm()
        else:
            form = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
            deltaform = DeltaDaysForm()

    else:
	form = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
	deltaform = DeltaDaysForm()
        optionsform = StatsOptionsForm()
    try:
	r2 = getrower(theuser)
	allergworkouts = Workout.objects.filter(user=r2,
						workouttype__in=workouttypes,
                                                boattype__in=waterboattype,
						startdatetime__gte=startdate,
						startdatetime__lte=enddate)
	
    except Rower.DoesNotExist:
	allergworkouts = []
	r2=0

    try:
	u = User.objects.get(id=theuser)
    except User.DoesNotExist:
	u = ''

    if allergworkouts:
	res = interactive_histoall(allergworkouts)
	script = res[0]
	div = res[1]
    else:
	script = ''
        typesstring = ', '.join('{}'.format(item) for i,item in enumerate(workouttypes))
        if 'water' in workouttypes:
            boatsstring = 'water ('+', '.join('{}'.format(item) for i,item in enumerate(waterboattype))+')'
            typesstring = typesstring.replace('water',boatsstring)
	div = '<p>No pieces found for '+typesstring+' for this date range.</p>'

    # set options form correctly
    initial = {}
    initial['includereststrokes'] = includereststrokes

    initial['waterboattype'] = waterboattype

    for wtype in types.checktypes:
        if wtype in workouttypes:
            initial[wtype] = True
        else:
            initial[wtype] = False


    optionsform = StatsOptionsForm(initial=initial)
        
    request.session['options'] = options

    return render(request, 'histo.html',
		  {'interactiveplot':script,
		   'the_div':div,
		   'id':theuser,
		   'theuser':u,
		   'startdate':startdate,
		   'enddate':enddate,
		   'form':form,
                   'optionsform':optionsform,
		   'deltaform':deltaform,
                   'teams':get_my_teams(request.user),
		   })

# add a workout manually
@login_required()
def addmanual_view(request):
    r = Rower.objects.get(user=request.user)

    if request.method == 'POST':
        # Form was submitted
        form = WorkoutForm(request.POST)
        if form.is_valid():
            # Get values from form
	    name = form.cleaned_data['name']
	    date = form.cleaned_data['date']
	    starttime = form.cleaned_data['starttime']
	    workouttype = form.cleaned_data['workouttype']
	    duration = form.cleaned_data['duration']
            weightcategory = form.cleaned_data['weightcategory']
	    distance = form.cleaned_data['distance']
	    notes = form.cleaned_data['notes']
            thetimezone = form.cleaned_data['timezone']
            private = form.cleaned_data['private']
            try:
                boattype  = request.POST['boattype']
            except KeyError:
                boattype = '1x'
            try:
                privacy = request.POST['privacy']
            except KeyError:
                privacy = 'visible'
            try:
                rankingpiece = form.cleaned_data['rankingpiece']
            except KeyError:
                rankingpiece = False
                
            if private:
                privacy = 'private'
            else:
                privacy = 'visible'

	    startdatetime = (str(date) + ' ' + str(starttime))
	    startdatetime = datetime.datetime.strptime(startdatetime,
						       "%Y-%m-%d %H:%M:%S")
	    startdatetime = timezone.make_aware(startdatetime)
            startdatetime = startdatetime.astimezone(
                pytz.timezone(thetimezone)
            )


            id,message = dataprep.create_row_df(r,
                                                distance,
#                                                weightcategory,
                                                duration,startdatetime,
#                                                title = name,
#                                                notes=notes,
                                                workouttype=workouttype)



            if message:
                messages.error(request,message)

            if id:
                w = Workout.objects.get(id=id)
                w.rankingpiece = rankingpiece or is_ranking_piece(w)
                w.privacy = privacy
                w.weightcategory = weightcategory
                w.notes = notes
                w.name = name
                w.workouttype = workouttype
                w.boattype = boattype
                w.save()
                messages.info(request,'New workout created')


    initial = {
        'workouttype':'rower',
        'date':datetime.date.today(),
        'starttime':timezone.now(),
        'timezone':r.defaulttimezone,
        'duration':datetime.timedelta(minutes=2),
        'distance':500,
        
    }
    form = WorkoutForm(initial=initial)

    return render(request,'manualadd.html',
                  {'form':form,
                   })

@login_required()
def fitness_metric_view(request,mode='rower',days=42):
    r = getrower(request.user)
    startdate = timezone.now()-datetime.timedelta(days=days)

    # test if not something already done
    ms = PowerTimeFitnessMetric.objects.filter(user=request.user)
    max_workout_id = max([m.last_workout for m in ms])
    last_update_date = max([m.date.strftime('%Y-%m-%d') for m in ms])

        
    now_date = timezone.now().strftime('%Y-%m-%d')

    
    if mode == 'rower':
        workouts = Workout.objects.filter(
            user=r,
            workouttype__in=['rower','dynamic','slides'],
            startdatetime__gte=startdate)
    else:
        workouts = Workout.objects.filter(
            user=r,
            workouttype__in=['water','coastal'],
            startdatetime__gte=startdate)

    theids = [int(w.id) for w in workouts]
    max_id = max(theids)

    if last_update_date >= now_date or max_workout_id >= max_id:
        return HttpResponse("already done today or no new workouts")


    job = myqueue(queue,
                  handle_updatefitnessmetric,
                  request.user.id,mode,theids,
                  )
    
    return HttpResponse("job queued")


# Show ranking distances including predicted paces
@login_required()
def rankings_view(request,theuser=0,
	  startdate=timezone.now()-datetime.timedelta(days=365),
	  enddate=timezone.now(),
	  deltadays=-1,
	  startdatestring="",
	  enddatestring=""):

    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))

    if startdatestring != "":
	startdate = iso8601.parse_date(startdatestring)

    if enddatestring != "":
	enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    if theuser == 0:
	theuser = request.user.id

    promember=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
        if r.birthdate:
            age = calculate_age(r.birthdate)
            worldclasspower = int(metrics.getagegrouprecord(
                age,
                sex=r.sex,
                weightcategory=r.weightcategory
            ))
        else:
            worldclasspower = None
            
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    # get all indoor rows in date range
    
    # process form
    if request.method == 'POST' and "daterange" in request.POST:
	dateform = DateRangeForm(request.POST)
	deltaform = DeltaDaysForm(request.POST)
	if dateform.is_valid():
	    startdate = dateform.cleaned_data['startdate']
	    enddate = dateform.cleaned_data['enddate']
	    if startdate > enddate:
		s = enddate
		enddate = startdate
		startdate = s
    elif request.method == 'POST' and "datedelta" in request.POST:
	deltaform = DeltaDaysForm(request.POST)
	if deltaform.is_valid():
	    deltadays = deltaform.cleaned_data['deltadays']
	    if deltadays:
		enddate = timezone.now()
		startdate = enddate-datetime.timedelta(days=deltadays)
		if startdate > enddate:
		    s = enddate
		    enddate = startdate
		    startdate = s
		dateform = DateRangeForm(initial={
		    'startdate': startdate,
		    'enddate': enddate,
		    })
            else:
                dateform = DateRangeForm()
                deltaform = DeltaDaysForm()

    else:
	dateform = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
	deltaform = DeltaDaysForm()

    # get all 2k (if any) - this rower, in date range
    try:
	r = getrower(theuser)
    except Rower.DoesNotExist:
	allergworkouts = []
	r=0

	
    try:
	uu = User.objects.get(id=theuser)
    except User.DoesNotExist:
	uu = ''


    # test to fix bug
    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)

    thedistances = []
    theworkouts = []
    thesecs = []

    rankingdistances.sort()
    rankingdurations.sort()

    for rankingdistance in rankingdistances:
    
	workouts = Workout.objects.filter(
            user=r,distance=rankingdistance,
	    workouttype__in=['rower','dynamic','slides'],
            rankingpiece=True,
	    startdatetime__gte=startdate,
	    startdatetime__lte=enddate
        ).order_by('duration')
	if workouts:
	    thedistances.append(rankingdistance)
	    theworkouts.append(workouts[0])

	    timesecs = 3600*workouts[0].duration.hour
	    timesecs += 60*workouts[0].duration.minute
	    timesecs += workouts[0].duration.second
	    timesecs += 1.e-6*workouts[0].duration.microsecond
	
	    thesecs.append(timesecs)

    for rankingduration in rankingdurations:
    
	workouts = Workout.objects.filter(
            user=r,duration=rankingduration,
	    workouttype='rower',
            rankingpiece=True,
	    startdatetime__gte=startdate,
	    startdatetime__lte=enddate
        ).order_by('-distance')
	if workouts:
	    thedistances.append(workouts[0].distance)
	    theworkouts.append(workouts[0])

	    timesecs = 3600*workouts[0].duration.hour
	    timesecs += 60*workouts[0].duration.minute
	    timesecs += workouts[0].duration.second
	    timesecs += 1.e-5*workouts[0].duration.microsecond
	
	    thesecs.append(timesecs)

    thedistances = np.array(thedistances)
    thesecs = np.array(thesecs)

    thevelos = thedistances/thesecs
    theavpower = 2.8*(thevelos**3)


    # create interactive plot
    if len(thedistances) !=0 :
	res = interactive_cpchart(
            r,thedistances,thesecs,theavpower,
	    theworkouts,promember=promember
        )
	script = res[0]
	div = res[1]
	paulslope = res[2]
	paulintercept = res[3]
	p1 = res[4]
	message = res[5]
    else:
	script = ''
	div = '<p>No ranking pieces found.</p>'
	paulslope = 1
	paulintercept = 1
	p1 = [1,1,1,1]
	message = ""


    if request.method == 'POST' and "piece" in request.POST:
	form = PredictedPieceForm(request.POST)
	if form.is_valid():
	    value = form.cleaned_data['value']
            hourvalue,value = divmod(value,60)
            if hourvalue >= 24:
                hourvalue = 23
	    pieceunit = form.cleaned_data['pieceunit']
	    if pieceunit == 'd':
		rankingdistances.append(value)
	    else:
		rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue)))
    else:
	form = PredictedPieceForm()

    rankingdistances.sort()
    rankingdurations.sort()


    predictions = []
    cpredictions = []


    for rankingdistance in rankingdistances:
	# Paul's model
	p = paulslope*np.log10(rankingdistance)+paulintercept
	velo = 500./p
	t = rankingdistance/velo
	pwr = 2.8*(velo**3)
	a = {'distance':rankingdistance,
	     'duration':timedeltaconv(t),
	     'pace':timedeltaconv(p),
	     'power':int(pwr)}
	predictions.append(a)

	# CP model -
	pwr2 = p1[0]/(1+t/p1[2])
	pwr2 += p1[1]/(1+t/p1[3])

	if pwr2 <= 0:
	    pwr2 = 50.
	
	velo2 = (pwr2/2.8)**(1./3.)

	if np.isnan(velo2) or velo2 <= 0:
	    velo2 = 1.0
	    
	t2 = rankingdistance/velo2
	
	pwr3 = p1[0]/(1+t2/p1[2])
	pwr3 += p1[1]/(1+t2/p1[3])

	if pwr3 <= 0:
	    pwr3 = 50.
	
	velo3 = (pwr3/2.8)**(1./3.)
	if np.isnan(velo3) or velo3 <= 0:
	    velo3 = 1.0
	    
	t3 = rankingdistance/velo3
	p3 = 500./velo3

	a = {'distance':rankingdistance,
	     'duration':timedeltaconv(t3),
	     'pace':timedeltaconv(p3),
	     'power':int(pwr3)}
	cpredictions.append(a)




    for rankingduration in rankingdurations:
	t = 3600.*rankingduration.hour
	t += 60.*rankingduration.minute
	t += rankingduration.second
	t += rankingduration.microsecond/1.e6

	# Paul's model
	ratio = paulintercept/paulslope

	u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope

	d = 500*t*np.log(10.)
	d = d/(paulslope*lambertw(u))
	d = d.real

	velo = d/t
	p = 500./velo
	pwr = 2.8*(velo**3)
	a = {'distance':int(d),
	     'duration':timedeltaconv(t),
	     'pace':timedeltaconv(p),
	     'power':int(pwr)}
	predictions.append(a)

	# CP model
	pwr = p1[0]/(1+t/p1[2])
	pwr += p1[1]/(1+t/p1[3])

	if pwr <= 0:
	    pwr = 50.

	velo = (pwr/2.8)**(1./3.)

	if np.isnan(velo) or velo <=0:
	    velo = 1.0
	
	d = t*velo
	p = 500./velo
	a = {'distance':int(d),
	     'duration':timedeltaconv(t),
	     'pace':timedeltaconv(p),
	     'power':int(pwr)}
	cpredictions.append(a)


    messages.error(request,message)
    return render(request, 'rankings.html',
		  {'rankingworkouts':theworkouts,
		   'interactiveplot':script,
		   'the_div':div,
		   'predictions':predictions,
		   'cpredictions':cpredictions,
		   'nrdata':len(thedistances),
		   'form':form,
		   'dateform':dateform,
		   'deltaform':deltaform,
                   'worldclasspower':worldclasspower,
		   'id': theuser,
		   'theuser':uu,
		   'startdate':startdate,
		   'enddate':enddate,
                   'teams':get_my_teams(request.user),
		   })

@login_required()
def ajax_agegrouprecords(request,
                         age=25,
                         sex='female',
                         weightcategory='hwt',
                         userid=0):
    
    wcdurations = []
    wcpower = []
    durations = [1,4,30,60]
    distances = [100,500,1000,2000,5000,6000,10000,21097,42195]

    df = pd.DataFrame(
        list(
            C2WorldClassAgePerformance.objects.filter(
                sex=sex,
                weightcategory=weightcategory
            ).values()
        )
    )

    jsondf = df.to_json()
    
    job = myqueue(queue,
                  handle_getagegrouprecords,
                  jsondf,distances,durations,age,sex,weightcategory,
    )

    
            
    return JSONResponse(
        {
            'job':job.id
            }
        )


# Show ranking distances including predicted paces
@login_required()
def rankings_view2(request,theuser=0,
	  startdate=timezone.now()-datetime.timedelta(days=365),
	  enddate=timezone.now(),
	  deltadays=-1,
	  startdatestring="",
	  enddatestring=""):

    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))

    if startdatestring != "":
	startdate = iso8601.parse_date(startdatestring)

    if enddatestring != "":
	enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    if theuser == 0:
	theuser = request.user.id
    else:
        lastupdated = "01-01-1900"

        
    promember=0
    if not request.user.is_anonymous():
        r = getrower(request.user)
        wcdurations = []
        wcpower = []
        
        lastupdated = "01-01-1900"
        userid = 0
        if 'options' in request.session:
            options = request.session['options']
            try:
                wcdurations = options['wcdurations']
                wcpower = options['wcpower']
                lastupdated = options['lastupdated']
            except KeyError:
                pass
            try:
                userid = options['userid']
            except KeyError:
                userid = 0
        else:
            options = {}

            

        lastupdatedtime = arrow.get(lastupdated).timestamp
        current_time = arrow.utcnow().timestamp

        deltatime_seconds = current_time - lastupdatedtime
        recalc = False
        if str(userid) != str(theuser) or deltatime_seconds > 3600:
            recalc = True
            options['lastupdated'] = arrow.utcnow().isoformat()
        else:
            recalc = False

        options['userid'] = theuser
        
        if r.birthdate:
            age = calculate_age(r.birthdate)            
        else:
            worldclasspower = None
            age = 0

        agerecords = CalcAgePerformance.objects.filter(
            age = age,
            sex = r.sex,
            weightcategory = r.weightcategory)

        if len(agerecords) == 0:
            recalc = True
            wcpower = []
            wcduration = []
        else:
            wcdurations = []
            wcpower = []
            for record in agerecords:
                wcdurations.append(record.duration)
                wcpower.append(record.power)

        options['wcpower'] = wcpower
        options['wcdurations'] = wcdurations
        if theuser:
            options['userid'] = theuser

        request.session['options'] = options

            
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    # get all indoor rows in date range
    
    # process form
    if request.method == 'POST' and "daterange" in request.POST:
	dateform = DateRangeForm(request.POST)
	deltaform = DeltaDaysForm(request.POST)
	if dateform.is_valid():
	    startdate = dateform.cleaned_data['startdate']
	    enddate = dateform.cleaned_data['enddate']
	    if startdate > enddate:
		s = enddate
		enddate = startdate
		startdate = s
    elif request.method == 'POST' and "datedelta" in request.POST:
	deltaform = DeltaDaysForm(request.POST)
	if deltaform.is_valid():
	    deltadays = deltaform.cleaned_data['deltadays']
	    if deltadays:
		enddate = timezone.now()
		startdate = enddate-datetime.timedelta(days=deltadays)
		if startdate > enddate:
		    s = enddate
		    enddate = startdate
		    startdate = s
		dateform = DateRangeForm(initial={
		    'startdate': startdate,
		    'enddate': enddate,
		    })
            else:
                dateform = DateRangeForm()
                deltaform = DeltaDaysForm()

    else:
	dateform = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
	deltaform = DeltaDaysForm()

    # get all 2k (if any) - this rower, in date range
    try:
	r = getrower(theuser)
    except Rower.DoesNotExist:
	allergworkouts = []
	r=0

	
    try:
	uu = User.objects.get(id=theuser)
    except User.DoesNotExist:
	uu = ''


    # test to fix bug
    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)


    thedistances = []
    theworkouts = []
    thesecs = []



    rankingdistances.sort()
    rankingdurations.sort()

    for rankingdistance in rankingdistances:
    
	workouts = Workout.objects.filter(
            user=r,distance=rankingdistance,
	    workouttype__in=['rower','dynamic','slides'],
            rankingpiece=True,
	    startdatetime__gte=startdate,
	    startdatetime__lte=enddate).order_by('duration')
	if workouts:
	    thedistances.append(rankingdistance)
	    theworkouts.append(workouts[0])

	    timesecs = 3600*workouts[0].duration.hour
	    timesecs += 60*workouts[0].duration.minute
	    timesecs += workouts[0].duration.second
	    timesecs += 1.e-6*workouts[0].duration.microsecond
	
	    thesecs.append(timesecs)

    for rankingduration in rankingdurations:
    
	workouts = Workout.objects.filter(
            user=r,duration=rankingduration,
	    workouttype='rower',
            rankingpiece=True,
	    startdatetime__gte=startdate,
	    startdatetime__lte=enddate).order_by('-distance')
	if workouts:
	    thedistances.append(workouts[0].distance)
	    theworkouts.append(workouts[0])

	    timesecs = 3600*workouts[0].duration.hour
	    timesecs += 60*workouts[0].duration.minute
	    timesecs += workouts[0].duration.second
	    timesecs += 1.e-5*workouts[0].duration.microsecond
	
	    thesecs.append(timesecs)

    thedistances = np.array(thedistances)
    thesecs = np.array(thesecs)

    thevelos = thedistances/thesecs
    theavpower = 2.8*(thevelos**3)


    # create interactive plot
    if len(thedistances) !=0 :
	res = interactive_cpchart(
            r,thedistances,thesecs,theavpower,
	    theworkouts,promember=promember,
            wcdurations=wcdurations,wcpower=wcpower
        )
	script = res[0]
	div = res[1]
	paulslope = res[2]
	paulintercept = res[3]
	p1 = res[4]
	message = res[5]
        try:
            testcalc = pd.Series(res[6])*3
        except TypeError:
            age = 0

    else:
	script = ''
	div = '<p>No ranking pieces found.</p>'
	paulslope = 1
	paulintercept = 1
	p1 = [1,1,1,1]
	message = ""


    if request.method == 'POST' and "piece" in request.POST:
	form = PredictedPieceForm(request.POST)
	if form.is_valid():
	    value = form.cleaned_data['value']
            hourvalue,value = divmod(value,60)
            if hourvalue >= 24:
                hourvalue = 23
	    pieceunit = form.cleaned_data['pieceunit']
	    if pieceunit == 'd':
		rankingdistances.append(value)
	    else:
		rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue)))
    else:
	form = PredictedPieceForm()

    rankingdistances.sort()
    rankingdurations.sort()


    predictions = []
    cpredictions = []


    for rankingdistance in rankingdistances:
	# Paul's model
	p = paulslope*np.log10(rankingdistance)+paulintercept
	velo = 500./p
	t = rankingdistance/velo
	pwr = 2.8*(velo**3)
	a = {'distance':rankingdistance,
	     'duration':timedeltaconv(t),
	     'pace':timedeltaconv(p),
	     'power':int(pwr)}
	predictions.append(a)

	# CP model -
	pwr2 = p1[0]/(1+t/p1[2])
	pwr2 += p1[1]/(1+t/p1[3])

	if pwr2 <= 0:
	    pwr2 = 50.
	
	velo2 = (pwr2/2.8)**(1./3.)

	if np.isnan(velo2) or velo2 <= 0:
	    velo2 = 1.0
	    
	t2 = rankingdistance/velo2
	
	pwr3 = p1[0]/(1+t2/p1[2])
	pwr3 += p1[1]/(1+t2/p1[3])

	if pwr3 <= 0:
	    pwr3 = 50.
	
	velo3 = (pwr3/2.8)**(1./3.)
	if np.isnan(velo3) or velo3 <= 0:
	    velo3 = 1.0
	    
	t3 = rankingdistance/velo3
	p3 = 500./velo3

	a = {'distance':rankingdistance,
	     'duration':timedeltaconv(t3),
	     'pace':timedeltaconv(p3),
	     'power':int(pwr3)}
	cpredictions.append(a)




    for rankingduration in rankingdurations:
	t = 3600.*rankingduration.hour
	t += 60.*rankingduration.minute
	t += rankingduration.second
	t += rankingduration.microsecond/1.e6

	# Paul's model
	ratio = paulintercept/paulslope

	u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope

	d = 500*t*np.log(10.)
	d = d/(paulslope*lambertw(u))
	d = d.real

	velo = d/t
	p = 500./velo
	pwr = 2.8*(velo**3)
	a = {'distance':int(d),
	     'duration':timedeltaconv(t),
	     'pace':timedeltaconv(p),
	     'power':int(pwr)}
	predictions.append(a)

	# CP model
	pwr = p1[0]/(1+t/p1[2])
	pwr += p1[1]/(1+t/p1[3])

	if pwr <= 0:
	    pwr = 50.

	velo = (pwr/2.8)**(1./3.)

	if np.isnan(velo) or velo <=0:
	    velo = 1.0
	
	d = t*velo
	p = 500./velo
	a = {'distance':int(d),
	     'duration':timedeltaconv(t),
	     'pace':timedeltaconv(p),
	     'power':int(pwr)}
	cpredictions.append(a)

    if recalc:
        wcdurations = []
        wcpower = []
        durations = [1,4,30,60]
        distances = [100,500,1000,2000,5000,6000,10000,21097,42195]

        df = pd.DataFrame(
            list(
                C2WorldClassAgePerformance.objects.filter(
                    sex=r.sex,
                    weightcategory=r.weightcategory
                ).values()
            )
        )

        jsondf = df.to_json()
    
        job = myqueue(queue,
                      handle_getagegrouprecords,
                      jsondf,distances,durations,age,r.sex,r.weightcategory)
        try:
            request.session['async_tasks'] += [(job.id,'agegrouprecords')]
        except KeyError:
            request.session['async_tasks'] = [(job.id,'agegrouprecords')]

        

    messages.error(request,message)
    return render(request, 'rankings.html',
		  {'rankingworkouts':theworkouts,
		   'interactiveplot':script,
		   'the_div':div,
		   'predictions':predictions,
		   'cpredictions':cpredictions,
		   'nrdata':len(thedistances),
		   'form':form,
		   'dateform':dateform,
		   'deltaform':deltaform,
		   'id': theuser,
		   'theuser':uu,
                   'age':age,
                   'sex':r.sex,
                   'recalc':recalc,
                   'weightcategory':r.weightcategory,
		   'startdate':startdate,
		   'enddate':enddate,
                   'teams':get_my_teams(request.user),
		   })

@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_update_cp_view(request,id=0):
    row = get_workout(id)

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    row.rankingpiece = True
    row.save()

    r = getrower(request.user)

    dataprep.runcpupdate(r)
    
    if row.workouttype in types.otwtypes:
        url = reverse(otwrankings_view)
    else:
        url = reverse(oterankings_view)

    return HttpResponseRedirect(url)

# Show ranking distances including predicted paces
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def otwrankings_view(request,theuser=0,
	             startdate=timezone.now()-datetime.timedelta(days=365),
	             enddate=timezone.now(),
	             deltadays=-1,
	             startdatestring="",
	             enddatestring=""):

    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))

    if startdatestring != "":
        try:
	    startdate = iso8601.parse_date(startdatestring)
        except ParseError:
            pass

    if enddatestring != "":
        try:
	    enddate = iso8601.parse_date(enddatestring)
        except ParseError:
            pass

    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    if theuser == 0:
        if 'rowerid' in request.session:
            try:
                r = Rower.objects.get(id=request.session['rowerid'])
                theuser = r.user.id
            except Rower.DoesNotExist:
                theuser = request.user.id
        else:
	    theuser = request.user.id

    promember=0
    if not request.user.is_anonymous():
	r = Rower.objects.get(user=request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    # get all OTW rows in date range
    
    # process form
    if request.method == 'POST' and "daterange" in request.POST:
	dateform = DateRangeForm(request.POST)
	deltaform = DeltaDaysForm(request.POST)
	if dateform.is_valid():
	    startdate = dateform.cleaned_data['startdate']
	    enddate = dateform.cleaned_data['enddate']
	    if startdate > enddate:
		s = enddate
		enddate = startdate
		startdate = s
    elif request.method == 'POST' and "datedelta" in request.POST:
	deltaform = DeltaDaysForm(request.POST)
	if deltaform.is_valid():
	    deltadays = deltaform.cleaned_data['deltadays']
	    if deltadays:
		enddate = timezone.now()
		startdate = enddate-datetime.timedelta(days=deltadays)
		if startdate > enddate:
		    s = enddate
		    enddate = startdate
		    startdate = s
		dateform = DateRangeForm(initial={
		    'startdate': startdate,
		    'enddate': enddate,
		    })
            else:
	        dateform = DateRangeForm(initial={
	            'startdate': startdate,
	            'enddate': enddate,
	        })
                deltaform = DeltaDaysForm()

    else:
	dateform = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
	deltaform = DeltaDaysForm()

    # get all 2k (if any) - this rower, in date range
    try:
	r = Rower.objects.get(user=theuser)
        request.session['rowerid'] = r.id
    except Rower.DoesNotExist:
	raise Http404("Rower doesn't exist")
	

	
    try:
	uu = User.objects.get(id=theuser)
    except User.DoesNotExist:
	uu = ''


    # test to fix bug
    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)

 

    thedistances = []
    theworkouts = []
    thesecs = []
    
    theworkouts = Workout.objects.filter(
        user=r,rankingpiece=True,
	workouttype='water',
	startdatetime__gte=startdate,
	startdatetime__lte=enddate
    ).order_by(
        "-startdatetime"
        )


    delta,cpvalue,avgpower = dataprep.fetchcp(r,theworkouts)

    runningjob = 0
    
    taskstatus = get_stored_tasks_status(request)
    for task in taskstatus:
        if task['func_name'] == 'updatecpwater':
            if 'success' in task['status'].lower() or 'finished' in task['status'].lower():
                runningjob = 1
                messages.info(request,'CP chart data have been updated')
                remove_asynctask(request,task['id'])
            elif 'fail' in task['status'].lower():
                runningjob = 0
                try:
                    remove_asynctask(request,task[id])
                    messages.error(request,'Oh, your task failed')
                except KeyError:
                    pass
            elif 'started' in task['status'].lower():
                messages.info(request,'Busy updating CP chart data')
                runningjob = 1
            elif 'queued' in task['status'].lower() or 'pending' in task['status'].lower():
                messages.info(request,'Getting ready to update CP chart data')
                runningjob = 1



    if not runningjob:
        job = dataprep.runcpupdate(
            r,type='water',
            startdate=startdate,
            enddate=enddate
        )
        request.session['job_id'] = job.id
        try:
            request.session['async_tasks'] += [(job.id,'updatecpwater')]
        except KeyError:
            request.session['async_tasks'] = [(job.id,'updatecpwater')]        
        messages.info(request,'New calculation queued. Page will reload automatically. You can check the status of your calculations <a href="/rowers/jobs-status/" target="_blank">here</a>')
    
    powerdf = pd.DataFrame({
        'Delta':delta,
        'CP':cpvalue,
        })

    if powerdf.empty:
        messages.info(request,'Your calculations are running in the background. Page will reload automatically. You can check the status of your calculations <a href="/rowers/jobs-status/" target="_blank">here</a>')
    
    powerdf = powerdf[powerdf['CP']>0]
    powerdf.dropna(axis=0,inplace=True)
    powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True)
    powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True)


    rowername = r.user.first_name+" "+r.user.last_name
    # create interactive plot
    if len(powerdf) !=0 :
	res = interactive_otwcpchart(powerdf,promember=promember,rowername=rowername)
	script = res[0]
	div = res[1]
	p1 = res[2]
        ratio = res[3]
        r.p0 = p1[0]
        r.p1 = p1[1]
        r.p2 = p1[2]
        r.p3 = p1[3]
        r.cpratio = ratio
        r.save()
        paulslope = 1
        paulintercept = 1
	message = res[4]
    else:
	script = ''
	div = '<p>No ranking pieces found.</p>'
	paulslope = 1
	paulintercept = 1
	p1 = [1,1,1,1]
	message = ""


    if request.method == 'POST' and "piece" in request.POST:
	form = PredictedPieceForm(request.POST)
        clean = form.is_valid()
	value = form.cleaned_data['value']
        hourvalue,value = divmod(value,60)
        hourvalue = int(hourvalue)
        minutevalue = int(value)
        value = int(60*(value-minutevalue))
        if hourvalue >= 24:
            hourvalue = 23
	rankingdurations.append(datetime.time(minute=minutevalue,
                                              hour=hourvalue,
                                              second=value))
    else:
	form = PredictedPieceForm()


    cpredictions = []

    for rankingduration in rankingdurations:
	t = 3600.*rankingduration.hour
	t += 60.*rankingduration.minute
	t += rankingduration.second
	t += rankingduration.microsecond/1.e6


	# CP model
	pwr = p1[0]/(1+t/p1[2])
	pwr += p1[1]/(1+t/p1[3])

        
	if pwr <= 0:
	    pwr = 50.


        if  not np.isnan(pwr):
            try:
                pwr2 = pwr*ratio
            except:
                pwr2 = pwr

            a = {
	        'duration':timedeltaconv(t),
	        'power':int(pwr),
                'upper':int(pwr2)}
	    cpredictions.append(a)


    del form.fields["pieceunit"]

    startdatestring = startdate.strftime('%Y-%m-%d')
    enddatestring = enddate.strftime('%Y-%m-%d')
    request.session['startdate'] = startdatestring
    request.session['enddate'] = enddatestring

    messages.error(request,message)
    return render(request, 'otwrankings.html',
		  {'rankingworkouts':theworkouts,
		   'interactiveplot':script,
		   'the_div':div,
		   'cpredictions':cpredictions,
                   'avgpower':avgpower,
		   'form':form,
		   'dateform':dateform,
		   'deltaform':deltaform,
		   'id': theuser,
		   'theuser':uu,
		   'startdate':startdate,
		   'enddate':enddate,
                   'teams':get_my_teams(request.user),
                   'workouttype':'water',
		   })

# Show ranking distances including predicted paces
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def oterankings_view(request,theuser=0,
	             startdate=timezone.now()-datetime.timedelta(days=365),
	             enddate=timezone.now(),
	             deltadays=-1,
	             startdatestring="",
	             enddatestring=""):

    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))

    if startdatestring != "":
        try:
	    startdate = iso8601.parse_date(startdatestring)
        except ParseError:
            pass

    if enddatestring != "":
        try:
	    enddate = iso8601.parse_date(enddatestring)
        except ParseError:
            pass

    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    if theuser == 0:
        if 'rowerid' in request.session:
            try:
                r = Rower.objects.get(id=request.session['rowerid'])
                theuser = r.user.id
            except Rower.DoesNotExist:
                theuser = request.user.id
        else:
	    theuser = request.user.id


    promember=0
    if not request.user.is_anonymous():
	r = Rower.objects.get(user=request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    # get all OTW rows in date range
    
    # process form
    if request.method == 'POST' and "daterange" in request.POST:
	dateform = DateRangeForm(request.POST)
	deltaform = DeltaDaysForm(request.POST)
	if dateform.is_valid():
	    startdate = dateform.cleaned_data['startdate']
	    enddate = dateform.cleaned_data['enddate']
	    if startdate > enddate:
		s = enddate
		enddate = startdate
		startdate = s
    elif request.method == 'POST' and "datedelta" in request.POST:
	deltaform = DeltaDaysForm(request.POST)
	if deltaform.is_valid():
	    deltadays = deltaform.cleaned_data['deltadays']
	    if deltadays:
		enddate = timezone.now()
		startdate = enddate-datetime.timedelta(days=deltadays)
		if startdate > enddate:
		    s = enddate
		    enddate = startdate
		    startdate = s
		dateform = DateRangeForm(initial={
		    'startdate': startdate,
		    'enddate': enddate,
		    })
            else:
	        dateform = DateRangeForm(initial={
	            'startdate': startdate,
	            'enddate': enddate,
	        })
                deltaform = DeltaDaysForm()

    else:
	dateform = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
	deltaform = DeltaDaysForm()

    # get all 2k (if any) - this rower, in date range
    try:
	r = Rower.objects.get(user=theuser)
        request.session['rowerid'] = r.id
    except Rower.DoesNotExist:
	allergworkouts = []
        raise Http404("Rower doesn't exist")

	
    try:
	uu = User.objects.get(id=theuser)
    except User.DoesNotExist:
	uu = ''


    # test to fix bug
    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)

 
    
    thedistances = []
    theworkouts = []
    thesecs = []
    
    theworkouts = Workout.objects.filter(
        user=r,rankingpiece=True,
	workouttype__in=[
            'rower',
            'dynamic',
            'slides'
        ],
	startdatetime__gte=startdate,
	startdatetime__lte=enddate
    ).order_by("-startdatetime")


    delta,cpvalue,avgpower = dataprep.fetchcp(
        r,theworkouts,table='cpergdata'
    )

    runningjob = 0
    
    taskstatus = get_stored_tasks_status(request)
    for task in taskstatus:
        if task['func_name'] == 'updatecp':
            if 'success' in task['status'].lower() or 'finished' in task['status'].lower():
                runningjob = 1
                messages.info(request,'CP chart data have been updated')
                remove_asynctask(request,task['id'])
            elif 'fail' in task['status'].lower():
                runningjob = 0
                try:
                    remove_asynctask(request,task[id])
                    messages.error(request,'Oh, your task failed')
                except KeyError:
                    pass
            elif 'started' in task['status'].lower():
                messages.info(request,'Busy updating CP chart data')
                runningjob = 1
            elif 'queued' in task['status'].lower():
                messages.info(request,'Getting ready to update CP chart data')
                runningjob = 1

    
    if not runningjob:
        job = dataprep.runcpupdate(
            r,type='rower',
            startdate=startdate,
            enddate=enddate
        )
        request.session['job_id'] = job.id
        try:
            request.session['async_tasks'] += [(job.id,'updatecp')]
        except KeyError:
            request.session['async_tasks'] = [(job.id,'updatecp')]
        messages.info(request,'New calculation queued. Page will reload automatically. You can check the status of your calculations <a href="/rowers/jobs-status/" target="_blank">here</a>')

    powerdf = pd.DataFrame({
        'Delta':delta,
        'CP':cpvalue,
        })

    if powerdf.empty:
        messages.info(request,'Your calculations are running in the background. Page will reload automatically. You can check the status of your calculations <a href="/rowers/jobs-status/" target="_blank">here</a>')
    
    powerdf = powerdf[powerdf['CP']>0]
    powerdf.dropna(axis=0,inplace=True)
    powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True)
    powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True)

    rowername = r.user.first_name+" "+r.user.last_name
    # create interactive plot
    if len(powerdf) !=0 :
	res = interactive_otwcpchart(powerdf,promember=promember,rowername=rowername)
	script = res[0]
	div = res[1]
	p1 = res[2]
        ratio = res[3]
        r.ep0 = p1[0]
        r.ep1 = p1[1]
        r.ep2 = p1[2]
        r.ep3 = p1[3]
        r.ecpratio = ratio
        r.save()
        paulslope = 1
        paulintercept = 1
	message = res[4]
    else:
        ratio = 1
	script = ''
	div = '<p>No ranking pieces found.</p>'
	paulslope = 1
	paulintercept = 1
	p1 = [1,1,1,1]
	message = ""


    if request.method == 'POST' and "piece" in request.POST:
	form = PredictedPieceForm(request.POST)
        clean = form.is_valid()
	value = form.cleaned_data['value']
        hourvalue,tvalue = divmod(value,60)
        hourvalue = int(hourvalue)
        minutevalue = int(tvalue)
        tvalue = int(60*(tvalue-minutevalue))
        if hourvalue >= 24:
            hourvalue = 23
        pieceunit = form.cleaned_data['pieceunit']
        if pieceunit == 'd':
            rankingdistances.append(value)
        else:
	    rankingdurations.append(datetime.time(
                minute=minutevalue,
                hour=hourvalue,
                second=tvalue
            ))
    else:
	form = PredictedPieceForm()


    cpredictions = []



    for rankingduration in rankingdurations:
	t = 3600.*rankingduration.hour
	t += 60.*rankingduration.minute
	t += rankingduration.second
	t += rankingduration.microsecond/1.e6


	# CP model
	pwr = p1[0]/(1+t/p1[2])
	pwr += p1[1]/(1+t/p1[3])

        velo = (pwr/2.8)**(1./3.)
        p = 500./velo
        d = t*velo
        
	if pwr <= 0:
	    pwr = 50.


        if  not np.isnan(pwr):
            try:
                pwr2 = pwr*ratio
            except:
                pwr2 = pwr

            a = {
                'distance':int(d),
	        'duration':timedeltaconv(t),
	        'power':int(pwr),
                'upper':int(pwr2),
                'pace':timedeltaconv(p)}

	    cpredictions.append(a)


    # initiation - get 10 min power, then use Paul's law

    t_10 = 600.
    power_10 = p1[0]/(1+t_10/p1[2])
    power_10 += p1[1]/(1+t_10/p1[3])

    velo_10 = (power_10/2.8)**(1./3.)
    pace_10 = 500./velo_10
    distance_10 = t_10*velo_10

    paulslope = 5. 
    
    for rankingdistance in rankingdistances:

        delta = paulslope * np.log(rankingdistance/distance_10)/np.log(2)
        
        
        p = pace_10+delta
        velo = 500./p
        t = rankingdistance/velo
        
	pwr2 = p1[0]/(1+t/p1[2])
	pwr2 += p1[1]/(1+t/p1[3])
        try:
            pwr2 *= ratio
        except UnboundLocalError:
            pass

	if pwr2 <= 0:
	    pwr2 = 50.
	
	velo2 = (pwr2/2.8)**(1./3.)

	if np.isnan(velo2) or velo2 <= 0:
	    velo2 = 1.0
	    
	t2 = rankingdistance/velo2
	
	pwr3 = p1[0]/(1+t2/p1[2])
	pwr3 += p1[1]/(1+t2/p1[3])
        pwr3 *= ratio

        
	if pwr3 <= 0:
	    pwr3 = 50.
	
	velo3 = (pwr3/2.8)**(1./3.)
	if np.isnan(velo3) or velo3 <= 0:
	    velo3 = 1.0
	    
	t3 = rankingdistance/velo3
	p3 = 500./velo3

	a = {
            'distance':rankingdistance,
	    'duration':timedeltaconv(t3),
	    'power':'--',
	    'upper':int(pwr3),
            'pace':timedeltaconv(p3)}

        cpredictions.append(a)

        #    del form.fields["pieceunit"]

    startdatestring = startdate.strftime('%Y-%m-%d')
    enddatestring = enddate.strftime('%Y-%m-%d')
    request.session['startdate'] = startdatestring
    request.session['enddate'] = enddatestring



    messages.error(request,message)
    return render(request, 'oterankings.html',
		  {'rankingworkouts':theworkouts,
		   'interactiveplot':script,
		   'the_div':div,
		   'cpredictions':cpredictions,
                   'avgpower':avgpower,
		   'form':form,
		   'dateform':dateform,
		   'deltaform':deltaform,
		   'id': theuser,
		   'theuser':uu,
		   'startdate':startdate,
		   'enddate':enddate,
                   'teams':get_my_teams(request.user),
                   'workouttype':'rower',
		   })

# Reload the workout and calculate the summary from the stroke data (lapIDx)
@login_required()
def workout_recalcsummary_view(request,id=0):
    row = get_workout(id)

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    filename = row.csvfilename
    rowdata = rdata(filename)
    if rowdata:
        row.summary = rowdata.allstats()
        row.save()
        successmessage = "Summary Updated"
        messages.info(request,successmessage)
        url = reverse(workout_edit_view,
		  kwargs = {
		      'id':int(id),
		  })
    else:
        message = "Something went wrong. Could not update summary"
        messages.error(request,message)
        url = reverse(workout_edit_view,
                      kwargs = {
                          'id':int(id),
                          })
        
    return HttpResponseRedirect(url)

@login_required()
def workout_makepublic_view(request,id,
                            message='',
                            successmessage=''):

    row = get_workout(id)
    
    if (checkworkoutuser(request.user,row)==False):
        message = "You are not allowed to edit this workout"
        messages.error(request,message)
        url = reverse(workouts_view)

        return HttpResponseRedirect(url)

    row.privacy = 'visible'
    row.save()
    rr = getrower(request.user)
    
    teams = rr.team.all()
    for team in teams:
        row.team.add(team)
        

    message = "Workout set to public. Your followers and team members will see it"
    messages.info(request,message)
    
    url = reverse(workout_edit_view,
		  kwargs = {
		      'id':int(id),
		  })
    return HttpResponseRedirect(url)

@login_required()
def workout_setprivate_view(request,id,
                            message='',
                            successmessage=''):
    row = get_workout(id)
    
    if (checkworkoutuser(request.user,row)==False):
        message = "You are not allowed to edit this workout"
        messages.error(request,message)
        url = reverse(workouts_view)

        return HttpResponseRedirect(url)

    row.privacy = 'private'
    row.save()

    for team in row.team.all():
        row.team.remove(team)

    message = "Workout set to private. Only you will see it"
    messages.info(request,message)
    
    url = reverse(workout_edit_view,
		  kwargs = {
		      'id':int(id),
		  })
    return HttpResponseRedirect(url)

# Joining workout
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workouts_join_view(request):
    promember=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
            promember=1

            
    if request.method == 'POST' and 'workouts' in request.POST:
        form = WorkoutMultipleCompareForm(request.POST)
        paramform = WorkoutJoinParamForm(request.POST)
        if form.is_valid() and paramform.is_valid():
            workout_name = paramform.cleaned_data['workout_name']
            set_private = paramform.cleaned_data['set_private']

            cd = form.cleaned_data
            workouts = cd['workouts']
            ids = [int(w.id) for w in workouts]
            request.session['ids'] = ids


            id,message = dataprep.join_workouts(r,ids,
                                                title=workout_name,
                                                setprivate=set_private)
            
            if message:
                messages.error(request,message)

            url = reverse(r.defaultlandingpage,
                          kwargs = {
                            'id':int(id),
                          })
        
            return HttpResponseRedirect(url)
                
        else:
            return HttpResponse("form is not valid")
        
    else:
        url = reverse(workouts_join_select)
        return HttpResponseRedirect(url)

@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workouts_join_select(request,
                         startdatestring="",
                         enddatestring="",
                         message='',
                         successmessage='',
                         startdate=timezone.now()-datetime.timedelta(days=30),
                         enddate=timezone.now(),
                         teamid=0):

    try:
	r = getrower(request.user)
    except Rower.DoesNotExist:
        raise Http404("Rower doesn't exist")

    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])


    if 'waterboattype' in request.session:
        waterboattype = request.session['waterboattype']
    else:
        waterboattype = types.waterboattype

        
    if 'modalities' in request.session:
        modalities = request.session['modalities']
        if len(modalities) > 1:
            modality = 'all'
        else:
            modality = modalities[0]
    else:
        modalities = [m[0] for m in types.workouttypes]
        modality = 'all'
            
    if request.method == 'POST' and 'daterange' in request.POST:
        dateform = DateRangeForm(request.POST)
        if dateform.is_valid():
            startdate = dateform.cleaned_data['startdate']
            enddate = dateform.cleaned_data['enddate']
            startdatestring = startdate.strftime('%Y-%m-%d')
            enddatestring = enddate.strftime('%Y-%m-%d')
            request.session['startdate'] = startdatestring
            request.session['enddate'] = enddatestring
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })

    
    if request.method == 'POST' and 'modality' in request.POST:
        modalityform = TrendFlexModalForm(request.POST)
        if modalityform.is_valid():
            modality = modalityform.cleaned_data['modality']
            waterboattype = modalityform.cleaned_data['waterboattype']
            if modality == 'all':
                modalities = [m[0] for m in types.workouttypes]
            else:
                modalities = [modality]

            if modality != 'water':
                waterboattype = [b[0] for b in types.boattypes]

                
            request.session['modalities'] = modalities
            request.session['waterboattype'] = waterboattype

    negtypes = []
    for b in types.boattypes:
        if b[0] not in waterboattype:
            negtypes.append(b[0])
            
    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)

    if startdatestring:
        startdate = iso8601.parse_date(startdatestring)
    if enddatestring:
        enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
        s = enddate
        enddate = startdate
        startdate = s

    try:
        theteam = Team.objects.get(id=teamid)
    except Team.DoesNotExist:
        theteam = 0
        
    if r.rowerplan == 'basic' and theteam==0:
        raise PermissionDenied("Access denied")

    if theteam and (theteam.viewing == 'allmembers' or theteam.manager == request.user):
        workouts = Workout.objects.filter(team=theteam,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes)
    elif theteam and theteam.viewing == 'coachonly':
        workouts = Workout.objects.filter(team=theteam,user=r,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities).order_by("-date","-starttime").exclude(boattype__in=negtypes)

            
    else:
        theteam = None
        workouts = Workout.objects.filter(user=r,
                                      startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes)

    query = request.GET.get('q')
    if query:
        query_list = query.split()
        workouts = workouts.filter(
            reduce(operator.and_,
                   (Q(name__icontains=q) for q in query_list)) |
            reduce(operator.and_,
                   (Q(notes__icontains=q) for q in query_list))
            )

    form = WorkoutMultipleCompareForm()
    form.fields["workouts"].queryset = workouts

    if theteam:
        theid = theteam.id
    else:
        theid = 0
        
    joinparamform = WorkoutJoinParamForm()
    modalityform = TrendFlexModalForm(initial={
        'modality':modality,
        'waterboattype':waterboattype
    })


    messages.info(request,successmessage)
    messages.error(request,message)
    
    return render(request, 'workout_join_select.html',
                  {'workouts': workouts,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'team':theteam,
                   'form':form,
                   'joinparamform':joinparamform,
                   'modalityform':modalityform,
                   'teams':get_my_teams(request.user),
                   })

# Team comparison
@login_required()
def team_comparison_select(request,
                           startdatestring="",
                           enddatestring="",
                           message='',
                           successmessage='',
                           startdate=timezone.now()-datetime.timedelta(days=30),
                           enddate=timezone.now(),
                           teamid=0):

    try:
	r = getrower(request.user)
    except Rower.DoesNotExist:
        raise Http404("Rower doesn't exist")

    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])


    if 'waterboattype' in request.session:
        waterboattype = request.session['waterboattype']
    else:
        waterboattype = types.waterboattype

        
    if 'modalities' in request.session:
        modalities = request.session['modalities']
        if len(modalities) > 1:
            modality = 'all'
        else:
            modality = modalities[0]
    else:
        modalities = [m[0] for m in types.workouttypes]
        modality = 'all'
            
    if request.method == 'POST' and 'daterange' in request.POST:
        dateform = DateRangeForm(request.POST)
        if dateform.is_valid():
            startdate = dateform.cleaned_data['startdate']
            enddate = dateform.cleaned_data['enddate']
            startdatestring = startdate.strftime('%Y-%m-%d')
            enddatestring = enddate.strftime('%Y-%m-%d')
            request.session['startdate'] = startdatestring
            request.session['enddate'] = enddatestring
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })

    
    if request.method == 'POST' and 'modality' in request.POST:
        modalityform = TrendFlexModalForm(request.POST)
        if modalityform.is_valid():
            modality = modalityform.cleaned_data['modality']
            waterboattype = modalityform.cleaned_data['waterboattype']
            if modality == 'all':
                modalities = [m[0] for m in types.workouttypes]
            else:
                modalities = [modality]

            if modality != 'water':
                waterboattype = [b[0] for b in types.boattypes]

                
            request.session['modalities'] = modalities
            request.session['waterboattype'] = waterboattype

    negtypes = []
    for b in types.boattypes:
        if b[0] not in waterboattype:
            negtypes.append(b[0])
            
    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)

    if startdatestring:
        startdate = iso8601.parse_date(startdatestring)
    if enddatestring:
        enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
        s = enddate
        enddate = startdate
        startdate = s

    try:
        theteam = Team.objects.get(id=teamid)
    except Team.DoesNotExist:
        theteam = 0
        
    if r.rowerplan == 'basic' and theteam==0:
        if r.protrialexpires is None or r.protrialexpires<datetime.date.today():
            raise PermissionDenied("Access denied")

    if theteam and (theteam.viewing == 'allmembers' or theteam.manager == request.user):
        workouts = Workout.objects.filter(team=theteam,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes)
    elif theteam and theteam.viewing == 'coachonly':
        workouts = Workout.objects.filter(team=theteam,user=r,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities).order_by("-date","-starttime").exclude(boattype__in=negtypes)

            
    else:
        theteam = None
        workouts = Workout.objects.filter(user=r,
                                      startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes)

    query = request.GET.get('q')
    if query:
        query_list = query.split()
        workouts = workouts.filter(
            reduce(operator.and_,
                   (Q(name__icontains=q) for q in query_list)) |
            reduce(operator.and_,
                   (Q(notes__icontains=q) for q in query_list))
            )

    form = WorkoutMultipleCompareForm()
    form.fields["workouts"].queryset = workouts

    if theteam:
        theid = theteam.id
    else:
        theid = 0
        
    chartform = ChartParamChoiceForm(initial={'teamid':0})
    modalityform = TrendFlexModalForm(initial={
        'modality':modality,
        'waterboattype':waterboattype
    })


    messages.info(request,successmessage)
    messages.error(request,message)
    
    return render(request, 'team_compare_select.html',
                  {'workouts': workouts,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'team':theteam,
                   'form':form,
                   'chartform':chartform,
                   'modalityform':modalityform,
                   'teams':get_my_teams(request.user),
                   })


# Team comparison
@login_required()
def multi_compare_view(request):
    promember=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
            promember=1

            
    if request.method == 'POST' and 'workouts' in request.POST:
        form = WorkoutMultipleCompareForm(request.POST)
        chartform = ChartParamChoiceForm(request.POST)
        if form.is_valid() and chartform.is_valid():
            cd = form.cleaned_data
            workouts = cd['workouts']
            xparam = chartform.cleaned_data['xparam']
            yparam = chartform.cleaned_data['yparam']
            plottype = chartform.cleaned_data['plottype']
            teamid = chartform.cleaned_data['teamid']
            ids = [int(w.id) for w in workouts]
            request.session['ids'] = ids

            labeldict = {
                int(w.id): w.__unicode__() for w in workouts
                }
            
            res = interactive_multiple_compare_chart(ids,xparam,yparam,
                                                     promember=promember,
                                                     plottype=plottype,
                                                     labeldict=labeldict)
            script = res[0]
            div = res[1]
            errormessage = res[3]
            if errormessage != '':
                messages.error(request,errormessage)

            return render(request,'multicompare.html',
                          {'interactiveplot':script,
                           'the_div':div,
                           'promember':promember,
                           'teamid':teamid,
                           'chartform':chartform,
                           'teams':get_my_teams(request.user),
                           })
        else:
            return HttpResponse("Form is not valid")
    if request.method == 'POST' and 'ids' in request.session:
        chartform = ChartParamChoiceForm(request.POST)
        if chartform.is_valid():
            xparam = chartform.cleaned_data['xparam']
            yparam = chartform.cleaned_data['yparam']
            plottype = chartform.cleaned_data['plottype']
            teamid = chartform.cleaned_data['teamid']
            ids = request.session['ids']
            request.session['ids'] = ids
            workouts = [Workout.objects.get(id=id) for id in ids]

            labeldict = {
                int(w.id): w.__unicode__() for w in workouts
                }
            
            res = interactive_multiple_compare_chart(ids,xparam,yparam,
                                                     promember=promember,
                                                     plottype=plottype,
                                                     labeldict=labeldict)
            script = res[0]
            div = res[1]

            return render(request,'multicompare.html',
                          {'interactiveplot':script,
                           'the_div':div,
                           'promember':promember,
                           'teamid':teamid,
                           'chartform':chartform,
                           'teams':get_my_teams(request.user),
                           })
        
    else:
        url = reverse(workouts_view)
        return HttpResponseRedirect(url)

# Multi Flex Chart with Grouping
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def user_multiflex_select(request,
                          startdatestring="",
                          enddatestring="",
                          message='',
                          successmessage='',
                          startdate=timezone.now()-datetime.timedelta(days=30),
                          enddate=timezone.now(),
                          userid=0):

    r = getrequestrower(request,userid=userid)
    user = r.user
    
    if 'options' in request.session:
        options = request.session['options']
    else:
        options = {}

    try:
        palette = request.session['palette']
    except KeyError:
        palette = 'monochrome_blue'
    
    try:
        includereststrokes = request.session['includereststrokes']
    except KeyError:
        includereststrokes = False

    try:
        ploterrorbars = request.session['ploterrorbars']
    except:
        ploterrorbars = False
        

        
    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])


    if 'waterboattype' in request.session:
        waterboattype = request.session['waterboattype']
    else:
        waterboattype = types.waterboattype

    if 'rankingonly' in request.session:
        rankingonly = request.session['rankingonly']
    else:
        rankingonly = False
        
        
    if 'modalities' in request.session:
        modalities = request.session['modalities']
        if len(modalities) > 1:
            modality = 'all'
        else:
            modality = modalities[0]
    else:
        modalities = [m[0] for m in types.workouttypes]
        modality = 'all'
            
    if request.method == 'POST' and 'daterange' in request.POST:
        dateform = DateRangeForm(request.POST)
        if dateform.is_valid():
            startdate = dateform.cleaned_data['startdate']
            enddate = dateform.cleaned_data['enddate']
            startdatestring = startdate.strftime('%Y-%m-%d')
            enddatestring = enddate.strftime('%Y-%m-%d')
            request.session['startdate'] = startdatestring
            request.session['enddate'] = enddatestring
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })

    if request.method == 'POST' and 'modality' in request.POST:
        modalityform = TrendFlexModalForm(request.POST)
        if modalityform.is_valid():
            modality = modalityform.cleaned_data['modality']
            waterboattype = modalityform.cleaned_data['waterboattype']
            rankingonly = modalityform.cleaned_data['rankingonly']
            if modality == 'all':
                modalities = [m[0] for m in types.workouttypes]
            else:
                modalities = [modality]

            if modality != 'water':
                waterboattype = [b[0] for b in types.boattypes]

                
            request.session['modalities'] = modalities
            request.session['waterboattype'] = waterboattype
            request.session['rankingonly'] = rankingonly
            
    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)

    if startdatestring:
        startdate = iso8601.parse_date(startdatestring)
    if enddatestring:
        enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
        s = enddate
        enddate = startdate
        startdate = s


    negtypes = []
    for b in types.boattypes:
        if b[0] not in waterboattype:
            negtypes.append(b[0])

    if rankingonly:
        rankingpiece = [True]
    else:
        rankingpiece = [True,False]
        
    workouts = Workout.objects.filter(
        user=r,
        startdatetime__gte=startdate,
        startdatetime__lte=enddate,
        workouttype__in=modalities,
        rankingpiece__in=rankingpiece
    ).order_by(
        "-date", "-starttime"
    ).exclude(
        boattype__in=negtypes
    )

    query = request.GET.get('q')
    if query:
        query_list = query.split()
        workouts = workouts.filter(
            reduce(operator.and_,
                   (Q(name__icontains=q) for q in query_list)) |
            reduce(operator.and_,
                   (Q(notes__icontains=q) for q in query_list))
            )

    form = WorkoutMultipleCompareForm()
    form.fields["workouts"].queryset = workouts

    chartform = MultiFlexChoiceForm(initial={
        'palette':palette,
        'ploterrorbars':ploterrorbars,
        'includereststrokes':includereststrokes,
    })

    modalityform = TrendFlexModalForm(initial={
        'modality':modality,
        'waterboattype':waterboattype,
        'rankingonly':rankingonly,
    })

    messages.info(request,successmessage)
    messages.error(request,message)

    startdatestring = startdate.strftime('%Y-%m-%d')
    enddatestring = enddate.strftime('%Y-%m-%d')
    request.session['startdate'] = startdatestring
    request.session['enddate'] = enddatestring

    request.session['waterboattype'] = waterboattype
    request.session['rankingonly'] = rankingonly
    request.session['modalities'] = modalities
    

    return render(request, 'user_multiflex_select.html',
                  {'workouts': workouts,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'theuser':user,
                   'form':form,
                   'chartform':chartform,
                   'modalityform':modalityform,
                   'teams':get_my_teams(request.user),
                   })

@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def multiflex_data(request,userid=0,
                 options={
                     'includereststrokes':False,
                     'ploterrorbars':False,
                     'userid':0,
                     'palette': 'monochrome_blue',
                     'groupby': 'spm',
                     'binsize': 1,
                     'xparam': 'hr',
                     'yparam': 'pace',
                     'spmmin': 15,
                     'spmmax': 55,
                     'workmin': 400,
                     'workmax': 1500,
                     'ids': [],
                     'ploterrorbars':False,
                     }):

    if 'options' in request.session:
        options = request.session['options']

    try:
        includereststrokes = options['includereststrokes']
    except KeyError:
        includereststrokes = False

    try:
        ploterrorbars = options['ploterrorbars']
    except KeyError:
        ploterrorbars = False

    try:
        palette = request.session['palette']
    except KeyError:
        palette = 'monochrome_blue'
        
    workstrokesonly = not includereststrokes

    if userid==0:
        userid = request.user.id

    palette = options['palette']
    groupby = options['groupby']
    binsize = options['binsize']
    xparam  = options['xparam']
    yparam = options['yparam']
    spmmin = options['spmmin']
    spmmax = options['spmmax']
    workmin = options['workmin']
    workmax = options['workmax']
    ids = options['ids']
        
    workouts = [Workout.objects.get(id=id) for id in ids]
    labeldict = {
        int(w.id): w.__unicode__() for w in workouts
    }
    
    fieldlist,fielddict = dataprep.getstatsfields()
    fieldlist = [xparam,yparam,groupby,
                 'workoutid','spm','driveenergy',
                 'workoutstate']
    
    # prepare data frame
    datadf,extracols = dataprep.read_cols_df_sql(ids,fieldlist)


    datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)


    datadf = dataprep.filter_df(datadf,'spm',spmmin,
                                largerthan=True)
    datadf = dataprep.filter_df(datadf,'spm',spmmax,
                                largerthan=False)

    datadf = dataprep.filter_df(datadf,'driveenergy',workmin,
                                largerthan=True)
    datadf = dataprep.filter_df(datadf,'driveneergy',workmax,
                                largerthan=False)


    datadf.dropna(axis=0,how='any',inplace=True)


    datemapping = {
        w.id:w.date for w in workouts
    }

    datadf['date'] = datadf['workoutid']
    datadf['date'].replace(datemapping,inplace=True)

    today = datetime.date.today()
    datadf['days ago'] = map(lambda x : x.days, datadf.date - today)

    if groupby != 'date':
        try:
            bins = np.arange(datadf[groupby].min()-binsize,
                             datadf[groupby].max()+binsize,
                             binsize)
            groups = datadf.groupby(pd.cut(datadf[groupby],bins,labels=False))
        except ValueError:
            messages.error(
                request,
                "Unable to compete. Probably not enough data selected"
            )
            url = reverse(user_multiflex_select)
            return HttpResponseRedirect(url)
    else:
        bins = np.arange(datadf['days ago'].min()-binsize,
                         datadf['days ago'].max()+binsize,
                         binsize,
        )
        groups = datadf.groupby(pd.cut(datadf['days ago'], bins,
                                           labels=False))
            

    xvalues = groups.mean()[xparam]
    yvalues = groups.mean()[yparam]
    xerror = groups.std()[xparam]
    yerror = groups.std()[yparam]
    groupsize = groups.count()[xparam]

    mask = groupsize <= min([0.01*groupsize.sum(),0.2*groupsize.mean()])
    xvalues.loc[mask] = np.nan
    yvalues.loc[mask] = np.nan
    xerror.loc[mask] = np.nan
    yerror.loc[mask] = np.nan
    groupsize.loc[mask] = np.nan

    xvalues.dropna(inplace=True)
    yvalues.dropna(inplace=True)
    xerror.dropna(inplace=True)
    yerror.dropna(inplace=True)
    groupsize.dropna(inplace=True)

    
    if len(groupsize) == 0:
        messages.error(request,'No data in selection')
        url = reverse(user_multiflex_select)
        return HttpResponseRedirect(url)
    else:
        groupsize = 30.*np.sqrt(groupsize/float(groupsize.max()))
    
    df = pd.DataFrame({
        xparam:xvalues,
        yparam:yvalues,
        'x':xvalues,
        'y':yvalues,
        'xerror':xerror,
        'yerror':yerror,
        'groupsize':groupsize,
    })

    if yparam == 'pace':
        df['y'] = dataprep.paceformatsecs(df['y']/1.0e3)
    
    aantal = len(df)
    
    if groupby != 'date':
        try:
            df['groupval'] = groups.mean()[groupby]
            df['groupval'].loc[mask] = np.nan
                    
            groupcols = df['groupval']
        except ValueError:
            df['groupval'] =  groups.mean()[groupby].fillna(value=0)
            df['groupval'].loc[mask] = np.nan
            groupcols = df['groupval']
        except KeyError:
            messages.error(request,'Data selection error')
            url = reverse(user_multiflex_select)
            return HttpResponseRedirect(url)            
    else:
        try:
            dates = groups.min()[groupby]
            dates.loc[mask] = np.nan
            dates.dropna(inplace=True)
            df['groupval'] = [x.strftime("%Y-%m-%d") for x in dates]
            df['groupval'].loc[mask] = np.nan
            groupcols = 100.*np.arange(aantal)/float(aantal)
        except AttributeError:
            df['groupval'] = groups.mean()['days ago'].fillna(value=0)
            groupcols = 100.*np.arange(aantal)/float(aantal)
                    

    groupcols = (groupcols-groupcols.min())/(groupcols.max()-groupcols.min())
    if aantal == 1:
        groupcols = np.array([1.])
        

    colors = range_to_color_hex(groupcols,palette=palette)
    
    df['color'] = colors

    clegendx = np.arange(0,1.2,.2)
    legcolors = range_to_color_hex(clegendx,palette=palette)
    if groupby != 'date':
        clegendy = df['groupval'].min()+clegendx*(df['groupval'].max()-df['groupval'].min())
    else:
        clegendy = df.index.min()+clegendx*(df.index.max()-df.index.min())


    
    colorlegend =  zip(range(6),clegendy,legcolors)


    if userid == 0:
        extratitle = ''
    else:
        u = User.objects.get(id=userid)
        extratitle = ' '+u.first_name+' '+u.last_name
                

            
    script,div = interactive_multiflex(df,xparam,yparam,
                                       groupby,
                                       extratitle=extratitle,
                                       ploterrorbars=ploterrorbars,
                                       binsize=binsize,
                                       colorlegend=colorlegend)
                
    scripta= script.split('\n')[2:-1]
    script = ''.join(scripta)
    

    return JSONResponse({
        "script":script,
        "div":div,
        })        
    

@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def multiflex_view(request,userid=0,
                 options={
                     'includereststrokes':False,
                     'ploterrorbars':False,
                     }):

    if 'options' in request.session:
        options = request.session['options']

    try:
        includereststrokes = options['includereststrokes']
    except KeyError:
        includereststrokes = False

    try:
        ploterrorbars = options['ploterrorbars']
    except KeyError:
        ploterrorbars = False

    try:
        palette = request.session['palette']
    except KeyError:
        palette = 'monochrome_blue'
        
    workstrokesonly = not includereststrokes

    if userid==0:
        userid = request.user.id
    
    if request.method == 'POST' and 'workouts' in request.POST:
        form = WorkoutMultipleCompareForm(request.POST)
        chartform = MultiFlexChoiceForm(request.POST)
        if form.is_valid() and chartform.is_valid():
            cd = form.cleaned_data
            workouts = cd['workouts']
            xparam = chartform.cleaned_data['xparam']
            yparam = chartform.cleaned_data['yparam']
            includereststrokes = chartform.cleaned_data['includereststrokes']
            ploterrorbars = chartform.cleaned_data['ploterrorbars']

            workstrokesonly = not includereststrokes
            palette = chartform.cleaned_data['palette']
            
            groupby = chartform.cleaned_data['groupby']
            binsize = chartform.cleaned_data['binsize']
            if binsize <= 0:
                binsize = 1
            if groupby == 'pace':
                binsize *= 1000
            
            spmmin = chartform.cleaned_data['spmmin']
            spmmax = chartform.cleaned_data['spmmax']
            workmin = chartform.cleaned_data['workmin']
            workmax = chartform.cleaned_data['workmax']

            ids = [int(w.id) for w in workouts]
            request.session['ids'] = ids

        else:
            return HttpResponse("Form is not valid")
    elif request.method == 'POST' and 'ids' in request.session:
        chartform = MultiFlexChoiceForm(request.POST)
        if chartform.is_valid():
            xparam = chartform.cleaned_data['xparam']
            yparam = chartform.cleaned_data['yparam']
            includereststrokes = chartform.cleaned_data['includereststrokes']
            ploterrorbars = chartform.cleaned_data['ploterrorbars']
            request.session['ploterrorbars'] = ploterrorbars
            request.session['includereststrokes'] = includereststrokes
            workstrokesonly = not includereststrokes
            palette = chartform.cleaned_data['palette']

            groupby = chartform.cleaned_data['groupby']
            binsize = chartform.cleaned_data['binsize']
            if binsize <= 0:
                binsize = 1
            if groupby == 'pace':
                binsize *= 1000.
            
            spmmin = chartform.cleaned_data['spmmin']
            spmmax = chartform.cleaned_data['spmmax']
            workmin = chartform.cleaned_data['workmin']
            workmax = chartform.cleaned_data['workmax']

            ids = request.session['ids']
            request.session['ids'] = ids
            workouts = dataprep.get_workouts(ids,userid)
            if not workouts:
                message = 'Error: Workouts in session storage do not belong to this user.'
                messages.error(request,message)
                url = reverse(user_multiflex_select,
                              kwargs={
                                  'userid':userid,
                                  }
                              )
                return HttpResponseRedirect(url)
                              
            # workouts = [Workout.objects.get(id=id) for id in ids]


        else:
            return HttpResponse("invalid form")
    else:
        url = reverse(user_multiflex_select)
        return HttpResponseRedirect(url)

    div = get_call()

    options['includereststrokes'] = includereststrokes
    options['ploterrorbars'] = ploterrorbars
    options['userid'] = userid
    options['palette'] = palette
    options['groupby'] = groupby
    options['binsize'] = binsize
    options['xparam'] = xparam
    options['yparam'] = yparam
    options['spmmin'] = spmmin
    options['spmmax'] = spmmax
    options['workmin'] = workmin
    options['workmax'] = workmax
    options['ids'] = ids


    request.session['options'] = options
            

    return render(request,'multiflex.html',
                  {'interactiveplot':'',
                   'the_div':div,
                   'chartform':chartform,
                   'userid':userid,
                   'teams':get_my_teams(request.user),
                  })


# Box plots
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def user_boxplot_select(request,
                        startdatestring="",
                        enddatestring="",
                        message='',
                        successmessage='',
                        startdate=timezone.now()-datetime.timedelta(days=30),
                        enddate=timezone.now(),
                        options={
                            'includereststrokes':False,
                            'workouttypes':['rower','dynamic','slides'],
                            'waterboattype':types.waterboattype,
                            'rankingonly':False,
                        },
                        userid=0):

    r = getrequestrower(request,userid=userid)
    user = r.user
    
    if 'options' in request.session:
        options = request.session['options']
        

    try:
        workouttypes = options['workouttypes']
    except KeyError:
        workouttypes = ['rower','dynamic','slides']

    try:
        rankingonly = options['rankingonly']
    except KeyError:
        rankingonly = False
        
    try:
        includereststrokes = options['includereststrokes']
    except KeyError:
        includereststrokes = False


    workstrokesonly = not includereststrokes

    waterboattype = types.waterboattype

    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])

    if startdatestring != "":
	startdate = iso8601.parse_date(startdatestring)

    if enddatestring != "":
	enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])

    if request.method == 'POST' and 'daterange' in request.POST:
        dateform = DateRangeForm(request.POST)
        if dateform.is_valid():
            startdate = dateform.cleaned_data['startdate']
            enddate = dateform.cleaned_data['enddate']
            startdatestring = startdate.strftime('%Y-%m-%d')
            enddatestring = enddate.strftime('%Y-%m-%d')
            request.session['startdate'] = startdatestring
            request.session['enddate'] = enddatestring
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })

    if request.method == 'POST' and 'optionsform' in request.POST:
        optionsform = StatsOptionsForm(request.POST)
        if optionsform.is_valid():
            workouttypes = []
            waterboattype = optionsform.cleaned_data['waterboattype']
            rankingonly = optionsform.cleaned_data['rankingonly']
            for type in types.checktypes:
                if optionsform.cleaned_data[type]:
                    workouttypes.append(type)
                    
            options = {
                'workouttypes':workouttypes,
                'waterboattype':waterboattype,
                'rankingonly':rankingonly,
                }

            
            request.session['options'] = options


    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)

    if startdatestring:
        startdate = iso8601.parse_date(startdatestring)
    if enddatestring:
        enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
        s = enddate
        enddate = startdate
        startdate = s

    negtypes = []
    for b in types.boattypes:
        if b[0] not in waterboattype:
            negtypes.append(b[0])

    if rankingonly:
        rankingpiece = [True]
    else:
        rankingpiece = [True,False]
        
    waterinclude = False

    for ttype in types.otwtypes:
        if ttype in workouttypes:
            waterinclude = True
    
    if waterinclude:
        workoutsw = Workout.objects.filter(user=r,
                                           startdatetime__gte=startdate,
                                           startdatetime__lte=enddate,
                                           workouttype__in=types.otwtypes,
                                           rankingpiece__in=rankingpiece,
        ).exclude(boattype__in=negtypes)
        workouttypes = [w for w in workouttypes if w not in types.otwtypes]

    workoutse = Workout.objects.filter(user=r,
                                       startdatetime__gte=startdate,
                                       startdatetime__lte=enddate,
                                       workouttype__in=workouttypes,
                                       rankingpiece__in=rankingpiece)

    if waterinclude:
        workouts = workoutse | workoutsw
        workouts = workouts.distinct().order_by("-date", "-starttime")
    else:
        workouts = workoutse.order_by("-date","-starttime")
        
    if waterinclude:
        for ttype in types.otwtypes:
            workouttypes.append(ttype)

    query = request.GET.get('q')
    if query:
        query_list = query.split()
        workouts = workouts.filter(
            reduce(operator.and_,
                   (Q(name__icontains=q) for q in query_list)) |
            reduce(operator.and_,
                   (Q(notes__icontains=q) for q in query_list))
            )

    form = WorkoutMultipleCompareForm()
    form.fields["workouts"].queryset = workouts

    chartform = BoxPlotChoiceForm()
    # set options form correctly
    initial = {}
    initial['waterboattype'] = waterboattype
    initial['rankingonly'] =  rankingonly

    for wtype in types.checktypes:
        if wtype in workouttypes:
            initial[wtype] = True
        else:
            initial[wtype] = False


    optionsform = StatsOptionsForm(initial=initial)
        
    messages.info(request,successmessage)
    messages.error(request,message)

    startdatestring = startdate.strftime('%Y-%m-%d')
    enddatestring = enddate.strftime('%Y-%m-%d')
    request.session['startdate'] = startdatestring
    request.session['enddate'] = enddatestring

    return render(request, 'user_boxplot_select.html',
                  {'workouts': workouts,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'theuser':user,
                   'form':form,
                   'chartform':chartform,
                   'optionsform':optionsform,
                   'teams':get_my_teams(request.user),
                   })

@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def boxplot_view_data(request,userid=0,
                 options={
                     'includereststrokes':False,
                     'spmmin':15,
                     'spmmax':55,
                     'workmin':0,
                     'workmax':1500,
                     'ids':[],
                     'userid':0,
                     'plotfield':'spm',
                     }):

    if 'options' in request.session:
        options = request.session['options']

    try:
        includereststrokes = options['includereststrokes']
        spmmin = options['spmmin']
        spmmax = options['spmmax']
        workmin = options['workmin']
        workmax = options['workmax']
        ids = options['ids']
        userid = options['userid']
        plotfield = options['plotfield']
    except KeyError:
        includereststrokes = False
        spmmin = 15
        spmmax = 55
        workmin = 0
        workmax = 55
        ids = []
        userid = 0
        plotfield = 'spm'

    
    workstrokesonly = not includereststrokes

    if userid==0:
        userid = request.user.id

    workouts = [Workout.objects.get(id=id) for id in ids]
    labeldict = {
        int(w.id): w.__unicode__() for w in workouts
    }
            
            
    datemapping = {
        w.id:w.date for w in workouts
    }

    
    
    fieldlist,fielddict = dataprep.getstatsfields()
    fieldlist = [plotfield,'workoutid','spm','driveenergy',
                 'workoutstate']
    
    # prepare data frame
    datadf,extracols = dataprep.read_cols_df_sql(ids,fieldlist)
    
    datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)

    datadf = dataprep.filter_df(datadf,'spm',spmmin,
                                largerthan=True)
    datadf = dataprep.filter_df(datadf,'spm',spmmax,
                                largerthan=False)
    datadf = dataprep.filter_df(datadf,'driveenergy',workmin,
                                largerthan=True)
    datadf = dataprep.filter_df(datadf,'driveneergy',workmax,
                                largerthan=False)

    datadf.dropna(axis=0,how='any',inplace=True)

    datadf['workoutid'].replace(datemapping,inplace=True)
    datadf.rename(columns={"workoutid":"date"},inplace=True)
    datadf = datadf.sort_values(['date'])

    if userid == 0:
        extratitle = ''
    else:
        u = User.objects.get(id=userid)
        extratitle = ' '+u.first_name+' '+u.last_name
                

            
    script,div = interactive_boxchart(datadf,plotfield,
                                      extratitle=extratitle)

    scripta = script.split('\n')[2:-1]
    script = ''.join(scripta)
    

    return JSONResponse({
        "script":script,
        "div":div,
        })
    
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def boxplot_view(request,userid=0,
                 options={
                     'includereststrokes':False,
                     'rankingonly':False,
                     }):

    if 'options' in request.session:
        options = request.session['options']

    try:
        includereststrokes = options['includereststrokes']
    except KeyError:
        includereststrokes = False
        options['includereststrokes'] = False

    try:
        rankingonly = options['rankingonly']
    except KeyError:
        rankingonly = False
        options['rankingonly'] = False
        
    workstrokesonly = not includereststrokes

    if userid==0:
        userid = request.user.id
    
    if request.method == 'POST' and 'workouts' in request.POST:
        form = WorkoutMultipleCompareForm(request.POST)
        chartform = BoxPlotChoiceForm(request.POST)
        if form.is_valid() and chartform.is_valid():
            cd = form.cleaned_data
            workouts = cd['workouts']
            plotfield = chartform.cleaned_data['yparam']
            includereststrokes = chartform.cleaned_data['includereststrokes']
            request.session['includereststrokes'] = includereststrokes
            workstrokesonly = not includereststrokes

            spmmin = chartform.cleaned_data['spmmin']
            spmmax = chartform.cleaned_data['spmmax']
            workmin = chartform.cleaned_data['workmin']
            workmax = chartform.cleaned_data['workmax']

            ids = [int(w.id) for w in workouts]
            request.session['ids'] = ids

        else:
            return HttpResponse("Form is not valid")
    elif request.method == 'POST' and 'ids' in request.session:
        chartform = BoxPlotChoiceForm(request.POST)
        if chartform.is_valid():
            plotfield = chartform.cleaned_data['yparam']
            includereststrokes = chartform.cleaned_data['includereststrokes']
            spmmin = chartform.cleaned_data['spmmin']
            spmmax = chartform.cleaned_data['spmmax']
            workmin = chartform.cleaned_data['workmin']
            workmax = chartform.cleaned_data['workmax']
            request.session['includereststrokes'] = includereststrokes
            workstrokesonly = not includereststrokes
            ids = request.session['ids']
            request.session['ids'] = ids


        else:
            return HttpResponse("invalid form")
    else:
        url = reverse(user_boxplot_select)
        return HttpResponseRedirect(url)

    div = get_call()

    options['spmmin'] = spmmin
    options['spmmax'] = spmmax
    options['workmin'] = workmin
    options['workmax'] = workmax
    options['ids'] = ids
    options['userid'] = userid
    options['plotfield'] = plotfield
    options['rankingonly'] = rankingonly

    request.session['options'] = options
    
    return render(request,'boxplot.html',
                  {'interactiveplot':'',
                   'the_div':div,
                   'chartform':chartform,
                   'userid':userid,
                   'teams':get_my_teams(request.user),
                  })


# List Courses
@login_required()
def courses_view(request):
    r = getrower(request.user)

    courses = GeoCourse.objects.all().order_by("country","name")

    # add search processing
    query = request.GET.get('q')
    if query:
        query_list = query.split()
        courses = GeoCourse.objects.filter(
            reduce(operator.and_,
                   (Q(name__icontains=q) for q in query_list)) |
            reduce(operator.and_,
                   (Q(country__icontains=q) for q in query_list)) |
            reduce(operator.and_,
                   (Q(notes__icontains=q) for q in query_list))
            )
    
    return render(request,'list_courses.html',
                  {'courses':courses,
                   'rower':r,
                   })


# List Workouts    
@login_required()
def workouts_view(request,message='',successmessage='',
                  startdatestring='',
                  enddatestring='',
                  teamid=0,rankingonly=False,rowerid=0,userid=0):

    request.session['referer'] = absolute(request)['PATH']
    r = getrequestrower(request,rowerid=rowerid,userid=userid)

    # check if access is allowed
    if not checkaccessuser(request.user,r):
        raise PermissionDenied("Access denied")

    if startdatestring:
        startdate = iso8601.parse_date(startdatestring)
    else:
        startdate = datetime.date.today()-datetime.timedelta(days=365)

    if enddatestring:
        enddate = iso8601.parse_date(enddatestring)
    else:
        enddate = datetime.date.today()


    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))

    
    if request.method == 'POST':
        dateform = DateRangeForm(request.POST)
        if dateform.is_valid():
            startdate = dateform.cleaned_data['startdate']
            enddate = dateform.cleaned_data['enddate']
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })

    startdate = datetime.datetime.combine(startdate,datetime.time())
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
    #enddate = enddate+datetime.timedelta(days=1)


    if enddate < startdate:
        s = enddate
        enddate = startdate
        startdate = s

    startdatestring = startdate.strftime('%Y-%m-%d')
    enddatestring = enddate.strftime('%Y-%m-%d')

    # start date for the small graph
    activity_startdate = enddate-datetime.timedelta(days=15)

    try:
        if utc.localize(enddate) > timezone.now():
            activity_enddate = timezone.now()
            activity_startdate = activity_enddate-datetime.timedelta(days=15)
        else:
            activity_enddate = enddate
    except ValueError:
        activity_enddate = enddate

    if teamid:
        try:
            theteam = Team.objects.get(id=teamid)
        except Team.DoesNotExist:
            raise Http404("Team doesn't exist")

        if theteam.viewing == 'allmembers' or theteam.manager == request.user:
            workouts = Workout.objects.filter(team=theteam,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate).order_by("-date","-starttime")
            g_workouts = Workout.objects.filter(team=theteam,
                                                startdatetime__gte=activity_startdate,
                                                startdatetime__lte=activity_enddate).order_by("-date", "-starttime")
        elif theteam.viewing == 'coachonly':
            workouts = Workout.objects.filter(team=theteam,user=r,
                                              startdatetime__gte=startdate,
                                              startdatetime__lte=enddate).order_by("-startdatetime")
            g_workouts = Workout.objects.filter(team=theteam,user=r,
                                                startdatetime__gte=activity_startdate,
                                                enddatetime__lte=activity_enddate).order_by("-startdatetime")


    else:
        theteam = None
        workouts = Workout.objects.filter(user=r,
                                      startdatetime__gte=startdate,
                                      startdatetime__lte=enddate).order_by("-date", "-starttime")
        g_workouts = Workout.objects.filter(user=r,
                                            startdatetime__gte=activity_startdate,
                                            startdatetime__lte=activity_enddate).order_by("-startdatetime")

    if rankingonly:
        workouts = [w for w in workouts if w.rankingpiece]
        
    query = request.GET.get('q')
    if query:
        query_list = query.split()
        workouts = workouts.filter(
            reduce(operator.and_,
                   (Q(name__icontains=q) for q in query_list)) |
            reduce(operator.and_,
                   (Q(notes__icontains=q) for q in query_list))
            )

    paginator = Paginator(workouts,20) # show 25 workouts per page
    page = request.GET.get('page')

    try:
        workouts = paginator.page(page)
    except PageNotAnInteger:
        workouts = paginator.page(1)
    except EmptyPage:
        workouts = paginator.page(paginator.num_pages)

    today = timezone.now()
    announcements = SiteAnnouncement.objects.filter(
        expires__gte=today
    ).order_by(
        "-created",
        "-id"
    )

    if theteam:
        stack='rower'
    else:
        stack='type'

    script,div = interactive_activitychart(g_workouts,
                                           activity_startdate,
                                           activity_enddate,
                                           stack=stack)
    
    messages.info(request,successmessage)
    messages.error(request,message)
    
    return render(request, 'list_workouts.html',
                  {'workouts': workouts,
                   'rower':r,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'announcements':announcements[0:4],
                   'team':theteam,
                   'rankingonly':rankingonly,
                   'teams':get_my_teams(request.user),
                   'interactiveplot':script,
                   'the_div':div,
                   })


# List of workouts to compare a selected workout to
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_comparison_list(request,id=0,message='',successmessage='',
                            startdatestring="",enddatestring="",
                            startdate=timezone.now()-datetime.timedelta(days=365),
                            enddate=timezone.now()):

    try:
	r = getrower(request.user)
	u = User.objects.get(id=r.user.id)
        if request.method == 'POST':
            dateform = DateRangeForm(request.POST)
            if dateform.is_valid():
	        startdate = dateform.cleaned_data['startdate']
	        enddate = dateform.cleaned_data['enddate']
        else:
            dateform = DateRangeForm(initial={
                'startdate':startdate,
                'enddate':enddate,
                })

        if startdatestring:
            startdate = iso8601.parse_date(startdatestring)
        if enddatestring:
            enddate = iso8601.parse_date(enddatestring)

        startdate = datetime.datetime.combine(startdate,datetime.time())
        enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
        #enddate = enddate+datetime.timedelta(days=1)
                
        if enddate < startdate:
	    s = enddate
	    enddate = startdate
	    startdate = s
        
	workouts = Workout.objects.filter(user=r,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate).order_by("-date", "-starttime").exclude(id=id)

        query = request.GET.get('q')
        if query:
            query_list = query.split()
            workouts = workouts.filter(
                reduce(operator.and_,
                       (Q(name__icontains=q) for q in query_list)) |
                reduce(operator.and_,
                       (Q(notes__icontains=q) for q in query_list))
                )

        paginator = Paginator(workouts,15) # show 25 workouts per page
        page = request.GET.get('page')

        try:
            workouts = paginator.page(page)
        except PageNotAnInteger:
            workouts = paginator.page(1)
        except EmptyPage:
            workouts = paginator.page(paginator.num_pages)

        row = get_workout(id)

        messages.error(request,message)
        messages.info(request,successmessage)
	
	return render(request, 'comparison_list.html',
		      {'id':int(id),
		       'workout':row,
		       'workouts': workouts,
		       'last_name':u.last_name,
		       'first_name':u.first_name,
                       'dateform':dateform,
                       'startdate':startdate,
                       'enddate':enddate,
	               'teams':get_my_teams(request.user),
	       })
    except Rower.DoesNotExist:
	raise Http404("User has no rower instance")

# List of workouts to compare a selected workout to
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_fusion_list(request,id=0,message='',successmessage='',
                            startdatestring="",enddatestring="",
                            startdate=timezone.now()-datetime.timedelta(days=365),
                            enddate=timezone.now()):

    try:
	r = getrower(request.user)
	u = User.objects.get(id=r.user.id)
        if request.method == 'POST':
            dateform = DateRangeForm(request.POST)
            if dateform.is_valid():
	        startdate = dateform.cleaned_data['startdate']
	        enddate = dateform.cleaned_data['enddate']
        else:
            dateform = DateRangeForm(initial={
                'startdate':startdate,
                'enddate':enddate,
                })

        if startdatestring:
            startdate = iso8601.parse_date(startdatestring)
        if enddatestring:
            enddate = iso8601.parse_date(enddatestring)

        startdate = datetime.datetime.combine(startdate,datetime.time())
        enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
        #enddate = enddate+datetime.timedelta(days=1)
                
        if enddate < startdate:
	    s = enddate
	    enddate = startdate
	    startdate = s
        
	workouts = Workout.objects.filter(user=r,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate).order_by("-date", "-starttime").exclude(id=id)

        query = request.GET.get('q')
        if query:
            query_list = query.split()
            workouts = workouts.filter(
                reduce(operator.and_,
                       (Q(name__icontains=q) for q in query_list)) |
                reduce(operator.and_,
                       (Q(notes__icontains=q) for q in query_list))
                )

        paginator = Paginator(workouts,15) # show 25 workouts per page
        page = request.GET.get('page')

        try:
            workouts = paginator.page(page)
        except PageNotAnInteger:
            workouts = paginator.page(1)
        except EmptyPage:
            workouts = paginator.page(paginator.num_pages)
        row = get_workout(id)

	messages.info(request,successmessage)
        messages.error(request,message)
        
	return render(request, 'fusion_list.html',
		      {'id':int(id),
		       'workout':row,
		       'workouts': workouts,
		       'last_name':u.last_name,
		       'first_name':u.first_name,
                       'dateform':dateform,
                       'startdate':startdate,
                       'enddate':enddate,
	               'teams':get_my_teams(request.user),
	       })
    except Rower.DoesNotExist:
	raise Http404("User has no rower instance")
 
# Basic 'EDIT' view of workout
def workout_view(request,id=0):
    request.session['referer'] = absolute(request)['PATH']

    try:
	# check if valid ID exists (workout exists)
	row = Workout.objects.get(id=id)
        comments = WorkoutComment.objects.filter(workout=row)

        aantalcomments = len(comments)


        if row.privacy == 'private':
            raise PermissionDenied("Access denied")
        
	g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
        for i in g:
            try:
                width,height = Image.open(i.filename).size
                i.width = width
                i.height = height
                i.save()
            except:
                pass
                
	r = Rower.objects.get(id=row.user.id)
	u = User.objects.get(id=r.user.id)

	
	# create interactive plot
	res = interactive_chart(id)
	script = res[0]
	div = res[1]

        # create map
        f1 = row.csvfilename
        u = row.user.user
        r = getrower(u)
        rowdata = rdata(f1)
        hascoordinates = 1
        if rowdata != 0:
            try:
                latitude = rowdata.df[' latitude']
                if not latitude.std():
                    hascoordinates = 0
            except KeyError,AttributeError:
                hascoordinates = 0

        else:
            hascoordinates = 0


        if hascoordinates:
            mapscript,mapdiv = leaflet_chart(rowdata.df[' latitude'],
                                             rowdata.df[' longitude'],
                                             row.name)
                                        

        else:
            mapscript = ""
            mapdiv = ""

		
	# render page
	if (len(g)<=3):
	    return render(request, 'workout_view.html',
			  {'workout':row,
			   'graphs1':g[0:3],
			   'last_name':u.last_name,
			   'first_name':u.first_name,
			   'interactiveplot':script,
                           'aantalcomments':aantalcomments,
                           'mapscript':mapscript,
                           'mapdiv':mapdiv,
		           'teams':get_my_teams(request.user),
	                   'the_div':div})
	else:
	    return render(request, 'workout_view.html',
			  {'workout':row,
			   'graphs1':g[0:3],
			   'graphs2':g[3:6],
			   'last_name':u.last_name,
			   'first_name':u.first_name,
                           'teams':get_my_teams(request.user),
                           'aantalcomments':aantalcomments,
                           'mapscript':mapscript,
                           'mapdiv':mapdiv,
			   'interactiveplot':script,
			   'the_div':div})


    except Workout.DoesNotExist:
	raise Http404("Workout doesn't exist")

# Resets stroke data to raw data (pace)
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_undo_smoothenpace_view(
        request,id=0,message="",successmessage=""
):
    row = get_workout(id)

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    filename = row.csvfilename
    row = rdata(filename)
    if row == 0:
	return HttpResponse("Error: CSV Data File Not Found")

    if 'originalvelo' in row.df:
	velo = row.df['originalvelo'].values
	row.df[' Stroke500mPace (sec/500m)'] = 500./velo

    row.write_csv(filename,gzip=True)
    dataprep.update_strokedata(id,row.df)

    url = "/rowers/workout/"+str(id)+"/advanced"

    return HttpResponseRedirect(url)

	
# Data smoothing of pace data
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_smoothenpace_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    filename = row.csvfilename
    row = rdata(filename)
    if row == 0:
	return HttpResponse("Error: CSV Data File Not Found")

    pace = row.df[' Stroke500mPace (sec/500m)'].values
    velo = 500./pace

    if not 'originalvelo' in row.df:
	row.df['originalvelo'] = velo

    velo2 = stravastuff.ewmovingaverage(velo,5)

    pace2 = 500./abs(velo2)

    row.df[' Stroke500mPace (sec/500m)'] = pace2

    row.df = row.df.fillna(0)

    row.write_csv(filename,gzip=True)
    dataprep.update_strokedata(id,row.df)

    url = "/rowers/workout/"+str(id)+"/advanced"

    return HttpResponseRedirect(url)

# Process CrewNerd Summary CSV and update summary
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

    if request.method == 'POST':
	form = CNsummaryForm(request.POST,request.FILES)
	if form.is_valid():
	    f = request.FILES['file']
	    res = handle_uploaded_file(f)
	    fname = res[1]
	    try:
		sumd = summarydata(fname)
		row.summary = sumd.allstats()
		row.save()
		os.remove(fname)
		successmessage = "CrewNerd summary added"
                messages.info(request,successmessage)
		url = reverse(workout_edit_view,
			      kwargs = {
				  'id':int(id),
				  })

		return HttpResponseRedirect(url)
	    except:
                try:
		    os.remove(fname)
                except:
                    pass
                message = "Something went wrong (workout_crewnerd_summary_view)"
                messages.error(request,message)
		url = reverse(workout_edit_view,
			      kwargs = {
				  'id':int(id),
				  })
		return HttpResponseRedirect(url)
	else:
	    return render(request,
			  "cn_form.html",
			  {'form':form,
                           'teams':get_my_teams(request.user),
			   'id':row.id})
    else:
	form = CNsummaryForm()
	
	return render(request,
		      "cn_form.html",
		      {'form':form,
                       'teams':get_my_teams(request.user),
		       'id':row.id})
    
# Get weather for given location and date/time
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_downloadwind_view(request,id=0,
                              airportcode=None,
                              message="",successmessage=""):
    row = get_workout(id)

    f1 = row.csvfilename
    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    # create bearing
    rowdata = rdata(f1)
    if rowdata == 0:
	return HttpResponse("Error: CSV Data File Not Found")

    try:
	bearing = rowdata.df.ix[:,'bearing'].values
    except KeyError:
	rowdata.add_bearing()
	rowdata.write_csv(f1,gzip=True)

    # get wind
    try:
	avglat = rowdata.df[' latitude'].mean()
	avglon = rowdata.df[' longitude'].mean()
	avgtime = int(rowdata.df['TimeStamp (sec)'].mean()-rowdata.df.ix[0,'TimeStamp (sec)'])
	startdatetime = dateutil.parser.parse("{}, {}".format(row.date,
							      row.starttime))

        starttimeunix = int(arrow.get(row.startdatetime).timestamp)
	#starttimeunix = int(mktime(startdatetime.utctimetuple()))
	avgtime = starttimeunix+avgtime
	winddata = get_wind_data(avglat,avglon,avgtime)
	windspeed = winddata[0]
	windbearing = winddata[1]
	message = winddata[2]
	row.notes += "\n"+message
	row.save()
	rowdata.add_wind(windspeed,windbearing)
	rowdata.write_csv(f1,gzip=True)

        messages.info(request,message)
        
	kwargs = {
	    'id':int(id)}

	url = reverse(workout_wind_view,kwargs=kwargs)
	response = HttpResponseRedirect(url)
    except KeyError:
	message = "No latitude/longitude data"
        messages.error(request,message)
	kwargs = {
	    'id':int(id)
        }
	url = reverse(workout_wind_view,kwargs=kwargs)
	response = HttpResponseRedirect(url)



    return response

# Get weather for given location and date/time
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_downloadmetar_view(request,id=0,
                              airportcode=None,
                              message="",successmessage=""):
    row = get_workout(id)

    f1 = row.csvfilename
    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    # create bearing
    rowdata = rdata(f1)
    if rowdata == 0:
	return HttpResponse("Error: CSV Data File Not Found")

    try:
	bearing = rowdata.df.ix[:,'bearing'].values
    except KeyError:
	rowdata.add_bearing()
	rowdata.write_csv(f1,gzip=True)

    # get wind
    try:
	avglat = rowdata.df[' latitude'].mean()
	avglon = rowdata.df[' longitude'].mean()
        airportcode = get_airport_code(avglat,avglon)[0]
	avgtime = int(rowdata.df['TimeStamp (sec)'].mean()-rowdata.df.ix[0,'TimeStamp (sec)'])
	startdatetime = dateutil.parser.parse("{}, {}".format(row.date,
							      row.starttime))
	
        starttimeunix = arrow.get(row.startdatetime).timestamp
	#starttimeunix = int(mktime(startdatetime.utctimetuple()))
	avgtime = starttimeunix +avgtime
	winddata = get_metar_data(airportcode,avgtime)
	windspeed = winddata[0]
	windbearing = winddata[1]
	message = winddata[2]
	row.notes += "\n"+message
	row.save()
	rowdata.add_wind(windspeed,windbearing)
	rowdata.write_csv(f1,gzip=True)
        messages.info(request,message)
        
	kwargs = {
		  'id':int(id)}

	url = reverse(workout_wind_view,kwargs=kwargs)
	response = HttpResponseRedirect(url)
    except KeyError:
	message = "No latitude/longitude data"
        messages.error(request,message)
	kwargs = {
	    'id':int(id)
        }
	url = reverse(workout_wind_view,kwargs=kwargs)
	response = HttpResponseRedirect(url)



    return response


# Show form to update wind data
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_wind_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)


    # get data
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)

    # create bearing
    rowdata = rdata(f1)
    if row == 0:
	return HttpResponse("Error: CSV Data File Not Found")


    hascoordinates = 1
    try:
	latitude = rowdata.df.ix[:,' latitude']
    except KeyError:
	hascoordinates = 0

    if hascoordinates and not latitude.std():
        hascoordinates = 0
        
    try:
	bearing = rowdata.df.ix[:,'bearing'].values
    except KeyError:
	rowdata.add_bearing()
	rowdata.write_csv(f1,gzip=True)
	

    if hascoordinates:
        avglat = rowdata.df[' latitude'].mean()
        avglon = rowdata.df[' longitude'].mean()
        airportcode,newlat,newlon,airportdistance = get_airport_code(avglat,avglon)
        airportcode = airportcode.upper()
        airportdistance = airportdistance[0]
    else:
        airportcode = 'UNKNOWN'
        airportdistance = 0
        

    if request.method == 'POST':
	# process form
	form = UpdateWindForm(request.POST)

	if form.is_valid():
	    
	    vwind1 = form.cleaned_data['vwind1']
	    vwind2 = form.cleaned_data['vwind2']
	    dist1 = form.cleaned_data['dist1']
	    dist2 = form.cleaned_data['dist2']
	    winddirection1 = form.cleaned_data['winddirection1']
	    winddirection2 = form.cleaned_data['winddirection2']
	    windunit = form.cleaned_data['windunit']

	    rowdata.update_wind(vwind1,vwind2,
				winddirection1,
				winddirection2,
				dist1,dist2,
				units=windunit)

	    rowdata.write_csv(f1,gzip=True)

	    
	else:
	    message = "Invalid Form"
            messages.error(request,message)
	    kwargs = {
		'id':int(id)
            }
	    url = reverse(workout_wind_view,kwargs=kwargs)
	    response = HttpResponseRedirect(url)
	    
    else:
	form = UpdateWindForm()

    # create interactive plot
    res = interactive_windchart(id,promember=1)
    script = res[0]
    div = res[1]

    if hascoordinates:
        gmscript,gmdiv = leaflet_chart(
            rowdata.df[' latitude'],
	    rowdata.df[' longitude'],
	    row.name)
    else:
	gmscript = ""
	gmdiv = "No GPS data available"


    messages.info(request,successmessage)
    messages.error(request,message)
    
    return render(request,
		  'windedit.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'interactiveplot':script,
		   'form':form,
                   'airport':airportcode,
                   'airportdistance':airportdistance,
		   'the_div':div,
		   'gmap':gmscript,
		   'gmapdiv':gmdiv})
    

# Show form to update River stream data (for river dwellers)
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_stream_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)


    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)

    rowdata = rdata(f1)
    if rowdata == 0:
	return HttpResponse("Error: CSV Data File Not Found")

    if request.method == 'POST':
	# process form
	form = UpdateStreamForm(request.POST)

	if form.is_valid():
	    
	    dist1 = form.cleaned_data['dist1']
	    dist2 = form.cleaned_data['dist2']
	    stream1 = form.cleaned_data['stream1']
	    stream2 = form.cleaned_data['stream2']
	    streamunit = form.cleaned_data['streamunit']

	    rowdata.update_stream(stream1,stream2,dist1,dist2,
				units=streamunit)

	    rowdata.write_csv(f1,gzip=True)

	    
	else:
	    message = "Invalid Form"
            messages.error(request,message)
	    kwargs = {
		'id':int(id)}
	    url = reverse(workout_wind_view,kwargs=kwargs)
	    response = HttpResponseRedirect(url)
	    
    else:
	form = UpdateStreamForm()

    # create interactive plot
    res = interactive_streamchart(id,promember=1)
    script = res[0]
    div = res[1]

    messages.info(request,successmessage)
    messages.error(request,message)
    return render(request,
		  'streamedit.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'interactiveplot':script,
		   'form':form,
		   'the_div':div})
    
# Form to set average crew weight and boat type, then run power calcs
@user_passes_test(ispromember, login_url="/",redirect_field_name=None)
def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)


    if request.method == 'POST':
	# process form
	form = AdvancedWorkoutForm(request.POST)

	if form.is_valid():
            quick_calc = form.cleaned_data['quick_calc']
	    boattype = form.cleaned_data['boattype']
	    weightvalue = form.cleaned_data['weightvalue']
	    row.boattype = boattype
	    row.weightvalue = weightvalue
	    row.save()


	    # load row data & create power/wind/bearing columns if not set
	    f1 = row.csvfilename
	    rowdata = rdata(f1)
	    if rowdata == 0:
		return HttpResponse("Error: CSV Data File Not Found")
	    try:
		vstream = rowdata.df['vstream']
	    except KeyError:
		rowdata.add_stream(0)
		rowdata.write_csv(f1,gzip=True)

	    try:
		bearing = rowdata.df['bearing']
	    except KeyError:
		rowdata.add_bearing()
		rowdata.write_csv(f1,gzip=True)

	    try:
		vwind = rowdata.df['vwind']
	    except KeyError:
		rowdata.add_wind(0,0)
		rowdata.write_csv(f1,gzip=True)

	    # do power calculation (asynchronous)
            r = row.user
            u = r.user

	    first_name = u.first_name
	    last_name = u.last_name
	    emailaddress = u.email

            job = myqueue(queuelow,
                          handle_otwsetpower,f1,boattype,
			  weightvalue,
			  first_name,last_name,emailaddress,id,
                          ps=[r.p0,r.p1,r.p2,r.p3],
                          ratio=r.cpratio,
                          quick_calc = quick_calc,
                          emailbounced = r.emailbounced
            )

	    try:
                request.session['async_tasks'] += [(job.id,'otwsetpower')]
            except KeyError:
                request.session['async_tasks'] = [(job.id,'otwsetpower')]

	    successmessage = 'Your calculations have been submitted. You will receive an email when they are done. You can check the status of your calculations <a href="/rowers/jobs-status/" target="_blank">here</a>'
            messages.info(request,successmessage)
	    kwargs = {
		'id':int(id)}

            try:
                url = request.session['referer']
            except KeyError:
	        url = reverse(workout_advanced_view,kwargs=kwargs)
                
	    response = HttpResponseRedirect(url)
	    return response
	    
	else:
	    message = "Invalid Form"
            messages.error(request,message)
	    kwargs = {
		'id':int(id)}
	    url = reverse(workout_otwsetpower_view,kwargs=kwargs)
	    response = HttpResponseRedirect(url)
	    
    else:
	form = AdvancedWorkoutForm(instance=row)

    messages.error(request,message)
    messages.info(request,successmessage)
    return render(request,
		  'otwsetpower.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'form':form,
		   })

@login_required()
def instroke_view(request,id=0):
    row = get_workout(id)

#    form = WorkoutForm(instance=row)
    g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
    # check if user is owner of this workout

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    from metrics import nometrics
    rowdata = rrdata(csvfile=row.csvfilename)
    try:
        instrokemetrics = rowdata.get_instroke_columns()
        instrokemetrics = [m for m in instrokemetrics if not m in nometrics]
    except AttributeError:
        instrokemetrics = []


    return render(request,
		  'instroke.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
                   'instrokemetrics':instrokemetrics,
                   })

# A special Edit page with all the Geeky functionality for the workout
@login_required()
def workout_geeky_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

#    form = WorkoutForm(instance=row)
    g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
    rowdata = rrdata(csvfile=row.csvfilename)
    instrokemetrics = rowdata.get_instroke_columns()

    
    for i in g:
        try:
            width,height = Image.open(i.filename).size
            i.width = width
            i.height = height
            i.save()
        except:
            pass

    # check if user is owner of this workout

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)


    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)

    # create interactive plot
    try:
	res = interactive_chart(id,promember=1)
	script = res[0]
	div = res[1]
    except ValueError:
	pass

    messages.error(request,message)
    messages.info(request,successmessage)

    if row.workouttype in types.otwtypes:
	return render(request,
		  'otwgeeky.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'interactiveplot':script,
                   'instrokemetrics':instrokemetrics,
		   'the_div':div})
    else:
	return render(request,
		  'advancededit.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'interactiveplot':script,
		   'the_div':div})

# generate instroke chart
@login_required()
def instroke_chart(request,id=0,metric=''):
    w = get_workout(id)

    if (checkworkoutuser(request.user,w)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    rowdata = rrdata(csvfile=w.csvfilename)
    instrokemetrics = rowdata.get_instroke_columns()


    if metric in instrokemetrics:
        f1 = w.csvfilename[6:-4]
	timestr = strftime("%Y%m%d-%H%M%S")
	imagename = f1+timestr+'.png'
        fullpathimagename = 'static/plots/'+imagename
        u = w.user.user
	r = getrower(u)
        title = w.name
        fig1 = rowdata.get_plot_instroke(metric)
        canvas = FigureCanvas(fig1)
        canvas.print_figure('static/plots/'+imagename)
        plt.close(fig1)
        fig1.clf()
        gc.collect()

        try:
            width,height = Image.open(fullpathimagename).size
        except:
            width = 1200
            height = 600

        imgs = GraphImage.objects.filter(workout=w)
        if len(imgs) < 7:
            i = GraphImage(workout=w,
                           creationdatetime=timezone.now(),
                           filename=fullpathimagename,
                           width=width,height=height)
            
            i.save()
        else:
            messages.error(request,'You have reached the maximum number of static images for this workout. Delete an image first')
        

    r = getrower(request.user)
    url = reverse(r.defaultlandingpage,
                  kwargs = {
                      'id':id,
                      })

    return HttpResponseRedirect(url)
    
# Cumulative stats page
@login_required()
def cumstats(request,theuser=0,
	     startdate=timezone.now()-datetime.timedelta(days=30),
	     enddate=timezone.now(),
	     deltadays=-1,
	     startdatestring="",
	     enddatestring="",
             plotfield='spm',
             options={
                 'includereststrokes':False,
                 'workouttypes':['rower','dynamic','slides'],
                 'waterboattype':types.waterboattype,
                 'rankingonly':False,
             }):

    if 'options' in request.session:
        options = request.session['options']

        
    try:
        workouttypes = options['workouttypes']
    except KeyError:
        workouttypes = ['rower','dynamic','slides']

    try:
        includereststrokes = options['includereststrokes']
    except KeyError:
        includereststrokes = False


    try:
        rankingonly = options['rankingonly']
    except KeyError:
        rankingonly = False
        
    workstrokesonly = not includereststrokes

    waterboattype = types.waterboattype
    
    if deltadays>0:
	startdate = enddate-datetime.timedelta(days=int(deltadays))

    if startdatestring != "":
	startdate = iso8601.parse_date(startdatestring)

    if enddatestring != "":
	enddate = iso8601.parse_date(enddatestring)

    if enddate < startdate:
	s = enddate
	enddate = startdate
	startdate = s

    promember=0
    if theuser == 0:
        if 'rowerid' in request.session:
            try:
                r = Rower.objects.get(id=request.session['rowerid'])
                theuser = r.user.id
            except Rower.DoesNotExist:
                theuser = request.user.id
        else:
	    theuser = request.user.id


    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    if not promember:
	return HttpResponseRedirect("/rowers/promembership/")
	
    # get all indoor rows of in date range
    # process form
    if request.method == 'POST' and "daterange" in request.POST:
	form = DateRangeForm(request.POST)
	deltaform = DeltaDaysForm(request.POST)
        optionsform = StatsOptionsForm()
	if form.is_valid():
	    startdate = form.cleaned_data['startdate']
	    enddate = form.cleaned_data['enddate']
	    if startdate > enddate:
		s = enddate
		enddate = startdate
		startdate = s
    elif request.method == 'POST' and "datedelta" in request.POST:
	deltaform = DeltaDaysForm(request.POST)
	if deltaform.is_valid():
	    deltadays = deltaform.cleaned_data['deltadays']
	    if deltadays != 0 and isinstance(deltadays, Number):
		enddate = timezone.now()
		startdate = enddate-datetime.timedelta(days=deltadays)
		if startdate > enddate:
		    s = enddate
		    enddate = startdate
		    startdate = s
		form = DateRangeForm(initial={
		    'startdate': startdate,
		    'enddate': enddate,
		    })
                optionsform = StatsOptionsForm()
            else:
                form = DateRangeForm()
                optionsform = StatsOptionsForm()
    elif request.method == 'POST' and 'options' in request.POST:
        optionsform = StatsOptionsForm(request.POST)
        if optionsform.is_valid():
            includereststrokes = optionsform.cleaned_data['includereststrokes']
            workstrokesonly = not includereststrokes
            workouttypes = []
            rankingonly = optionsform.cleaned_data['rankingonly']
            waterboattype = optionsform.cleaned_data['waterboattype']
            for type in types.checktypes:
                if optionsform.cleaned_data[type]:
                    workouttypes.append(type)

            options = {
                'includereststrokes':includereststrokes,
                'workouttypes':workouttypes,
                'waterboattype':waterboattype,
                'rankingonly':rankingonly,
                }
            request.session['options'] = options
            form = DateRangeForm()
            deltaform = DeltaDaysForm()
        else:
            form = DateRangeForm()
            deltaform = DeltaDaysForm()
    else:
	form = DateRangeForm(initial={
	    'startdate': startdate,
	    'enddate': enddate,
	    })
	deltaform = DeltaDaysForm()
        optionsform = StatsOptionsForm()

    try:
	r2 = getrower(theuser)
        if rankingonly:
            rankingpiece = [True]
        else:
            rankingpiece = [True,False]
        
        waterinclude = False

        for ttype in types.otwtypes:
            if ttype in workouttypes:
                waterinclude = True

        if waterinclude:
            workoutsw = Workout.objects.filter(user=r2,
                                               startdatetime__gte=startdate,
                                               startdatetime__lte=enddate,
                                               workouttype='water',
                                               boattype__in='waterboattype',
                                               rankingpiece__in=rankingpiece,
            )
            workouttypes = [w for w in workouttypes if w != 'water']

        workoutse = Workout.objects.filter(user=r2,
                                           startdatetime__gte=startdate,
                                           startdatetime__lte=enddate,
                                           workouttype__in=workouttypes,
                                           rankingpiece__in=rankingpiece)
            
        if waterinclude:
            allergworkouts = workoutse | workoutsw
            allergworkouts = allergworkouts.distinct().order_by("-date", "-starttime")
        else:
            allergworkouts = workoutse.order_by("-date","-starttime")
            
        if waterinclude:
            for ttype in types.otwtypes:
                workouttypes.append(ttype)


	
    except Rower.DoesNotExist:
	allergworkouts = []
	r2=0

    try:
	u = User.objects.get(id=theuser)
    except User.DoesNotExist:
	u = ''

    ids = [int(workout.id) for workout in allergworkouts]

    datemapping = {
        w.id:w.date for w in allergworkouts
        }

    
    
    fieldlist,fielddict = dataprep.getstatsfields()
    
    # prepare data frame
    datadf,extracols = dataprep.read_cols_df_sql(ids,fieldlist)

    datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)

    request.session['rowerid'] = r.id
    
    if datadf.empty:
        stats = {}
        plotfield = 'spm'
        cordict = {}
        div = "No Data found"
        script = ''
        
        response = render(request,
		          'cumstats.html',
		          {
                              'stats':stats,
                              'teams':get_my_teams(request.user),
                              'options':options,
		              'id':theuser,
		              'theuser':u,
		              'startdate':startdate,
		              'enddate':enddate,
		              'form':form,
		              'deltaform':deltaform,
                              'optionsform':optionsform,
                              'cordict':cordict,
                              'plotscript':script,
                              'plotdiv':div,
                              'plotfield':plotfield,
                          })

        request.session['options'] = options
        
        return response



    # Create stats
    stats = {}
    fielddict.pop('workoutstate')
    fielddict.pop('workoutid')

    for field,verbosename in fielddict.iteritems():
        thedict = {
            'mean':datadf[field].mean(),
            'min': datadf[field].min(),
            'std': datadf[field].std(),
            'max': datadf[field].max(),
            'median': datadf[field].median(),
            'firstq':datadf[field].quantile(q=0.25),
            'thirdq':datadf[field].quantile(q=0.75),
            'verbosename':verbosename,
        }
        stats[field] = thedict

    # Create a dict with correlation values
    cor = datadf.corr(method='spearman')
    cor.fillna(value=0,inplace=True)
    cordict = {}
    for field1,verbosename in fielddict.iteritems():
        thedict = {}
        for field2,verbosename in fielddict.iteritems():
            try:
                thedict[field2] = cor.ix[field1,field2]
            except KeyError:
                thedict[field2] = 0

        cordict[field1] = thedict

    # interactive box plot
    datadf['workoutid'].replace(datemapping,inplace=True)
    datadf.rename(columns={"workoutid":"date"},inplace=True)
    datadf = datadf.sort_values(['date'])
    script,div = interactive_boxchart(datadf,plotfield)
    
    # set options form correctly
    initial = {}
    initial['includereststrokes'] = includereststrokes
    initial['waterboattype'] = waterboattype
    initial['rankingonly'] = rankingonly

    for wtype in types.checktypes:
        if wtype in workouttypes:
            initial[wtype] = True
        else:
            initial[wtype] = False


    optionsform = StatsOptionsForm(initial=initial)
            
    response = render(request,
		  'cumstats.html',
		  {
                      'stats':stats,
                      'teams':get_my_teams(request.user),
                      'options':options,
		      'id':theuser,
		      'theuser':u,
		      'startdate':startdate,
		      'enddate':enddate,
		      'form':form,
		      'deltaform':deltaform,
                      'optionsform':optionsform,
                      'cordict':cordict,
                      'plotscript':script,
                      'plotdiv':div,
                      'plotfield':plotfield,
                  })

    request.session['options'] = options

    return response

# Stats page
@login_required()
def workout_stats_view(request,id=0,message="",successmessage=""):

    r = getrower(request.user)
    w = get_workout(id)

    workstrokesonly = True
    if request.method == 'POST' and 'workstrokesonly' in request.POST:
        workstrokesonly = str2bool(request.POST['workstrokesonly'])


    # prepare data frame
    datadf,row = dataprep.getrowdata_db(id=id)
    if (checkworkoutuser(request.user,row)==False):
        message = "You are not allowed to see the stats of this workout"
        messages.error(request,message)
        url = reverse(workouts_view)
        return HttpResponseRedirect(url)

    datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
        
    if datadf.empty:
        datadf,row = dataprep.getrowdata_db(id=id)
        datadf = dataprep.clean_df_stats(datadf,workstrokesonly=False)
        workstrokesonly=False
        if datadf.empty:
            return HttpResponse("CSV data file not found")

    #datadf['deltat'] = datadf['time'].diff()
        
        
    workoutstateswork = [1,4,5,8,9,6,7]
    workoutstatesrest = [3]
    workoutstatetransition = [0,2,10,11,12,13]


    # Create stats
    stats = {}

    fieldlist,fielddict = dataprep.getstatsfields()
    fielddict.pop('workoutstate')
    fielddict.pop('workoutid')
    
    for field,verbosename in fielddict.iteritems():
        thedict = {
            'mean':datadf[field].mean(),
            'wmean': wavg(datadf, field, 'deltat'),
            'min': datadf[field].min(),
            'std': datadf[field].std(),
            'max': datadf[field].max(),
            'median': datadf[field].median(),
            'firstq':datadf[field].quantile(q=0.25),
            'thirdq':datadf[field].quantile(q=0.75),
            'verbosename':verbosename,
        }
        stats[field] = thedict

    # Create a dict with correlation values
    cor = datadf.corr(method='spearman')
    cor.fillna(value=0,inplace=True)
    cordict = {}
    for field1,verbosename in fielddict.iteritems():
        thedict = {}
        for field2,verbosename in fielddict.iteritems():
            try:
                thedict[field2] = cor.ix[field1,field2]
            except KeyError:
                thedict[field2] = 0

            cordict[field1] = thedict

    # additional non-automated stats
    otherstats = {}

    # Normalized power & TSS
    tss,normp = dataprep.workout_rscore(w)


    if not np.isnan(tss) and tss != 0:
        otherstats['tss'] = {
            'verbose_name':'rScore',
            'value':int(tss),
            'unit':''
        }
    
    if not np.isnan(normp):
        otherstats['np'] = {
            'verbose_name':'rPower',
            'value':int(10*normp)/10.,
            'unit':'Watt'
        }
        
    # HR Drift
    tmax = datadf['time'].max()
    tmin = datadf['time'].min()
    thalf = tmin+0.5*(tmax-tmin)
    mask1 = datadf['time'] < thalf
    mask2 = datadf['time'] > thalf

    hr1 = datadf.loc[mask1,'hr'].mean()
    hr2 = datadf.loc[mask2,'hr'].mean()
            
    pwr1 = datadf.loc[mask1,'power'].mean()
    pwr2 = datadf.loc[mask2,'power'].mean()

    try:
        hrdrift = ((pwr1/hr1)-(pwr2/hr2))/(pwr1/hr1)
        hrdrift *= 100.
        if not np.isnan(hrdrift):
            hrdrift = int(100*hrdrift)/100.
            otherstats['hrdrift'] = {
                'verbose_name': 'Heart Rate Drift',
                'value': hrdrift,
                'unit': '%',
            }
    except ZeroDivisionError,ValueError:
        pass

    # TRIMP
    trimp,hrtss = dataprep.workout_trimp(w)

    otherstats['trimp'] = {
        'verbose_name': 'TRIMP',
        'value': trimp,
        'unit': ''
    }

    otherstats['hrScore'] = {
        'verbose_name': 'rScore (HR)',
        'value': hrtss,
        'unit':''
        }

    return render(request,
		  'workoutstats.html',
		  {
                      'stats':stats,
                      'teams':get_my_teams(request.user),
                      'workout':row,
                      'workstrokesonly':workstrokesonly,
                      'cordict':cordict,
                      'otherstats':otherstats,
                  })
    
# The Advanced edit page
@login_required()
def workout_advanced_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

#    form = WorkoutForm(instance=row)
    g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
    for i in g:
        try:
            width,height = Image.open(i.filename).size
            i.width = width
            i.height = height
            i.save()
        except:
            pass

    # check if user is owner of this workout

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)


    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)

    # create interactive plot
    try:
	res = interactive_chart(id,promember=1)
	script = res[0]
	div = res[1]
    except ValueError:
	pass

    messages.error(request,message)
    messages.info(request,successmessage)


    if row.workouttype in types.otwtypes:
	return render(request,
		  'advancedotw.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'interactiveplot':script,
		   'the_div':div})
    else:
	return render(request,
		  'advancededit.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'interactiveplot':script,
		   'the_div':div})

# The interactive plot comparing two workouts (obsolete version)
def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'):
    promember=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    # create interactive plot
    res = interactive_comparison_chart(id1,id2,xparam=xparam,yparam=yparam,
				       promember=promember)
    script = res[0]
    div = res[1]

    axchoicesbasic = {ax[0]:ax[1] for ax in axes if ax[4]=='basic'}
    axchoicespro = {ax[0]:ax[1] for ax in axes if ax[4]=='pro'}
    noylist = ["time","distance"]
    axchoicesbasic.pop("cumdist")

    return render(request,
		  'comparisonchart.html',
		  {'interactiveplot':script,
		   'the_div':div,
                   'teams':get_my_teams(request.user),
		   'id1':id1,
		   'id2':id2,
                   'axchoicesbasic':axchoicesbasic,
                   'axchoicespro':axchoicespro,
                   'noylist':noylist,
		   'xparam':xparam,
		   'yparam':yparam,
		   })

# Updated version of comparison plot	
def workout_comparison_view2(request,id1=0,id2=0,xparam='distance',
			    yparam='spm',plottype='line'):
    promember=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1

    if not Workout.objects.filter(id=id1).exists() or not Workout.objects.filter(id=id2).exists():
        raise Http404("Workout doesn't exist")
        
    # create interactive plot
    res = interactive_comparison_chart(id1,id2,xparam=xparam,yparam=yparam,
				       promember=promember,plottype=plottype)
    script = res[0]
    div = res[1]

    axchoicesbasic = {ax[0]:ax[1] for ax in axes if ax[4]=='basic'}
    axchoicespro = {ax[0]:ax[1] for ax in axes if ax[4]=='pro'}
    noylist = ["time","distance"]
    axchoicesbasic.pop("cumdist")

    row1 = Workout.objects.get(id=id1)
    row2 = Workout.objects.get(id=id2)

    mayedit = 0
    if request.user == row1.user.user:
        mayedit=1
    if checkworkoutuser(request.user,row1):
        mayedit=1

    if row1.workouttype != 'water' or row2.workouttype != 'water':
        axchoicespro.pop('slip')
        axchoicespro.pop('wash')
        axchoicespro.pop('catch')
        axchoicespro.pop('finish')
        axchoicespro.pop('totalangle')
        axchoicespro.pop('effectiveangle')
        axchoicespro.pop('peakforceangle')
        
    
    return render(request,
		  'comparisonchart2.html',
		  {'interactiveplot':script,
		   'the_div':div,
                   'teams':get_my_teams(request.user),
		   'id1':id1,
		   'id2':id2,
                   'mayedit':mayedit,
                   'axchoicesbasic':axchoicesbasic,
                   'axchoicespro':axchoicespro,
                   'noylist':noylist,
		   'xparam':xparam,
		   'yparam':yparam,
		   'plottype':plottype,
		   'promember':promember,
		   })

# Change default landing page
@login_required()
def workflow_default_view(request):
    r = getrower(request.user)
    if r.defaultlandingpage == 'workout_edit_view':
        r.defaultlandingpage = 'workout_workflow_view'
    else:
        r.defaultlandingpage = 'workout_edit_view'

    r.save()

    url = reverse(workout_workflow_config2_view)
    
    return HttpResponseRedirect(url)


# Workflow Configuration
@login_required()
def workout_workflow_config_view(request):
    request.session['referer'] = absolute(request)['PATH']
    request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
    try:
        workoutid = request.session['lastworkout']
    except KeyError:
        workoutid = 0
        
        
    r = getrower(request.user)

    if request.method == 'POST' and 'leftpanel' in request.POST:
        formleft = WorkFlowLeftPanelForm(request.POST)
        if formleft.is_valid():
            leftpanel = formleft.cleaned_data['leftpanel']
            r.workflowleftpanel = leftpanel
            r.save()
    if request.method == 'POST' and 'middlepanel' in request.POST:
        formmiddle = WorkFlowMiddlePanelForm(request.POST)
        if formmiddle.is_valid():
            middlepanel = formmiddle.cleaned_data['middlepanel']
            r.workflowmiddlepanel = middlepanel
            r.save()

    
    formleft = WorkFlowLeftPanelForm(instance=r)
    formmiddle = WorkFlowMiddlePanelForm(instance=r)

    tmplt = 'workflowconfig.html'

        
    return render(request,tmplt,
                  {
                      'rower':r,
                      'formleft':formleft,
                      'formmiddle':formmiddle,
                      'workoutid': workoutid,
                      })

@login_required()
def workout_workflow_config2_view(request):
    request.session['referer'] = absolute(request)['PATH']
    request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
    try:
        workoutid = request.session['lastworkout']
    except KeyError:
        workoutid = 0
        
        
    r = getrower(request.user)

    MiddlePanelFormSet = formset_factory(WorkFlowMiddlePanelElement,extra=1)
    LeftPanelFormSet = formset_factory(WorkFlowLeftPanelElement,extra=1)
    

    if request.method == 'POST':
        wasmiddle =  [1 for key,value in request.POST.items() if 'middlepanel' in key.lower()]
        wasleft = [1 for key,valye in request.POST.items() if 'leftpanel' in key.lower()]
        if wasmiddle:
            middlepanel_formset = MiddlePanelFormSet(request.POST,
                                                     prefix='middlepanel')
            newmiddlepanel = []
            if middlepanel_formset.is_valid():
                for form in middlepanel_formset:
                    value = form.cleaned_data.get('panel')
                    if value != 'None':
                        newmiddlepanel.append(value)


                newmiddlepanel = [i for i in newmiddlepanel if i != None]
                r.workflowmiddlepanel = newmiddlepanel
                try:
                    r.save()
                except IntegrityError:
                    messages.error(request,'Something went wrong')
        if wasleft:
            leftpanel_formset = LeftPanelFormSet(request.POST,
                                                     prefix='leftpanel')
            newleftpanel = []
            if leftpanel_formset.is_valid():
                for form in leftpanel_formset:
                    value = form.cleaned_data.get('panel')
                    if value != 'None':
                        newleftpanel.append(value)


                newleftpanel = [i for i in newleftpanel if i != None]
                r.workflowleftpanel = newleftpanel
                try:
                    r.save()
                except IntegrityError:
                    messages.error(request,'Something went wrong')
                
    leftpanelform_data = [{'panel':panel}
                          for panel in r.workflowleftpanel]

    
    middlepanelform_data = [{'panel':panel}
                          for panel in r.workflowmiddlepanel]

    leftpanel_formset = LeftPanelFormSet(initial=leftpanelform_data,
                                         prefix='leftpanel')
    middlepanel_formset = MiddlePanelFormSet(initial=middlepanelform_data,
                                             prefix='middlepanel')
    
    
    tmplt = 'workflowconfig2.html'

    return render(request,tmplt,
                  {
                      'rower':getrower(request.user),
                      'leftpanel_formset':leftpanel_formset,
                      'middlepanel_formset':middlepanel_formset,
                      'workoutid': workoutid,
                      })


# Workflow View
@login_required()
def workout_workflow_view(request,id):
    request.session['referer'] = absolute(request)['PATH']
    request.session['lastworkout'] = id
    request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
    row = get_workout_permitted(request.user,id)
    
    r = getrower(request.user)
    result = request.user.is_authenticated() and ispromember(request.user)
    if result:
	promember=1
    if request.user == row.user.user:
	mayedit=1

    comments = WorkoutComment.objects.filter(workout=row)

    aantalcomments = len(comments)

    workouttype = 'ote'
    if row.workouttype in types.otwtypes:
        workouttype = 'otw'

    try:
        favorites = FavoriteChart.objects.filter(user=r,
                                           workouttype__in=[workouttype,'both']).order_by("id")
        maxfav = len(favorites)-1
    except:
        favorites = None
        maxfav = 0

    charts = get_call()


    if 'panel_map.html' in r.workflowmiddlepanel and rowhascoordinates(row):
        rowdata = rdata(row.csvfilename)
        mapscript,mapdiv = leaflet_chart2(rowdata.df[' latitude'],
                                          rowdata.df[' longitude'],
                                          row.name)
    else:
        mapscript = ''
        mapdiv = ''

        

    statcharts = GraphImage.objects.filter(workout=row)
        

    middleTemplates = []
    for t in r.workflowmiddlepanel:
        try:
            template.loader.get_template(t)
            middleTemplates.append(t)
        except template.TemplateDoesNotExist:
            pass

    leftTemplates = []
    for t in r.workflowleftpanel:
        try:
            template.loader.get_template(t)
            leftTemplates.append(t)
        except template.TemplateDoesNotExist:
            pass

    
    return render(request,
                  'workflow.html',
                  {
                      'middleTemplates':middleTemplates,
                      'leftTemplates':leftTemplates,
                      'charts':charts,
                      'workout':row,
                      'mapscript':mapscript,
                      'mapdiv':mapdiv,
                      'statcharts':statcharts,
                      'rower':r,
                      'aantalcomments':aantalcomments,
                  })

# The famous flex chart
def workout_flexchart3_view(request,*args,**kwargs):
    
    try:
        id = kwargs['id']
    except KeyError:
        return HttpResponse("Invalid workout number")
    
    if 'promember' in kwargs:
        promember = kwargs['promember']
    else:
        promember = 0

    try:
        favoritenr = int(request.GET['favoritechart'])
    except:
        favoritenr = -1
        
    row = get_workout(id)

    promember=0
    mayedit=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1
	if request.user == row.user.user:
	    mayedit=1
        if checkworkoutuser(request.user,row):
            mayedit=1

    workouttype = 'ote'
    if row.workouttype in types.otwtypes:
        workouttype = 'otw'

    try:
        favorites = FavoriteChart.objects.filter(user=r,
                                                 workouttype__in=[workouttype,'both']).order_by("id")
        maxfav = len(favorites)-1
    except:
        favorites = None
        maxfav = 0

    # check if favoritenr is not out of range
    if favorites:
        try:
            t = favorites[favoritenr].xparam
        except IndexError:
            favoritenr=0
        except AssertionError:
            favoritenr=0
        
    if 'xparam' in kwargs:
        xparam = kwargs['xparam']
    else:
        if favorites:
            xparam = favorites[favoritenr].xparam
        else:
            xparam = 'distance'

    if 'yparam1' in kwargs:
        yparam1 = kwargs['yparam1']
    else:
        if favorites:
            yparam1 = favorites[favoritenr].yparam1
        else:
            yparam1 = 'pace'
            
    if 'yparam2' in kwargs:
        yparam2 = kwargs['yparam2']
        if yparam2 == '':
            yparam2 = 'None'
    else:
        if favorites:
            yparam2 = favorites[favoritenr].yparam2
            if yparam2 == '':
                yparam2 = 'None'
        else:
            yparam2 = 'hr'

    if not request.user.is_anonymous():
        r = getrower(request.user)
        if favoritenr>=0 and r.showfavoritechartnotes:
            try:
                favoritechartnotes = favorites[favoritenr].notes
            except IndexError:
                favoritechartnotes = ''
        else:
            favoritechartnotes = ''
    else:
        favoritechartnotes = ''
        favoritenr = 0
        
    if 'plottype' in kwargs:
        plottype = kwargs['plottype']
    else:
        if favorites:
            plottype = favorites[favoritenr].plottype
        else:
            plottype = 'line'

    if 'workstrokesonly' in kwargs:
        workstrokesonly = kwargs['workstrokesonly']
    else:
        if favorites:
            workstrokesonly = not favorites[favoritenr].reststrokes
        else:
            workstrokesonly = False
            
    if request.method == 'POST' and 'savefavorite' in request.POST:
        if not request.user.is_anonymous():
            workstrokesonly = request.POST['workstrokesonlysave']
            reststrokes = not workstrokesonly
	    r = getrower(request.user)
            try:
                range = metrics.yaxmaxima[xparam]
                if yparam1 is not None:
                    range = metrics.yaxmaxima[yparam1]
                if yparam2 is not None:
                    range = metrics.yaxmaxima[yparam2]
                f = FavoriteChart(user=r,xparam=xparam,
                              yparam1=yparam1,yparam2=yparam2,
                              plottype=plottype,workouttype=workouttype,
                              reststrokes=reststrokes)
                f.save()
                
            except KeyError:
                messages.error(request,'We cannot save the ad hoc metrics in a favorite chart')

    if request.method == 'POST' and 'workstrokesonly' in request.POST:
	workstrokesonly = request.POST['workstrokesonly']
	if workstrokesonly == 'True':
	    workstrokesonly = True
	else:
	    workstrokesonly = False

    if not promember:
        for name,d in rowingmetrics:
            if d['type'] != 'basic':
                if xparam == name:
                    xparam = 'time'
                    messages.info(request,'To use '+d['verbose_name']+', you have to be Pro member')
                if yparam1 == name:
                    yparam1 = 'pace'
                    messages.info(request,'To use '+d['verbose_name']+', you have to be Pro member')
                if yparam2 == name:
                    yparam2 = 'spm'
                    messages.info(request,'To use '+d['verbose_name']+', you have to be Pro member')

    # bring back slashes
    yparam1 = yparam1.replace('_slsh_','/')
    yparam2 = yparam2.replace('_slsh_','/')
    xparam = xparam.replace('_slsh_','/')

    # create interactive plot
    try:
        (
            script,
            div,
            js_resources,
            css_resources,
            workstrokesonly
        ) = interactive_flex_chart2(
            id,xparam=xparam,yparam1=yparam1,
	    yparam2=yparam2,
	    promember=promember,plottype=plottype,
            workstrokesonly=workstrokesonly
        )
    except ValueError:
        (
            script,
            div,
            js_resources,
            css_resources,
            workstrokesonly
        ) = interactive_flex_chart2(
            id,xparam=xparam,yparam1=yparam1,
	    yparam2=yparam2,
	    promember=promember,plottype=plottype,
	    workstrokesonly=workstrokesonly
        )
        js_resources = ""
        css_resources = ""

        
    axchoicesbasic = {ax[0]:ax[1] for ax in axes if ax[4]=='basic'}
    axchoicespro = {ax[0]:ax[1] for ax in axes if ax[4]=='pro'}
    noylist = ["time","distance"]
    axchoicesbasic.pop("cumdist")
    
    if row.workouttype in types.otwtypes:
        for name,d in rowingmetrics:
            if d['mode'] == 'erg':
                axchoicespro.pop(name)

    else:
        for name,d in rowingmetrics:
            if d['mode'] == 'water':
                axchoicespro.pop(name)

    from rowers.metrics import nometrics
    
    rowdata = rdata(row.csvfilename)
    try:
        rowdata.set_instroke_metrics()
    except AttributeError:
        pass
    try:
        additionalmetrics = rowdata.get_additional_metrics()
        additionalmetrics = [m for m in additionalmetrics if not m in nometrics]
    except AttributeError:
        additionalmetrics = []


    extrametrics = {m.replace('/','_slsh_'):m for m in additionalmetrics}

    xparam = xparam.replace('/','_slsh_')
    yparam1 = yparam1.replace('/','_slsh_')
    yparam2 = yparam2.replace('/','_slsh_')


    for metric in nometrics:
        try:
            extrametrics.pop(metric)
        except KeyError:
            pass

    return render(request,
		  'flexchart3otw.html',
		  {'the_script':script,
		   'the_div':div,
		   'js_res': js_resources,
		   'css_res':css_resources,
		   'teams':get_my_teams(request.user),
                   'id':int(id),
		   'xparam':xparam,
		   'yparam1':yparam1,
		   'yparam2':yparam2,
		   'plottype':plottype,
                   'axchoicesbasic':axchoicesbasic,
                   'axchoicespro':axchoicespro,
                   'extrametrics':extrametrics,
                   'favoritechartnotes':favoritechartnotes,
                   'noylist':noylist,
		   'mayedit':mayedit,
		   'promember':promember,
		   'workstrokesonly': not workstrokesonly,
                   'favoritenr':favoritenr,
                   'maxfav':maxfav,
		  })
	

# The interactive plot with the colored Heart rate zones
def workout_biginteractive_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

    # check if user is owner of this workout


    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    # r = getrower(u)

    promember=0
    mayedit=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1
	if request.user == row.user.user:
	    mayedit=1


    # create interactive plot
    res = interactive_bar_chart(id,promember=promember)
    script = res[0]
    div = res[1]

    messages.error(request,message)
    messages.info(request,successmessage)


    return render(request,
		  'biginteractive1.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'interactiveplot':script,
		   'the_div':div,
		   'promember':promember,
		   'mayedit':mayedit})

# The interactive plot with wind corrected pace for OTW outings
def workout_otwpowerplot_view(request,id=0,message="",successmessage=""):
    row = get_workout(id)

    # check if user is owner of this workout


    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    # r = getrower(u)

    promember=0
    mayedit=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1
	if request.user == row.user.user:
	    mayedit=1

    # create interactive plot
    res = interactive_otw_advanced_pace_chart(id,promember=promember)
    script = res[0]
    div = res[1]

    messages.error(request,message)
    messages.info(request,successmessage)

    return render(request,
		  'otwinteractive.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
		   'interactiveplot':script,
		   'the_div':div,
		   'mayedit':mayedit})

# the page where you can choose where to export this workout
@login_required()
def workout_export_view(request,id=0, message="", successmessage=""):
    request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
    row = get_workout(id)

    try:
	thetoken = c2_open(request.user)
    except C2NoTokenError:
        thetoken = 0

    if (checkworkoutuser(request.user,row)) and thetoken:
        c2userid = c2stuff.get_userid(thetoken)
    else:
        c2userid = 0

    try:
        rktoken = runkeeper_open(request.user)
    except RunKeeperNoTokenError:
        rktoken = 0
        
    if (checkworkoutuser(request.user,row)) and rktoken:
        rkuserid = runkeeperstuff.get_userid(rktoken)
    else:
        rkuserid = 0
        
        
#    form = WorkoutForm(instance=row)
    g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
    for i in g:
        try:
            width,height = Image.open(i.filename).size
            i.width = width
            i.height = height
            i.save()
        except:
            pass

    # check if user is owner of this workout

    if (checkworkoutuser(request.user,row)==False):
	message = "You are not allowed to edit this workout"
        messages.error(request,message)
	url = reverse(workouts_view)

	return HttpResponseRedirect(url)

    messages.error(request,message)
    messages.info(request,successmessage)

    return render(request,
		  'export.html',
		  {'workout':row,
                   'teams':get_my_teams(request.user),
                   'c2userid':c2userid,
                   'rkuserid':rkuserid,
		  })

#
@login_required()
def workout_unsubscribe_view(request,id=0):
    w = get_workout(id)

    if w.privacy == 'private' and w.user.user != request.user:
	return HttpResponseForbidden("Permission error")

    comments = WorkoutComment.objects.filter(workout=w,
                                             user=request.user).order_by("created")

    for c in comments:
        c.notification = False
        c.save()

    form = WorkoutCommentForm()

    successmessage = 'You have been unsubscribed from new comment notifications for this workout'
    
    messages.info(request,successmessage)

    return render(request,
                  'workout_comments.html',
                  {'workout':w,
                   'teams':get_my_teams(request.user),
                   'comments':comments,
                   'form':form,
                   })

        
# list of comments to a workout
@login_required()
def workout_comment_view(request,id=0):
    w = get_workout(id)

    if w.privacy == 'private' and w.user.user != request.user:
	return HttpResponseForbidden("Permission error")

    comments = WorkoutComment.objects.filter(workout=w).order_by("created")

    # ok we're permitted
    if request.method == 'POST':
        r = w.user
        form = WorkoutCommentForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            comment = cd['comment']
            comment = bleach.clean(comment)
            if isinstance(comment,unicode):
                comment = comment.encode('utf8')
            elif isinstance(comment, str):
                comment = comment.decode('utf8')

            notification = cd['notification']
            c = WorkoutComment(workout=w,user=request.user,comment=comment,
                               notification=notification)
            c.save()
            url = reverse(workout_comment_view,
                          kwargs={
                              'id':id
                              })
            message = '{name} says: <a href="{url}">{comment}</a>'.format(
                name = request.user.first_name,
                comment = comment,
                url = url,
            )
            if request.user != r.user:    
                a_messages.info(r.user,message.encode('ascii','ignore'))

            res = myqueue(queuehigh,
                          handle_sendemailnewcomment,r.user.first_name,
			  r.user.last_name,
			  r.user.email,
                          request.user.first_name,
                          request.user.last_name,
                          comment,w.name,w.id,
                          emailbounced = r.emailbounced
            )
                
            commenters = {oc.user for oc in comments if oc.notification}
            for u in commenters:
                a_messages.info(u,message)
                if u != request.user and u != r.user:
                    ocr = Rower.objects.get(user=u)
                    res = myqueue(queuelow,
                                  handle_sendemailnewresponse,
                                  u.first_name,
                                  u.last_name,
                                  u.email,
                                  request.user.first_name,
                                  request.user.last_name,
                                  comment,
                                  w.name,
                                  w.id,
                                  c.id,
                                  emailbounced = ocr.emailbounced
                    )

        url = reverse(workout_comment_view,kwargs = {
        'id':id})
        return HttpResponseRedirect(url)
                
    form = WorkoutCommentForm()

    g = GraphImage.objects.filter(workout=w).order_by("-creationdatetime")
    for i in g:
        try:
            width,height = Image.open(i.filename).size
            i.width = width
            i.height = height
            i.save()
        except:
            pass


    if (len(g)<=3):
        return render(request,
                      'workout_comments.html',
                      {'workout':w,
                       'teams':get_my_teams(request.user),
		       'graphs1':g[0:3],
                       'comments':comments,
                       'form':form,
                      })
    else:
        return render(request,
                      'workout_comments.html',
                      {'workout':w,
                       'teams':get_my_teams(request.user),
		       'graphs1':g[0:3],
		       'graphs1':g[3:6],
                       'comments':comments,
                       'form':form,
                      })

# for ajax calls
def course_map_view(request,id=0):
    if id != 0:
        try:
            course = GeoCourse.objects.get(id=id)
        except GeoCourse.DoesNotExist:
            return Http404("Course doesn't exist")

        script,div = course_map(course)

        return render(request,
                      'coursemap.html',
                      {
                          'mapdiv':div,
                          'mapscript':script
                          })

    else:
        return ""
    
@login_required()
def course_replace_view(request,id=0):
    try:
        course = GeoCourse.objects.get(id=id)
    except GeoCourse.DoesNotExist:
        return Http404("Course doesn't exist")

    r = getrower(request.user)
    
    if course.manager != r:
        raise PermissionDenied("Access denied")

    thecourses = GeoCourse.objects.filter(manager=r).exclude(id=id)

    if request.method == 'POST':
        form = CourseSelectForm(request.POST)
        if form.is_valid():
            course2 = form.cleaned_data['course']
            res = courses.replacecourse(course,course2)

            url =  reverse(course_view,
                           kwargs = {
                               'id':course2.id
                               })

            return HttpResponseRedirect(url)
    else:

        form = CourseSelectForm()
        form.fields["course"].queryset = thecourses

    script,div = course_map(course)

    return render(request,
                  'course_replace.html',
                  {'course':course,
                   'mapdiv':div,
                   'mapscript':script,
                   'form':form})
    
@login_required()
def course_delete_view(request,id=0):
    try:
        course = GeoCourse.objects.get(id=id)
    except GeoCourse.DoesNotExist:
        return Http404("Course doesn't exist")

    r = getrower(request.user)
    
    if course.manager != r:
        raise PermissionDenied("Access denied")

    ps = PlannedSession.objects.filter(course=course)
    nosessions = len(ps) == 0

    if nosessions:
        course.delete()

    url = reverse(courses_view)

    return HttpResponseRedirect(url)
    
@login_required()
def course_edit_view(request,id=0):
    try:
        course = GeoCourse.objects.get(id=id)
    except GeoCourse.DoesNotExist:
        return Http404("Course doesn't exist")

    r = getrower(request.user)
    
    if course.manager != r:
        raise PermissionDenied("Access denied")

    ps = PlannedSession.objects.filter(course=course)
    nosessions = len(ps) == 0
    
    script,div = course_map(course)

    if request.method == 'POST':
        form = GeoCourseEditForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            country = form.cleaned_data['country']
            notes = form.cleaned_data['notes']
            if isinstance(name,unicode):
                name = name.encode('utf8')
            elif isinstance(name, str):
                name = name.decode('utf8')
            
            course.name = name
            course.country = country
            course.notes = notes
            course.save()

    form = GeoCourseEditForm(instance=course)
    
    return render(request, 'course_edit_view.html',
                  {
                      'course':course,
                      'mapscript':script,
                      'mapdiv':div,
                      'nosessions':nosessions,
                      'rower':r,
                      'form':form,
                      }
                  )

@login_required()
def course_view(request,id=0):
    try:
        course = GeoCourse.objects.get(id=id)
    except GeoCourse.DoesNotExist:
        return Http404("Course doesn't exist")

    r = getrower(request.user)
    
    script,div = course_map(course)
    
    return render(request, 'course_view.html',
                  {
                      'course':course,
                      'mapscript':script,
                      'mapdiv':div,
                      'nosessions':False,
                      'rower':r,
                      }
                  )

        
# The basic edit page
@login_required()
def workout_edit_view(request,id=0,message="",successmessage=""):
    request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
    request.session['referer'] = absolute(request)['PATH']


    row = get_workout(id)

    form = WorkoutForm(instance=row)

    if request.method == 'POST':
	# Form was submitted
	form = WorkoutForm(request.POST)
	if form.is_valid():
	    # Get values from form
	    name = form.cleaned_data['name']
	    date = form.cleaned_data['date']
	    starttime = form.cleaned_data['starttime']
	    workouttype = form.cleaned_data['workouttype']
            weightcategory = form.cleaned_data['weightcategory']
	    duration = form.cleaned_data['duration']
	    distance = form.cleaned_data['distance']
            private = form.cleaned_data['private']
	    notes = form.cleaned_data['notes']
            thetimezone = form.cleaned_data['timezone']
            
            try:
                boattype  = request.POST['boattype']
            except KeyError:
                boattype = Workout.objects.get(id=id).boattype
            try:
                privacy = request.POST['privacy']
            except KeyError:
                privacy = Workout.objects.get(id=id).privacy
            try:
                rankingpiece = form.cleaned_data['rankingpiece']
            except KeyError:
                rankingpiece =- Workout.objects.get(id=id).rankingpiece

            if private:
                privacy = 'private'
            else:
                privacy = 'visible'
                
            startdatetime = datetime.datetime.combine(
                date,starttime
                )

            startdatetime = pytz.timezone(thetimezone).localize(
                startdatetime
                )

            try:
                # aware object can be in any timezone
                out = startdatetime.astimezone(pytz.utc)
            except (ValueError, TypeError):
	        startdatetime = timezone.make_aware(startdatetime)
                
            startdatetime = startdatetime.astimezone(pytz.timezone(thetimezone))


            # check if user is owner of this workout
            if checkworkoutuser(request.user,row):
                row.name  = name
                row.date = date
                row.starttime = starttime
                row.startdatetime = startdatetime
                row.workouttype = workouttype
                row.weightcategory = weightcategory
                row.notes = notes
                row.duration = duration
                row.distance = distance
                row.boattype = boattype
                row.privacy = privacy
                row.rankingpiece = rankingpiece
                row.timezone = thetimezone
                try:
                    row.save()
                except IntegrityError:
                    pass
                # change data in csv file

                r = rdata(row.csvfilename)
                if r == 0:
                    return HttpResponse("Error: CSV Data File Not Found")
                r.rowdatetime = startdatetime
                r.write_csv(row.csvfilename,gzip=True)
                dataprep.update_strokedata(id,r.df)
                successmessage = "Changes saved"

                if rankingpiece:
                    dataprep.runcpupdate(row.user,type=row.workouttype)
                
                messages.info(request,successmessage)
                url = reverse(workout_edit_view,
                              kwargs = {
                                  'id':str(row.id),
                              })
                response = HttpResponseRedirect(url)
            else:
                message = "You are not allowed to change this workout"
                messages.error(request,message)
                url = reverse(workouts_view)

                response = HttpResponseRedirect(url)
                
    #else: # form not POSTed
    form = WorkoutForm(instance=row)

    row = get_workout(id)

    g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
    for i in g:
        try:
            width,height = Image.open(i.filename).size
            i.width = width
            i.height = height
            i.save()
        except:
            pass


    # check if user is owner of this workout

    comments = WorkoutComment.objects.filter(workout=row)

    aantalcomments = len(comments)

    if (checkworkoutuser(request.user,row)==False):
        raise PermissionDenied("Access denied")

    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)
    rowdata = rdata(f1)
    hascoordinates = 1
    if rowdata != 0:
        try:
            latitude = rowdata.df[' latitude']
            if not latitude.std():
                hascoordinates = 0
        except KeyError,AttributeError:
            hascoordinates = 0

    else:
        hascoordinates = 0


    if hascoordinates:
        mapscript,mapdiv = leaflet_chart(rowdata.df[' latitude'],
                                         rowdata.df[' longitude'],
                                         row.name)
                                        
        #res = googlemap_chart(rowdata.df[' latitude'],
        #                      rowdata.df[' longitude'],
        #                      row.name)
        #gmscript = res[0]
        #gmdiv = res[1]

    else:
        mapscript = ""
        mapdiv = ""


    # render page
    if (len(g)<=3):
        return render(request, 'workout_form.html',
                      {'form':form,
                       'workout':row,
                       'teams':get_my_teams(request.user),
                       'graphs1':g[0:3],
                       'mapscript':mapscript,
                       'aantalcomments':aantalcomments,
                       'mapdiv':mapdiv,
                       'rower':r,
                       })

    else:
        return render(request, 'workout_form.html',
                      {'form':form,
                       'teams':get_my_teams(request.user),
                       'workout':row,
                       'graphs1':g[0:3],
                       'graphs2':g[3:6],
                       'mapscript':mapscript,
                       'aantalcomments':aantalcomments,
                       'mapdiv':mapdiv,
                       'rower':r,
                       })


    return HttpResponseRedirect(url)

@login_required()
def workout_map_view(request,id=0):
    request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
    request.session['referer'] = absolute(request)['PATH']

    row = get_workout(id)

    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)
    rowdata = rdata(f1)
    hascoordinates = 1
    if rowdata != 0:
        try:
            latitude = rowdata.df[' latitude']
            if not latitude.std():
                hascoordinates = 0
        except KeyError,AttributeError:
            hascoordinates = 0

    else:
        hascoordinates = 0


    if hascoordinates:
        mapscript,mapdiv = leaflet_chart2(rowdata.df[' latitude'],
                                         rowdata.df[' longitude'],
                                         row.name)
    else:
        mapscript = ""
        mapdiv = ""
        
    mayedit=0
    if not request.user.is_anonymous():
	r = getrower(request.user)
	result = request.user.is_authenticated() and ispromember(request.user)
	if result:
	    promember=1
	if request.user == row.user.user:
	    mayedit=1

    return render(request, 'map_view.html',
                  {'mapscript':mapscript,
                   'workout':row,
                   'mapdiv':mapdiv,
                   'mayedit':mayedit,
                   })
        

# Image upload
@login_required()
def workout_uploadimage_view(request,id):
    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    r = getrower(request.user)

    w = get_workout(id)

    if not checkworkoutuser(request.user,w):
        raise PermissionDenied("You are not allowed to edit this workout")

    images = GraphImage.objects.filter(workout=w)

    
    if len(images) >= 6:
        message = "You have reached the maximum number of static images for this workout"
        messages.error(request,message)
        url = reverse(r.defaultlandingpage,
                      kwargs = {
                          'id':int(id),
                          })
        return HttpResponseRedirect(url)

    
    if request.method == 'POST':
        form = ImageForm(request.POST,request.FILES)

        if form.is_valid():
            f = form.cleaned_data['file']

            if f is not None:
                filename,path_and_filename = handle_uploaded_image(f)
                try:
                    width,height = Image.open(path_and_filename).size
                except:
                    message = "Not a valid image"
                    messages.error(request,message)
                    os.remove(path_and_filename)
                    url = reverse(workout_uploadimage_view,
                                  kwargs = {'id':id})

                    if is_ajax:
                        return JSONResponse({'result':0,'url':0})
                    else:
                        return HttpResponseRedirect(url)

                i = GraphImage(workout=w,
                               creationdatetime=timezone.now(),
                               filename = path_and_filename,
                               width=width,height=height)
                i.save()
                
                url = reverse(r.defaultlandingpage,
                              kwargs = {'id':id})
                if is_ajax:
                    return JSONResponse({'result':1,'url':url})
                else:
                    return HttpResponseRedirect(url)
            else:
                messages.error(request,'Something went wrong - no file attached')
                url = reverse(workout_uploadimage_view,
                              kwargs = {'id':id})

                if is_ajax:
                    return JSONResponse({'result':0,'url':0})
                else:
                    return HttpResponseRedirect(url)
        else:
            return HttpResponse("Form is not valid")

    else:
        if not is_ajax:
            form = ImageForm()
            return render(request,'image_form.html',
                          {'form':form,
                           'teams':get_my_teams(request.user),
                           'workout': w,
                           })
        else:
            return {'result':0}

# Image upload
@login_required()
def course_upload_view(request):
    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    r = getrower(request.user)
    
    if request.method == 'POST':
        form = CourseForm(request.POST,request.FILES)

        if form.is_valid():
            f = form.cleaned_data['file']
            name = form.cleaned_data['name']
            notes = form.cleaned_data['notes']
            if f is not None:
                filename,path_and_filename = handle_uploaded_file(f)
            
                cs = courses.kmltocourse(path_and_filename)

                for course in cs:
                    cname = name+' - '+course['name']
                    cnotes = notes+'\n\n'+course['description']
                    polygons = course['polygons']
                    
                    course = courses.createcourse(r,cname,polygons,notes=cnotes)
                    
                os.remove(path_and_filename)
                
                url = reverse(courses_view)
                if is_ajax:
                    return JSONResponse({'result':1,'url':url})
                else:
                    return HttpResponseRedirect(url)
            else:
                messages.error(request,'Something went wrong - no file attached')
                url = reverse(course_upload_view)

                if is_ajax:
                    return JSONResponse({'result':0,'url':0})
                else:
                    return HttpResponseRedirect(url)
        else:
            messages.error(request,'Form is not valid')
            return render(request,'course_form.html',
                          {'form':form,
                           })

    else:
        if not is_ajax:
            form = CourseForm()
            return render(request,'course_form.html',
                          {'form':form,
                           })
        else:
            return {'result':0}

                
                
# Generic chart creation
@login_required()
def workout_add_chart_view(request,id,plotnr=1):

    w = get_workout(id)

    plotnr = int(plotnr)
    
    if (checkworkoutuser(request.user,w)==False):
	raise PermissionDenied("You are not allowed add plots to this workout")
    else:
	f1 = w.csvfilename[6:-4] 
	timestr = strftime("%Y%m%d-%H%M%S")
	imagename = f1+timestr+'.png'
	u = w.user.user
	r = getrower(u)
        title = w.name
        res,jobid = uploads.make_plot(
            r,w,f1,w.csvfilename,'timeplot',title,plotnr=plotnr,
            imagename=imagename
        )
        if res == 0:
            messages.error(request,jobid)
        else:
            try:
                request.session['async_tasks'] += [(jobid,'make_plot')]
            except KeyError:
                request.session['async_tasks'] = [(jobid,'make_plot')]

    try:
        url = request.session['referer']
    except KeyError:
        url = "/rowers/workout/"+str(w.id)+"/edit"
    return HttpResponseRedirect(url)


# The page where you select which Strava workout to import
@login_required()
def workout_stravaimport_view(request,message=""):
    res = stravastuff.get_strava_workout_list(request.user)

    if (res.status_code != 200):
	if (res.status_code == 401):
	    r = getrower(request.user)
	    if (r.stravatoken == '') or (r.stravatoken is None):
		s = "Token doesn't exist. Need to authorize"
		return HttpResponseRedirect("/rowers/me/stravaauthorize/")
	message = "Something went wrong in workout_stravaimport_view"
        messages.error(request,message)
	if settings.DEBUG:
	    return HttpResponse(res)
	else:
	    url = reverse(workouts_view)
	    return HttpResponseRedirect(url)
    else:
        workouts = []
        r = getrower(request.user)
        stravaids = [int(item['id']) for item in res.json()]
        knownstravaids = uniqify([
            w.uploadedtostrava for w in Workout.objects.filter(user=r)
            ])
        newids = [stravaid for stravaid in stravaids if not stravaid in knownstravaids]
        
	for item in res.json():
            d = int(float(item['distance']))
            i = item['id']
            if i in knownstravaids:
                nnn = ''
            else:
                nnn = 'NEW'
            n = item['name']
            ttot = str(datetime.timedelta(seconds=int(float(item['elapsed_time']))))
            s = item['start_date']
            r = item['type']
            keys = ['id','distance','duration','starttime','type','name','new']
	    values = [i,d,ttot,s,r,n,nnn]
	    res = dict(zip(keys,values))
	    workouts.append(res)

        
	return render(request,'strava_list_import.html',
		      {'workouts':workouts,
                       'teams':get_my_teams(request.user),
		       })

    return HttpResponse(res)

# The page where you select which RunKeeper workout to import
@login_required()
def workout_runkeeperimport_view(request,message=""):
    res = runkeeperstuff.get_runkeeper_workout_list(request.user)
    if (res.status_code != 200):
	if (res.status_code == 401):
	    r = getrower(request.user)
	    if (r.runkeepertoken == '') or (r.runkeepertoken is None):
		s = "Token doesn't exist. Need to authorize"
		return HttpResponseRedirect("/rowers/me/runkeeperauthorize/")
	message = "Something went wrong in workout_runkeeperimport_view"
        messages.error(request,message)

	if settings.DEBUG:
	    return HttpResponse(res)
	else:
	    url = reverse(workouts_view)
	    return HttpResponseRedirect(url)
    else:
	workouts = []
	for item in res.json()['items']:
	    d = int(float(item['total_distance']))
	    i = getidfromsturi(item['uri'],length=9)
	    ttot = str(datetime.timedelta(seconds=int(float(item['duration']))))
	    s = item['start_time']
	    r = item['type']
	    keys = ['id','distance','duration','starttime','type']
	    values = [i,d,ttot,s,r]
	    res = dict(zip(keys,values))
	    workouts.append(res)
	return render(request,'runkeeper_list_import.html',
		      {'workouts':workouts,
                       'teams':get_my_teams(request.user),
		       })

    return HttpResponse(res)

# The page where you select which RunKeeper workout to import
@login_required()
def workout_underarmourimport_view(request,message=""):
    res = underarmourstuff.get_underarmour_workout_list(request.user)
    if (res.status_code != 200):
	if (res.status_code == 401):
	    r = getrower(request.user)
	    if (r.underarmourtoken == '') or (r.underarmourtoken is None):
		s = "Token doesn't exist. Need to authorize"
		return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
	message = "Something went wrong in workout_underarmourimport_view"
        messages.error(request,message)
	if settings.DEBUG:
	    return HttpResponse(res)
	else:
	    url = reverse(workouts_view)
	    return HttpResponseRedirect(url)
    else:
	workouts = []
        items = res.json()['_embedded']['workouts']
	for item in items:
	    s = item['start_datetime']
            i,r = underarmourstuff.get_idfromuri(request.user,item['_links'])
	    n = item['name']
            try:
                d = item['aggregates']['distance_total']
            except KeyError:
                d = 0
            try:
                ttot = item['aggregates']['active_time_total']
            except KeyError:
                ttot = 0
                
	    keys = ['id','distance','duration','starttime','type']
	    values = [i,d,ttot,s,r]
	    thedict = dict(zip(keys,values))
                
	    workouts.append(thedict)

	return render(request,'underarmour_list_import.html',
		      {'workouts':workouts,
                       'teams':get_my_teams(request.user),
		       })

    return HttpResponse(res)

# the page where you select which Polar workout to Import
@login_required()
def workout_polarimport_view(request):
    exercises = polarstuff.get_polar_workouts(request.user)
    workouts = []

    try:
        a = exercises.status_code
        if a == 401:
            messages.error(request,'Not authorized. You need to connect to Polar first')
        url = reverse(imports_view)
        return HttpResponseRedirect(url)
    except:
        pass
    
    for exercise in exercises:
        try:
            d = exercise['distance']
        except KeyError:
            d = 0
            
        i = exercise['id']
        transactionid = exercise['transaction-id']
        starttime = exercise['start-time']
        rowtype = exercise['sport']
        durationstring = exercise['duration']
        duration = isodate.parse_duration(durationstring)
        keys = ['id','distance','duration','starttime','type','transactionid']
        values = [i,d,duration,starttime,rowtype,transactionid]
        res = dict(zip(keys,values))
        workouts.append(res)


    return render(request, 'polar_list_import.html',
                  {
                      'workouts':workouts,
                      'teams':get_my_teams(request.user),
                      })


                   

# The page where you select which SportTracks workout to import
@login_required()
def workout_sporttracksimport_view(request,message=""):
    res = sporttracksstuff.get_sporttracks_workout_list(request.user)
    if (res.status_code != 200):
	if (res.status_code == 401):
	    r = getrower(request.user)
	    if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
		s = "Token doesn't exist. Need to authorize"
		return HttpResponseRedirect("/rowers/me/sporttracksauthorize/")
            else:
                return HttpResponseRedirect("/rowers/me/sporttracksrefresh/")
	message = "Something went wrong in workout_sporttracksimport_view"
        messages.error(request,message)
	if settings.DEBUG:
	    return HttpResponse(res)
	else:
	    url = reverse(workouts_view)
	    return HttpResponseRedirect(url)
    else:
	workouts = []
        r = getrower(request.user)
        stids = [int(getidfromsturi(item['uri'])) for item in res.json()['items']]
        knownstids = uniqify([
            w.uploadedtosporttracks for w in Workout.objects.filter(user=r)
                      ])
        newids = [stid for stid in stids if not stid in knownstids]
	for item in res.json()['items']:
	    d = int(float(item['total_distance']))
	    i = int(getidfromsturi(item['uri']))
            if i in knownstids:
                nnn = ''
            else:
                nnn = 'NEW'
	    n = item['name']
	    ttot = str(datetime.timedelta(seconds=int(float(item['duration']))))
	    s = item['start_time']
	    r = item['type']
	    keys = ['id','distance','duration','starttime','type','name','new']
	    values = [i,d,ttot,s,r,n,nnn]
	    res = dict(zip(keys,values))
	    workouts.append(res)
	return render(request,'sporttracks_list_import.html',
		      {'workouts':workouts,
                       'teams':get_my_teams(request.user),
		       })

    return HttpResponse(res)
	
# List of workouts on Concept2 logbook. This view only used for debugging
@login_required()
def c2listdebug_view(request,page=1,message=""):
    try:
	thetoken = c2_open(request.user)
    except C2NoTokenError:
	return HttpResponseRedirect("/rowers/me/c2authorize/")

    r = getrower(request.user)

    res = c2stuff.get_c2_workout_list(request.user,page=page)

    if (res.status_code != 200):
	message = "Something went wrong in workout_c2import_view (C2 token renewal)"
        messages.error(request,message)
	if settings.DEBUG:
	    return HttpResponse(res)
	else:
	    url = reverse(workouts_view)
	    return HttpResponseRedirect(url)
    else:
	workouts = []

	for item in res.json()['data']:
	    d = item['distance']
	    i = item['id']
	    ttot = item['time_formatted']
	    s = item['date']
	    r = item['type']
	    s2 = item['source']
	    c = item['comments']
	    keys = ['id','distance','duration','starttime','rowtype','source','comment']
	    values = [i,d,ttot,s,r,s2,c]
	    res = dict(zip(keys,values))
	    workouts.append(res)

	    
	return render(request,
		      'c2_list_import2.html',
		      {'workouts':workouts,
                       'teams':get_my_teams(request.user),
                      })

# Import all unknown workouts available on Concept2 logbook
@login_required()
def workout_getc2workout_all(request,page=1,message=""):
    try:
	thetoken = c2_open(request.user)
    except C2NoTokenError:
	return HttpResponseRedirect("/rowers/me/c2authorize/")

    res = c2stuff.get_c2_workout_list(request.user,page=page)

    if (res.status_code != 200):
	message = "Something went wrong in workout_c2import_view (C2 token refresh)"
        messages.error(request,message)
    else:
        r = getrower(request.user)
        c2ids = [item['id'] for item in res.json()['data']]
        alldata = {}
        for item in res.json()['data']:
            alldata[item['id']] = item
        
        knownc2ids = uniqify([
            w.uploadedtoc2 for w in Workout.objects.filter(user=r)
        ])
        newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
        
        for c2id in newids:
            workoutid = c2stuff.create_async_workout(alldata,
                                                     request.user,c2id)

    url = reverse(workouts_view)
    return HttpResponseRedirect(url)
            
    
# List of workouts available on Concept2 logbook - for import
@login_required()
def workout_c2import_view(request,page=1,message=""):
    try:
	thetoken = c2_open(request.user)
    except C2NoTokenError:
	return HttpResponseRedirect("/rowers/me/c2authorize/")

    res = c2stuff.get_c2_workout_list(request.user,page=page)

    if (res.status_code != 200):
	message = "Something went wrong in workout_c2import_view (C2 token refresh)"
        messages.error(request,message)
	if settings.DEBUG:
	    return HttpResponse(res)
	else:
	    url = reverse(workouts_view)
	    return HttpResponseRedirect(url)
    else:
	workouts = []
        r = getrower(request.user)
        c2ids = [item['id'] for item in res.json()['data']]
        knownc2ids = uniqify([
            w.uploadedtoc2 for w in Workout.objects.filter(user=r)
                      ])
        newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
	for item in res.json()['data']:
	    d = item['distance']
	    i = item['id']
	    ttot = item['time_formatted']
	    s = item['date']
	    r = item['type']
	    s2 = item['source']
	    c = item['comments']
            if i in knownc2ids:
                nnn = ''
            else:
                nnn = 'NEW'
	    keys = ['id','distance','duration','starttime','rowtype','source','comment','new']
	    values = [i,d,ttot,s,r,s2,c,nnn]
	    res = dict(zip(keys,values))
	    workouts.append(res)

	    
	return render(request,
		      'c2_list_import2.html',
		      {'workouts':workouts,
                       'teams':get_my_teams(request.user),
                       'page':page,
                      })

    
# Import a workout from Strava
@login_required()
def workout_getstravaworkout_view(request,stravaid):
    res = stravastuff.get_strava_workout(request.user,stravaid)
    if not res[0]:
        messages.error(request,res[1])
        return imports_view(request)
        
    strokedata = res[1]
    data = res[0]
    id,message = add_workout_from_strokedata(request.user,stravaid,data,strokedata,
				             source='strava',
                                             workoutsource='strava')
    w = get_workout(id)

    w.uploadedtostrava=stravaid
    w.save()
    if message:
        messages.error(request,message)


    r = getrower(request.user)
        
    url = reverse(r.defaultlandingpage,
                  kwargs = {
                      'id':int(id),
                  })
        
    return HttpResponseRedirect(url)

# Imports a workout from Runkeeper
@login_required()
def workout_getrunkeeperworkout_view(request,runkeeperid):
    res = runkeeperstuff.get_runkeeper_workout(request.user,runkeeperid)
    try:
        data = res.json()
    except ValueError:
        messages.error(request,'Error getting workout from Runkeeper')
        url = reverse(workout_runkeeperimport_view)
        return HttpResponseRedirect(url)

    id,message = add_workout_from_runkeeperdata(request.user,runkeeperid,data)
    w = Workout.objects.get(id=id)
    w.uploadedtorunkeeper=runkeeperid
    thetoken = runkeeper_open(request.user)
    w.save()
    if message:
        messages.error(request,message)

    r = getrower(request.user)
        
    url = reverse(r.defaultlandingpage,
                  kwargs = {
                      'id':int(id),
                  })
    return HttpResponseRedirect(url)

# Imports a workout from Underarmour
@login_required()
def workout_getunderarmourworkout_view(request,underarmourid):
    res = underarmourstuff.get_underarmour_workout(request.user,underarmourid)
    data = res.json()

    id,message = add_workout_from_underarmourdata(request.user,underarmourid,data)
    w = Workout.objects.get(id=id)
    w.uploadedtounderarmour=underarmourid
    w.save()
    if message:
        messages.error(request,message)

    r = getrower(request.user)
        
    url = reverse(r.defaultlandingpage,
                  kwargs = {
                      'id':int(id),
                  })
    return HttpResponseRedirect(url)



# Imports a workout from SportTracks
@login_required()
def workout_getsporttracksworkout_view(request,sporttracksid):
    res = sporttracksstuff.get_sporttracks_workout(request.user,sporttracksid)
    data = res.json()

    id,message = add_workout_from_stdata(request.user,sporttracksid,data)
    if id==0:
        messages.error(request,message)
        url = reverse(workouts_view)
        return HttpResponseRedirect(url)
    w = Workout.objects.get(id=id)
    w.uploadedtosporttracks=sporttracksid
    w.save()
    if message:
        messages.error(request,message)

    r = getrower(request.user)
        
    url = reverse(r.defaultlandingpage,
                  kwargs = {
                      'id':int(id),
                  })
    return HttpResponseRedirect(url)

# Imports all new workouts from SportTracks
@login_required()
def workout_getsporttracksworkout_all(request):
    res = sporttracksstuff.get_sporttracks_workout_list(request.user)
    if (res.status_code == 200):
        r = getrower(request.user)
        stids = [int(getidfromsturi(item['uri'])) for item in res.json()['items']]
        knownstids = uniqify([
            w.uploadedtosporttracks for w in Workout.objects.filter(user=r)
                      ])
        newids = [stid for stid in stids if not stid in knownstids]
        for sporttracksid in newids:
            res = sporttracksstuff.get_sporttracks_workout(
                request.user,sporttracksid)
            data = res.json()

            id,message = add_workout_from_stdata(request.user,sporttracksid,data)
            if id==0:
                messages.error(request,message)

            else:
                w = Workout.objects.get(id=id)
                w.uploadedtosporttracks=sporttracksid
                w.save()

    url = reverse(workouts_view)
    return HttpResponseRedirect(url)


# Imports all new workouts from SportTracks
@login_required()
def workout_getstravaworkout_all(request):
    res = stravastuff.get_strava_workout_list(request.user)
    if (res.status_code == 200):
        r = getrower(request.user)
        stravaids = [int(item['id']) for item in res.json()]
        knownstravaids = uniqify([
            w.uploadedtostrava for w in Workout.objects.filter(user=r)
            ])
        newids = [stravaid for stravaid in stravaids if not stravaid in knownstravaids]

        for stravaid in newids:
            res = stravastuff.get_strava_workout(request.user,stravaid)
            strokedata = res[1]
            data = res[0]

            if data:
                id,message = add_workout_from_strokedata(
                    request.user,stravaid,data,strokedata,
                    source='strava',
                    workoutsource='strava')

                if id==0:
                    messages.error(request,message)

                else:
                    messages.info(request,"imported Strava workout "+str(stravaid))
                    w = Workout.objects.get(id=id)
                    w.uploadedtostrava=stravaid
                    w.save()

            else:
                messages.error(request,"Couldn't import Strava workout "+str(stravaid))

    url = reverse(workouts_view)
    return HttpResponseRedirect(url)



# Imports a workout from Concept2 
@login_required()
def workout_getc2workout_view(request,c2id):
    try:
	thetoken = c2_open(request.user)
    except C2NoTokenError:
	return HttpResponseRedirect("/rowers/me/c2authorize/")

    res = c2stuff.get_c2_workout(request.user,c2id)
    if (res.status_code == 200):
	data = res.json()['data']
        splitdata = None
        if 'workout' in data:
            if 'splits' in data['workout']:
                splitdata = data['workout']['splits']
            if 'intervals' in data['workout']:
                splitdata = data['workout']['intervals']

        # Check if workout has stroke data, and get the stroke data
        if data['stroke_data']:
	    res2 = c2stuff.get_c2_workout_strokes(request.user,c2id)
        else:
            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'
            totaltime = data['time']/10.
            duration = dataprep.totaltime_sec_to_string(totaltime)
            duration = datetime.datetime.strptime(duration,'%H:%M:%S.%f').time()

            try:
                timezone_str = data['timezone']
            except:
                timezone_str = 'UTC'

            if timezone_str is None:
                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 = getrower(request.user)
            
            id, message = dataprep.create_row_df(r,
                                                 distance,
                                                 duration,
                                                 startdatetime,
#                                                 title = 'Imported from C2',
                                                 workouttype=workouttype)

            w = Workout.objects.get(id=id)
            w.uploadedtoc2 = c2id
            w.name = 'Imported from C2'
            w.workouttype = 'rower'
            w.save()

            message = "This workout does not have any stroke data associated with it. We created synthetic stroke data."
            messages.info(request,message)
            url = reverse(r.defaultlandingpage,
                          kwargs = {
                              'id':int(id),
                          })

	    return HttpResponseRedirect(url)

        # We have stroke data
	if res2.status_code == 200:
	    strokedata = pd.DataFrame.from_dict(res2.json()['data'])
            # create the workout
	    id,message = add_workout_from_strokedata(request.user,c2id,data,strokedata,
					     source='c2')
	    w = Workout.objects.get(id=id)
	    w.uploadedtoc2=c2id
            # If we have split data, update the stroke data so they
            # match exactly (some users are anal about this)
            if splitdata:
                try:
                    w.summary,sa,results = c2stuff.summaryfromsplitdata(splitdata,data,w.csvfilename)
                except:
                    sa = []
                    results = []
                    with open("media/c2splitdata.log","a") as errorlog:
                        errorstring = str(sys.exc_info()[0])
                        timestr = strftime("%Y%m%d-%H%M%S")
                        errorlog.write(timestr+errorstring+"\r\n")
                        errorlog.write("views.py line 952\r\n")

                w.save()

                from rowingdata.trainingparser import getlist
                # set stroke data in CSV file
                if sa:
                    values = getlist(sa)
                    units = getlist(sa,sel='unit')
                    types = getlist(sa,sel='type')

                    rowdata = rdata(w.csvfilename)
                    if rowdata:
                        rowdata.updateintervaldata(values,
                                                   units,types,results)

                        rowdata.write_csv(w.csvfilename,gzip=True)
                        dataprep.update_strokedata(w.id,rowdata.df)

            if message:
                messages.error(request,message)

            r = getrower(request.user)
        
            url = reverse(r.defaultlandingpage,
                          kwargs = {
                              'id':int(id),
                          })

	    return HttpResponseRedirect(url)
	else:
	    # message = json.loads(s.text)['message']
            message = json.loads(res2.text)['message']
            messages.error(request,message)

	url = reverse(workout_c2import_view)
	return HttpResponseRedirect(url)

    else:
	message = "Received error code from Concept2"
        messages.error(request,message)
	if settings.DEBUG:
	    return HttpResponse(res)
	else:
	    url = reverse(workout_c2import_view)
	    return HttpResponseRedirect(url)

@login_required
def workout_toggle_ranking(request,id=0):
    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    row = get_workout_permitted(request.user,id)

    row.rankingpiece = not row.rankingpiece
    row.save()

    if is_ajax:
        return JSONResponse({'result':row.rankingpiece})
    else: 
        url = reverse(workouts_view)
        response = HttpResponseRedirect(url)

    return response
        
        
# This is the main view for processing uploaded files
@login_required()
def workout_upload_view(request,
                        uploadoptions={
                            'makeprivate':False,
                            'make_plot':False,
                            'upload_to_C2':False,
                            'plottype':'timeplot',
                            'landingpage':'workout_edit_view',
                        },
                        docformoptions={
                            'workouttype':'rower',
                        }):

    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    r = getrower(request.user)

    if 'uploadoptions' in request.session:
        uploadoptions = request.session['uploadoptions']
        try:
            defaultlandingpage = uploadoptions['landingpage']
        except KeyError:
            uploadoptions['landingpage'] = r.defaultlandingpage
            defaultlandingpage = r.defaultlandingpage
    else:
        request.session['uploadoptions'] = uploadoptions

    if 'docformoptions' in request.session:
        docformoptions = request.session['docformoptions']
    else:
        request.session['docformoptions'] = docformoptions

    try:
        makeprivate = uploadoptions['makeprivate']
    except KeyError:
        makeprivate = False
    try:
        make_plot = uploadoptions['make_plot']
    except KeyError:
        make_plot = False

    try:
        workouttype = docformoptions['workouttype']
    except KeyError:
        workouttype = 'rower'

    try:
        boattype = docformoptions['boattype']
    except KeyError:
        boattype = '1x'

    try:
        plottype = uploadoptions['plottype']
    except KeyError:
        plottype = 'timeplot'

    try:
        landingpage = uploadoptions['landingpage']
    except KeyError:
        landingpage = r.defaultlandingpage
        uploadoptions['landingpage'] = landingpage

    try:
        upload_to_c2 = uploadoptions['upload_to_C2']
    except KeyError:
        upload_to_c2 = False

    try:
        upload_to_strava = uploadoptions['upload_to_Strava']
    except KeyError:
        upload_to_strava = False

    try:
        upload_to_st = uploadoptions['upload_to_SportTracks']
    except KeyError:
        upload_to_st = False

    try:
        upload_to_rk = uploadoptions['upload_to_RunKeeper']
    except KeyError:
        upload_to_rk = False

    try:
        upload_to_ua = uploadoptions['upload_to_MapMyFitness']
    except KeyError:
        upload_to_ua = False

    try:
        upload_to_tp = uploadoptions['upload_to_TrainingPeaks']
    except KeyError:
        upload_to_tp = False

    response = {}
    if request.method == 'POST':
	form = DocumentsForm(request.POST,request.FILES)
	optionsform = UploadOptionsForm(request.POST)

	if form.is_valid():
#	    f = request.FILES['file']
            f = form.cleaned_data['file']

            if f is not None:
	        res = handle_uploaded_file(f)
            else:
                messages.error(request,
                               "Something went wrong - no file attached")
                url = reverse(workout_upload_view)
                if is_ajax:
                    return JSONResponse({'result':0,'url':0})
                else:
                    return HttpResponseRedirect(url)
                
	    t = form.cleaned_data['title']
	    workouttype = form.cleaned_data['workouttype']
            boattype = form.cleaned_data['boattype']

            request.session['docformoptions'] = {
                'workouttype':workouttype,
                'boattype': boattype,
                }
            
	    notes = form.cleaned_data['notes']
            offline = form.cleaned_data['offline']

            if optionsform.is_valid():
	        make_plot = optionsform.cleaned_data['make_plot']
	        plottype = optionsform.cleaned_data['plottype']
	        upload_to_c2 = optionsform.cleaned_data['upload_to_C2']
	        upload_to_strava = optionsform.cleaned_data['upload_to_Strava']
	        upload_to_st = optionsform.cleaned_data['upload_to_SportTracks']
	        upload_to_rk = optionsform.cleaned_data['upload_to_RunKeeper']
	        upload_to_ua = optionsform.cleaned_data['upload_to_MapMyFitness']
	        upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks']
                makeprivate = optionsform.cleaned_data['makeprivate']
                landingpage = optionsform.cleaned_data['landingpage']

                uploadoptions = {
                    'makeprivate':makeprivate,
                    'make_plot':make_plot,
                    'plottype':plottype,
                    'upload_to_C2':upload_to_c2,
                    'upload_to_Strava':upload_to_strava,
                    'upload_to_SportTracks':upload_to_st,
                    'upload_to_RunKeeper':upload_to_rk,
                    'upload_to_MapMyFitness':upload_to_ua,
                    'upload_to_TrainingPeaks':upload_to_tp,
                    'landingpage':landingpage,
                    'boattype': boattype,
                    'workouttype': workouttype,
                }


            request.session['uploadoptions'] = uploadoptions

	    f1 = res[0] # file name
	    f2 = res[1] # file name incl media directory

            if not offline:
                id,message,f2 = dataprep.new_workout_from_file(
                    r,f2,
                    workouttype=workouttype,
                    boattype=boattype,
                    makeprivate=makeprivate,
                    title = t,
                    notes=''
                )
            else:
                workoutsbox = Mailbox.objects.filter(name='workouts')[0]
                uploadoptions['fromuploadform'] = True
                bodyyaml = yaml.safe_dump(
                    uploadoptions,
                    default_flow_style=False
                )
                msg = Message(mailbox=workoutsbox,
                              from_header=r.user.email,
                              subject = t,body=bodyyaml)
                msg.save()
                f3 = 'media/mailbox_attachments/'+f2[6:]
                copyfile(f2,f3)
                f3 = f3[6:]
                a = MessageAttachment(message=msg,document=f3)
                a.save()
                os.remove(f2)
                    
                messages.info(
                    request,
                    "The file was too large to process in real time. It will be processed in a background process. You will receive an email when it is ready")
                url = reverse(workout_upload_view)
                if is_ajax:
                    return JSONResponse({'result':1,'url':url})
                else:
                    response = HttpResponseRedirect(url)
                    return response
                
            if not id:
                messages.error(request,message)
		url = reverse(workout_upload_view)
                if is_ajax:
                    return JSONResponse({'result':0,'url':url})
                else:
		    response = HttpResponseRedirect(url)
                    return response
            elif id == -1:
                message = 'The zip archive will be processed in the background. The files in the archive will only be uploaded without the extra actions. You will receive email when the workouts are ready.'
                messages.info(request,message)
                url = reverse(workout_upload_view)
                if is_ajax:
                    return JSONResponse({'result':1,'url':url})
                else:
                    response = HttpResponseRedirect(url)
                    return response
            else:
                if message:
                    messages.error(request,message)

                url = reverse(workout_edit_view,
                              kwargs = {
                                  'id':int(id),
                              })

                if is_ajax:
                    response = {'result': 1,'url':url}
                else:
                    response = HttpResponseRedirect(url)

                w = Workout.objects.get(id=id)

            r = getrower(request.user)
	    if (make_plot):
                res,jobid = uploads.make_plot(r,w,f1,f2,plottype,t)
                if res == 0:
                    messages.error(request,jobid)
                else:
                    try:
                        request.session['async_tasks'] += [(jobid,'make_plot')]
                    except KeyError:
                        request.session['async_tasks'] = [(jobid,'make_plot')]

	    # upload to C2
	    if (upload_to_c2) or (w.user.c2_auto_export and isprorower(w.user)):
                try:
                    message,id = c2stuff.workout_c2_upload(request.user,w)
                except C2NoTokenError:
                    id = 0
                    message = "Something went wrong with the Concept2 sync"
                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)
                    
            if (upload_to_strava) or (w.user.strava_auto_export  and isprorower(w.user)):
                try:
                    message,id = stravastuff.workout_strava_upload(
                        request.user,w
                    )
                except StravaNoTokenError:
                    id = 0
                    message = "Please connect to Strava first"
                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)
                    
            if (upload_to_st) or (w.user.sporttracks_auto_export and isprorower(w.user)):
                try:
                    message,id = sporttracksstuff.workout_sporttracks_upload(
                        request.user,w
                    )
                except SportTracksNoTokenError:
                    message = "Please connect to SportTracks first"
                    id = 0
                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)
                    
            if (upload_to_rk) or (w.user.runkeeper_auto_export  and isprorower(w.user)):
                try:
                    message,id = runkeeperstuff.workout_runkeeper_upload(
                        request.user,w
                        )
                except RunKeeperNoTokenError:
                    message = "Please connect to Runkeeper first"
                    id = 0

                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)


            if (upload_to_ua) or (w.user.mapmyfitness_auto_export  and isprorower(w.user)):
                try:
                    message,id = underarmourstuff.workout_ua_upload(
                        request.user,w
                    )
                except UnderArmourNoTokenError:
                    message = "Please connect to MapMyFitness first"
                    id = 0

                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)


            if (upload_to_tp) or (w.user.trainingpeaks_auto_export and isprorower(w.user)):
                try:
                    message,id = tpstuff.workout_tp_upload(
                        request.user,w
                        )
                except TPNoTokenError:
                    message = "Please connect to TrainingPeaks first"
                    id = 0

                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)

                    
            if landingpage != 'workout_upload_view':
                url = reverse(landingpage,
                              kwargs = {
                                  'id':w.id,
                              })
            else:
                url = reverse(landingpage)

            if is_ajax:
                response = {'result':1,'url':url}
            else:
                response = HttpResponseRedirect(url)
	else:
            if not is_ajax:
	        response = render(request,
			          'document_form.html',
			          {'form':form,
                                   'teams':get_my_teams(request.user),
			           'optionsform': optionsform,
                                  })


        if is_ajax:
            return JSONResponse(response)
        else:
	    return response
    else:
        if not is_ajax:
	    form = DocumentsForm(initial=docformoptions)
	    optionsform = UploadOptionsForm(initial=uploadoptions)
	    return render(request, 'document_form.html',
		          {'form':form, 
                           'teams':get_my_teams(request.user),
		           'optionsform': optionsform,
                          })
        else:
            return {'result':0}

    
# This is the main view for processing uploaded files
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def team_workout_upload_view(request,message="",
                             successmessage="",
                             uploadoptions={
                                 'make_plot':False,
                                 'plottype':'timeplot',
                             }):

    if 'uploadoptions' in request.session:
        uploadoptions = request.session['uploadoptions']
    else:
        request.session['uploadoptions'] = uploadoptions


    myteams = Team.objects.filter(manager=request.user)
        
    make_plot = uploadoptions['make_plot']
    plottype = uploadoptions['plottype']

    r = getrower(request.user)
    if request.method == 'POST':
	form = DocumentsForm(request.POST,request.FILES)
	optionsform = TeamUploadOptionsForm(request.POST)
        
        rowerform = TeamInviteForm(request.POST)
        rowerform.fields.pop('email')
        rowerform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct()
	if form.is_valid():
	    f = request.FILES['file']
	    res = handle_uploaded_file(f)
	    t = form.cleaned_data['title']
            offline = form.cleaned_data['offline']
            if rowerform.is_valid():
                u = rowerform.cleaned_data['user']
                if u:
                    r = getrower(u)
                else:
                    message = 'Please select a rower'
                    messages.error(request,message)
                    messages.info(request,successmessage)
                    response = render(request,
			      'team_document_form.html',
			     {'form':form,
                              'teams':get_my_teams(request.user),
			      'optionsform': optionsform,
                              'rowerform': rowerform,
                             })

	            return response

                workouttype = form.cleaned_data['workouttype']

	    notes = form.cleaned_data['notes']

            if optionsform.is_valid():
	        make_plot = optionsform.cleaned_data['make_plot']
	        plottype = optionsform.cleaned_data['plottype']

                uploadoptions = {
                    'makeprivate':False,
                    'make_plot':make_plot,
                    'plottype':plottype,
                    'upload_to_C2':False,
                }


            request.session['uploadoptions'] = uploadoptions

	    f1 = res[0] # file name
	    f2 = res[1] # file name incl media directory


            if not offline:
                id,message,f2 = dataprep.new_workout_from_file(
                    r,f2,
                    workouttype=workouttype,
                    boattype=boattype,
                    makeprivate=False,
                    title = t,
                    notes=''
                )
            else:
                job = myqueue(
                    queuehigh,
                    handle_zip_file,
                    r.user.email,
                    t,
                    f2,
                    emailbounced = r.emailbounced
                )

                messages.info(
                    request,
                    "The file was too large to process in real time. It will be processed in a background process. The user will receive an email when it is ready"
                )

                
                url = reverse(team_workout_upload_view)
		response = HttpResponseRedirect(url)
                return response
                 
                    
            if not id:
                messages.error(request,message)
		url = reverse(team_workout_upload_view)
		response = HttpResponseRedirect(url)
                return response
            elif id == -1:
                message = 'The zip archive will be processed in the background. The files in the archive will only be uploaded without the extra actions. You will receive email when the workouts are ready.'
                messages.info(request,message)
                url = reverse(team_workout_upload_view)
                response = HttpResponseRedirect(url)
                return response

            else:
                successmessage = "The workout was added to the user's account"
                messages.info(request,successmessage)

                url = reverse(team_workout_upload_view)
                    
                response = HttpResponseRedirect(url)
                w = Workout.objects.get(id=id)

            r = getrower(request.user)
	    if (make_plot):
                id,jobid = uploads.make_plot(r,w,f1,f2,plottype,t)
                



	else:
            
            response = render(request,
			      'team_document_form.html',
			     {'form':form,
                              'teams':get_my_teams(request.user),
			      'optionsform': optionsform,
                              'rowerform': rowerform,
                             })

	return response
    else:
	form = DocumentsForm()
	optionsform = TeamUploadOptionsForm(initial=uploadoptions)
        rowerform = TeamInviteForm()
        rowerform.fields.pop('email')
        rowerform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct()
	return render(request, 'team_document_form.html',
		      {'form':form, 
                       'teams':get_my_teams(request.user),
		       'optionsform': optionsform,
                       'rowerform':rowerform,
                      })



# Ask the user if he really wants to delete the workout
@login_required()
def workout_delete_confirm_view(request, id=0):
    try:
	row = Workout.objects.get(id=id)
	if (checkworkoutuser(request.user,row)==False):
	    raise PermissionDenied("You are not allowed to delete this workout")
	else:
            url = request.META.get('HTTP_REFERER','/')
	    return render(request,'workout_delete_confirm.html',
			  {'id':int(id),
                           'teams':get_my_teams(request.user),
			   'workout':row,
                           'url':url})
		
    except Workout.DoesNotExist:
	raise Http404("Workout doesn't exist")

# Really deleting the workout
@login_required()
def workout_delete_view(request,id=0):
    try:
	row = Workout.objects.get(id=id)
	if (checkworkoutuser(request.user,row)==False):
	    raise PermissionDenied("You are not allowed to delete this workout")
	else:
	    # files are removed by pre-delete in models.py
	    row.delete()

        messages.info(request,'Workout deleted')
        try:
            url = request.session['referer']
            if 'rowers/workout/' in url:
                url = reverse(workouts_view)
        except KeyError:
            url = reverse(workouts_view)
            
        
	return HttpResponseRedirect(url)
		
    except Workout.DoesNotExist:
	raise Http404("Workout doesn't exist")

# Ask the user to confirm that he wants to delete a chart
@login_required()
def graph_delete_confirm_view(request, id=0):
    try:
	img = GraphImage.objects.get(id=id)
	row = Workout.objects.get(id=img.workout.id)
	if (checkworkoutuser(request.user,row)==False):
	    raise PermissionDenied("You are not allowed to delete this workout")
	else:
            try:
                url = request.session['referer']
            except KeyError:
                url = '/rowers/list-graphs'
                request.session['referer'] = url
	    return render(request,'graphimage_delete_confirm.html',
			  {'id':int(id),
                           'teams':get_my_teams(request.user),
			   'graph':img,
                           'url':url})
		
    except Workout.DoesNotExist:
	raise Http404("Workout doesn't exist")
    except GraphImage.DoesNotExist:
        raise Http404("The image doesn't exist")

# Really deleting the chart
@login_required()
def graph_delete_view(request,id=0):
    try:
	img = GraphImage.objects.get(id=id)
	row = Workout.objects.get(id=img.workout.id)
	if (checkworkoutuser(request.user,row)==False):
	    raise PermissionDenied("You are not allowed to delete this graph")
	else:
	    img.delete()
            messages.info(request,'Graph deleted')
            try:
                url = request.session['referer']
            except KeyError:
                url = reverse(graphs_view)
	    return HttpResponseRedirect(url)

    except GraphImage.DoesNotExist:
	raise Http404("Graph Image doesn't exist")
    except Workout.DoesNotExist:
        raise Http404("Workout doesn't exist")

# A page with all the recent graphs (searchable on workout name)
@login_required()
def graphs_view(request):
    request.session['referer'] = reverse(graphs_view)
    try:
	r = getrower(request.user)
	workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
        query = request.GET.get('q')
        if query:
            query_list = query.split()
            workouts = workouts.filter(
                reduce(operator.and_,
                       (Q(name__icontains=q) for q in query_list)) |
                reduce(operator.and_,
                       (Q(notes__icontains=q) for q in query_list))
                )

	g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
	if (len(g)<=5):
	    return render(request, 'list_graphs.html',
			  {'graphs1': g[0:4],
                          'teams':get_my_teams(request.user),
                          })
	else:
	    return render(request, 'list_graphs.html',
			  {'graphs1': g[0:5],
                           'teams':get_my_teams(request.user),
			   'graphs2': g[5:10]})
    except Rower.DoesNotExist:
	raise Http404("User has no rower instance")

# Show the chart (png image)
def graph_show_view(request,id):
    try:
	g = GraphImage.objects.get(id=id)
        try:
            width,height = Image.open(g.filename).size
            g.width = width
            g.height = height
            g.save()
        except:
            pass
        
	w = Workout.objects.get(id=g.workout.id)
	r = Rower.objects.get(id=w.user.id)

	return render(request,'show_graph.html',
		      {'graph':g,
                       'teams':get_my_teams(request.user),
		       'workout':w,
		       'rower':r,})
			 
    except GraphImage.DoesNotExist:
	raise Http404("This graph doesn't exist")
    except Workout.DoesNotExist:
        raise Http404("This workout doesn't exist")
    
# Restore original stroke data and summary
@login_required()
def workout_summary_restore_view(request,id,message="",successmessage=""):
    try:
	row = Workout.objects.get(id=id)
	if (checkworkoutuser(request.user,row)==False):
	    raise PermissionDenied("You are not allowed to edit this workout")
    except Workout.DoesNotExist:
	raise Http404("Workout doesn't exist")

    s = ""
    # still here - this is a workout we may edit
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)
    powerperc = 100*np.array([r.pw_ut2,
                              r.pw_ut1,
                              r.pw_at,
                              r.pw_tr,r.pw_an])/r.ftp

    ftp = float(r.ftp)
    if row.workouttype in types.otwtypes:
        ftp = ftp*(100.-r.otwslack)/100.
        
    rr = rrower(hrmax=r.max,hrut2=r.ut2,
		hrut1=r.ut1,hrat=r.at,
		hrtr=r.tr,hran=r.an,ftp=ftp,
                powerperc=powerperc,powerzones=r.powerzones)
    rowdata = rdata(f1,rower=rr)
    if rowdata == 0:
	raise Http404("Error: CSV Data File Not Found")
    rowdata.restoreintervaldata()
    rowdata.write_csv(f1,gzip=True)
    dataprep.update_strokedata(id,rowdata.df)
    intervalstats = rowdata.allstats()
    row.summary = intervalstats
    row.save()

    # create interactive plot
    try:
	res = interactive_chart(id,promember=1)
	script = res[0]
	div = res[1]
    except ValueError:
	pass
    

    messages.info(request,'Original Interval Data Restored')
    url = reverse(workout_summary_edit_view,
                  kwargs={
	              'id':int(id),
                  }			  
    )
    return HttpResponseRedirect(url)

# Split a workout
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_split_view(request,id=id):
    row = get_workout_permitted(request.user,id)

    r = row.user
    
    if request.method == 'POST':
        form = WorkoutSplitForm(request.POST)
        if form.is_valid():
            splittime = form.cleaned_data['splittime']
            splitsecond = splittime.hour*3600
            splitsecond += splittime.minute*60
            splitsecond += splittime.second
            splitsecond += splittime.microsecond/1.e6
            splitmode = form.cleaned_data['splitmode']
            try:
                ids,mesgs = dataprep.split_workout(
                    r,row,splitsecond,splitmode
                )
            except IndexError:
                messages.error("Something went wrong in Split")
                
            for message in mesgs:
                messages.info(request,message)


            if request.user == r:
                url = reverse(workouts_view)
            else:
                mgrids = [team.id for team in Team.objects.filter(manager=request.user)]
                rwrids = [team.id for team in r.team.all()]
                teamids = list(set(mgrids) & set(rwrids))
                if len(teamids) > 0:
                    teamid = teamids[0]
                
                    url = reverse(workouts_view,
                                  kwargs={
	                              'teamid':int(teamid),
                                  }
                    )
                else:
                    url = reverse(workouts_view)

            rowname = row.name
            if isinstance(rowname,unicode):
                rowname = rowname.encode('utf8')
            elif isinstance(rowname, str):
                rowname = rowname.decode('utf8')
                
            qdict = {'q':rowname}
            url+='?'+urllib.urlencode(qdict)

            return HttpResponseRedirect(url)

    form = WorkoutSplitForm()

    # create interactive plot
    try:
	res = interactive_chart(id,promember=1)
	script = res[0]
	div = res[1]
    except ValueError:
	pass

    return render(request, 'splitworkout.html',
		  {'form':form,
                   'workout':row,
                   'thediv':script,
                   'thescript':div,
                  })


# Fuse two workouts
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_fusion_view(request,id1=0,id2=1):
    try:
        w1 = Workout.objects.get(id=id1)
        w2 = Workout.objects.get(id=id2)
        r = w1.user
        if (checkworkoutuser(request.user,w1)==False) or \
           (checkworkoutuser(request.user,w2)==False):
            raise PermissionDenied("You are not allowed to use these workouts")
    except Workout.DoesNotExist:
        raise Http404("One of the workouts doesn't exist")

    if request.method == 'POST':
        form = FusionMetricChoiceForm(request.POST,instance=w2)
        if form.is_valid():
            cd = form.cleaned_data
            columns = cd['columns']
            timeoffset = cd['offset']
            posneg = cd['posneg']
            if posneg == 'neg':
                timeoffset = -timeoffset

            # Create DataFrame
            df,forceunit = dataprep.datafusion(id1,id2,columns,timeoffset)

            
            idnew,message = dataprep.new_workout_from_df(r,df,
                                                         title='Fused data',
                                                         parent=w1,
                                                         forceunit=forceunit)
            if message != None:
                messages.error(request,message)
            else:
                successmessage = 'Data fused'
                messages.info(request,message)

            url = reverse(workout_edit_view,
                          kwargs={
                              'id':idnew,
                          })

            return HttpResponseRedirect(url)
        else:
            return render(request, 'fusion.html',
		          {'form':form,
                           'teams':get_my_teams(request.user),
                           'workout1':w1,
                           'workout2':w2,
                          })
        

    form = FusionMetricChoiceForm(instance=w2)
    
    return render(request, 'fusion.html',
		  {'form':form,
                   'teams':get_my_teams(request.user),
                   'workout1':w1,
                   'workout2':w2,
                  })


# Edit the splits/summary
@login_required()
def workout_summary_edit_view(request,id,message="",successmessage=""
			      ):
    row = get_workout_permitted(request.user,id)

    s = ""
    # still here - this is a workout we may edit
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)
    powerperc = 100*np.array([r.pw_ut2,
                              r.pw_ut1,
                              r.pw_at,
                              r.pw_tr,r.pw_an])/r.ftp

    ftp = float(r.ftp)
    if row.workouttype in types.otwtypes:
        ftp = ftp*(100.-r.otwslack)/100.
        
    rr = rrower(hrmax=r.max,hrut2=r.ut2,
		hrut1=r.ut1,hrat=r.at,
		hrtr=r.tr,hran=r.an,ftp=ftp,
                powerperc=powerperc,powerzones=r.powerzones)
    rowdata = rdata(f1,rower=rr)
    if rowdata == 0:
	return HttpResponse("Error: CSV Data File Not Found")
    intervalstats = rowdata.allstats()
    try:
        itime,idist,itype = rowdata.intervalstats_values()
    except TypeError:
        return HttpResponse("Error: CSV Data File Not Found")
    nrintervals = len(idist)

    
    savebutton = 'nosavebutton'
    formvalues = {}
    form = SummaryStringForm()

    tss,normp = dataprep.workout_rscore(row)

    normv,normw = dataprep.workout_normv(row,pp=8.0)

    work = int(normw)
    power = int(normp)
    pace_secs = int(500./normv)

    try:
        avpace = datetime.timedelta(seconds=int(500./normv))
    except:
        avpace = datetime.timedelta(seconds=130)

    data = {
        'power': int(normp),
        'pace': avpace,
        'selector': 'power',
        'work': int(normw)
        }

    powerorpace = 'power'

    if normp == 0:
        data['selector'] = 'pace'
        powerorpace = 'pace'

        
    
    powerupdateform = PowerIntervalUpdateForm(initial=data)
    
    # We have submitted the mini language interpreter
    if request.method == 'POST' and "intervalstring" in request.POST:
	form = SummaryStringForm(request.POST)
	if form.is_valid():
	    cd = form.cleaned_data
	    s = cd["intervalstring"]
            try:
	        rowdata.updateinterval_string(s)
            except ParseException,err:
                messages.error(request,'Parsing error in column '+str(err.col))
	    intervalstats = rowdata.allstats()
	    itime,idist,itype = rowdata.intervalstats_values()
	    nrintervals = len(idist)
	    savebutton = 'savestringform'
        powerupdateform = PowerIntervalUpdateForm(initial=data)

    # we are saving the results obtained from the split by power/pace interpreter
    elif request.method == 'POST' and "savepowerpaceform" in request.POST:
        powerorpace = request.POST['powerorpace']
        value_pace = request.POST['value_pace']
        value_power = request.POST['value_power']
        value_work = request.POST['value_work']
        if powerorpace == 'power':
            power = int(value_power)
        elif powerorpace == 'pace':
            try:
                pace_secs = float(value_pace)
            except ValueError:
                pace_secs = float(value_pace.replace(',','.'))
        elif powerorpace == 'work':
            work = int(value_work)

        if powerorpace == 'power' and power is not None:
            try:
                rowdata.updateinterval_metric(
                    ' Power (watts)',power,mode='larger',
                    debug=False,smoothwindow=15.)
            except:
                messages.error(request,'Error updating power')
        elif powerorpace == 'pace':
            try:
                velo = 500./pace_secs
                rowdata.updateinterval_metric(
                    ' AverageBoatSpeed (m/s)',velo,mode='larger',
                    debug=False,smoothwindow=15.)
            except:
                messages.error(request,'Error updating pace')
        elif powerorpace == 'work':
            try:
                rowdata.updateinterval_metric(
                    'driveenergy',work,mode='larger',
                    debug=False,smoothwindow=15.)
            except:
                messages.error(request,'Error updating Work per Stroke')

        intervalstats = rowdata.allstats()
        itime,idist,itype = rowdata.intervalstats_values()
        nrintervals = len(idist)

        row.summary = intervalstats
        row.save()

        rowdata.write_csv(f1,gzip=True)

        dataprep.update_strokedata(id,rowdata.df)
        
        messages.info(request,"Updated interval data saved")
        data = {
            'power': power,
            'pace': datetime.timedelta(seconds=int(pace_secs)),
            'work': work,
            'selector': powerorpace
        }
        form = SummaryStringForm()
        powerupdateform = PowerIntervalUpdateForm(initial=data)
        savebutton = 'savepowerpaceform'
        formvalues = {
            'powerorpace': powerorpace,
            'value_power': power,
            'value_pace': pace_secs,
            'value_work':work,
            }

            
    # we are saving the results obtained from the mini language interpreter
    elif request.method == 'POST' and "savestringform" in request.POST:
	s = request.POST["savestringform"]
        try:
	    rowdata.updateinterval_string(s)
        except ParseException,err:
            messages.error(request,'Parsing error in column '+str(err.col))
            
	intervalstats = rowdata.allstats()
	itime,idist,itype = rowdata.intervalstats_values()
	nrintervals = len(idist)
	row.summary = intervalstats
	#intervalstats = rowdata.allstats()
        if s:
            try:
	        row.notes = u'{n} \n {s}'.format(
                    n = row.notes,
                    s = s
                )
            except TypeError:
                pass
            
	row.save()
	rowdata.write_csv(f1,gzip=True)
        dataprep.update_strokedata(id,rowdata.df)
	messages.info(request,"Updated interval data saved")
	data = {'intervalstring':s}
	form = SummaryStringForm(initial=data)
        powerupdateform = PowerIntervalUpdateForm(initial={
            'power': int(normp),
            'pace': avpace,
            'selector': 'power',
            'work': int(normw)
        })
	savebutton = 'savestringform'

    # we are saving the results obtained from the power update form
    elif request.method == 'POST' and 'selector' in request.POST:
        powerupdateform = PowerIntervalUpdateForm(request.POST)
        if powerupdateform.is_valid():
            cd = powerupdateform.cleaned_data
            powerorpace = cd['selector']
            power = cd['power']
            pace = cd['pace']
            work = cd['work']
            try:
                pace_secs = pace.seconds+pace.microseconds/1.0e6
            except AttributeError:
                pace_secs = 120.

            if powerorpace == 'power' and power is not None:
                try:
                    rowdata.updateinterval_metric(' Power (watts)',power,mode='larger',
                                                  debug=False,smoothwindow=15)
                except:
                    messages.error(request,'Error updating power')
            elif powerorpace == 'pace':
                try:
                    velo = 500./pace_secs
                    rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',velo,mode='larger',
                                                  debug=False,smoothwindow=15)
                except:
                    messages.error(request,'Error updating pace')
            elif powerorpace == 'work':
                try:
                    rowdata.updateinterval_metric(
                        'driveenergy',work,mode='larger',
                        debug=False,smoothwindow=15.)
                except:
                    messages.error(request,'Error updating Work per Stroke')
                    

            intervalstats = rowdata.allstats()
            itime,idist,itype = rowdata.intervalstats_values()
            nrintervals = len(idist)
            savebutton = 'savepowerpaceform'
            formvalues = {
                'powerorpace': powerorpace,
                'value_power': power,
                'value_pace': pace_secs,
                'value_work': work,
                }
            powerupdateform = PowerIntervalUpdateForm(initial=cd)
	    form = SummaryStringForm()
                

        form = SummaryStringForm()
                    
    # we are saving the results obtained from the detailed form
    elif request.method == 'POST' and "savedetailform" in request.POST:
	savebutton = 'savedetailform'
	form = SummaryStringForm()
	nrintervals = int(request.POST['nrintervals'])
	detailform = IntervalUpdateForm(request.POST,aantal=nrintervals)
	itime = []
	idist = []
	itype = []
	ivalues = []
	iunits = []
	itypes = []
	iresults = []
	for i in xrange(nrintervals):
	    try:
		t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S.%f")
	    except ValueError:
		t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S")
		
	    timesecs = 3600*t.hour+60*t.minute+t.second+t.microsecond/1.e6
	    itime += [timesecs]
	    idist += [int(request.POST['intervald_%s' % i])]
	    itype += [int(request.POST['type_%s' % i])]

	    if itype[i] == 3: # rest
		itypes += ['rest']
		ivalues += [timesecs]
		iresults += [idist[i]]
		iunits += ['seconds']
	    if itype[i] == 5 or itype[i] == 2:  # distance based work
		itypes += ['work']
		ivalues += [idist[i]]
		iresults += [timesecs]
		iunits += ['meters']
	    if itype[i] == 4 or itype[i] == 1:  # time based work
		itypes += ['work']
		ivalues += [timesecs]
		iresults += [idist[i]]
		iunits += ['seconds']


	rowdata.updateintervaldata(ivalues,iunits,itypes,iresults=iresults)
	intervalstats = rowdata.allstats()
	row.summary = intervalstats
	row.notes += "\n"+s
	row.save()
	rowdata.write_csv(f1,gzip=True)
        dataprep.update_strokedata(id,rowdata.df)
	messages.info(request,"Updated interval data saved")

	form = SummaryStringForm()
        powerupdateform = PowerIntervalUpdateForm(initial={
            'power': int(normp),
            'pace': avpace,
            'selector': 'power',
            'work': int(normw)
        })


    # we are processing the details form
    elif request.method == 'POST' and "nrintervals" in request.POST:
	savebutton = 'savedetailform'
	nrintervals = int(request.POST['nrintervals'])
	detailform = IntervalUpdateForm(request.POST,aantal=nrintervals)
	if detailform.is_valid():
	    cd = detailform.cleaned_data
	    itime = []
	    idist = []
	    itype = []
	    ivalues = []
	    iunits = []
	    itypes = []
	    iresults = []
	    for i in xrange(nrintervals):
		t = cd['intervalt_%s' % i]
		timesecs = t.total_seconds()
		itime += [timesecs]
		idist += [cd['intervald_%s' % i]]
		itype += [cd['type_%s' % i]]

		if itype[i] == '3': # rest
		    itypes += ['rest']
		    ivalues += [timesecs]
		    iresults += [idist[i]]
		    iunits += ['seconds']
		if itype[i] == '5' or itype[i] == '2':  # distance based work
		    itypes += ['work']
		    ivalues += [idist[i]]
		    iresults += [timesecs]
		    iunits += ['meters']
		if itype[i] == '4' or itype[i] == '1':  # time based work
		    itypes += ['work']
		    ivalues += [timesecs]
		    iresults += [idist[i]]
		    iunits += ['seconds']

	    rowdata.updateintervaldata(ivalues,iunits,
				       itypes,iresults=iresults)
	    intervalstats = rowdata.allstats()


	form = SummaryStringForm()
	powerupdateform = PowerIntervalUpdateForm()



    initial = {}
    for i in xrange(nrintervals):
	initial['intervald_%s' % i] = idist[i]
	initial['intervalt_%s' % i] = get_time(itime[i])
	initial['type_%s' % i] = itype[i]


    detailform = IntervalUpdateForm(aantal=nrintervals,initial=initial)

    # create interactive plot
    try:
        intervaldata = {
            'itime':itime,
            'idist':idist,
            'itype':itype,
            'selector': powerorpace,
            'normp': normp,
            'normv': normv,
            }
	res = interactive_chart(id,promember=1,intervaldata=intervaldata)
	script = res[0]
	div = res[1]
    except ValueError:
	pass

    # render page

    return render(request, 'summary_edit.html',
		  {'form':form,
		   'detailform':detailform,
                   'powerupdateform':powerupdateform,
		   'workout':row,
                   'teams':get_my_teams(request.user),
		   'intervalstats':intervalstats,
		   'nrintervals':nrintervals,
		   'interactiveplot':script,
		   'the_div':div,
		   'intervalstring':s,
		   'savebutton':savebutton,
                   'formvalues':formvalues,
		   })

# Page where user can manage his favorite charts
@login_required()
def rower_favoritecharts_view(request):
    message = ''
    successmessage = ''
    r = getrower(request.user)
    favorites = FavoriteChart.objects.filter(user=r).order_by('id')
    aantal = len(favorites)
    favorites_data = [{'yparam1':f.yparam1,
                       'yparam2':f.yparam2,
                       'xparam':f.xparam,
                       'plottype':f.plottype,
                       'workouttype':f.workouttype,
                       'reststrokes':f.reststrokes,
                       'notes':f.notes,}
                       for f in favorites]
    FavoriteChartFormSet = formset_factory(FavoriteForm,formset=BaseFavoriteFormSet,extra=0)
    if aantal==0:
        FavoriteChartFormSet = formset_factory(FavoriteForm,formset=BaseFavoriteFormSet,extra=1)
        

    if request.method == 'POST':
        favorites_formset = FavoriteChartFormSet(request.POST)
        if favorites_formset.is_valid():
            new_instances = []
            for favorites_form in favorites_formset:
                yparam1 = favorites_form.cleaned_data.get('yparam1')
                yparam2 = favorites_form.cleaned_data.get('yparam2')
                xparam = favorites_form.cleaned_data.get('xparam')
                plottype = favorites_form.cleaned_data.get('plottype')
                workouttype = favorites_form.cleaned_data.get('workouttype')
                reststrokes = favorites_form.cleaned_data.get('reststrokes')
                notes = favorites_form.cleaned_data.get('notes')
                new_instances.append(FavoriteChart(user=r,
                                                   yparam1=yparam1,
                                                   yparam2=yparam2,
                                                   xparam=xparam,
                                                   plottype=plottype,
                                                   notes=notes,
                                                   workouttype=workouttype,
                                                   reststrokes=reststrokes))
            try:
                with transaction.atomic():
                    FavoriteChart.objects.filter(user=r).delete()
                    FavoriteChart.objects.bulk_create(new_instances)
                    successmessage = "You have updated your favorites"
                    messages.info(request,message)
                    if len(new_instances)==0:
                        FavoriteChartFormSet=formset_factory(FavoriteForm,formset=BaseFavoriteFormSet,extra=1)
                        favorites_formset = FavoriteChartFormSet()
            except IntegrityError:
                message = "something went wrong"
                messages.error(request,message)
    else:
        favorites_formset = FavoriteChartFormSet(initial=favorites_data)
                

    context = {
        'favorites_formset':favorites_formset,
        'teams':get_my_teams(request.user),
        }

    
    
    return render(request,'favoritecharts.html',context)

# page where user sets his export settings
@login_required()
def rower_exportsettings_view(request):
    r = getrower(request.user)
    if request.method == 'POST':
        form = RowerExportForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data

            for attr, value in cd.items():
                setattr(r, attr, value)

            r.save()
    else:
        form = RowerExportForm(instance=r)
    return render(request, 'rower_exportsettings.html',
		  {'form':form,
                   'rower':r, 
                  })


# Page where user can set his details
# Add email address to form so user can change his email address
@login_required()
def rower_edit_view(request,rowerid=0,message=""):
    r = getrequestrower(request,rowerid=rowerid,notpermanent=True)

    rowerid = r.id
        
    if request.method == 'POST' and "ut2" in request.POST:
	form = RowerForm(request.POST)
	if form.is_valid():
	    # something
	    cd = form.cleaned_data
	    hrmax = cd['max']
	    ut2 = cd['ut2']
	    ut1 = cd['ut1']
	    at = cd['at']
	    tr = cd['tr']
	    an = cd['an']
	    rest = cd['rest']
	    try:
		r.max = max(min(hrmax,250),10)
		r.ut2 = max(min(ut2,250),10)
		r.ut1 = max(min(ut1,250),10)
		r.at = max(min(at,250),10)
		r.tr = max(min(tr,250),10)
		r.an = max(min(an,250),10)
		r.rest = max(min(rest,250),10)
		r.save()
                successmessage = "Your Heart Rate data were changed"
                messages.info(request,successmessage)
	        form = RowerForm(instance=r)
	        powerform = RowerPowerForm(instance=r)
                powerzonesform = RowerPowerZonesForm(instance=r)
                accountform = AccountRowerForm(instance=r)
                userform = UserForm(instance=r.user)
                return render(request, 'rower_form.html',
			  {'form':form,
                           'powerzonesform':powerzonesform,
                           'teams':get_my_teams(request.user),
                           'powerform':powerform,
                           'rower':r,
                           'accountform':accountform,
                           'userform':userform,
                          })
	    except Rower.DoesNotExist:
		message = "Funny. This user doesn't exist."
                messages.error(request,message)
		url = reverse(workouts_view)
		response = HttpResponseRedirect(url)
	else:
	    message = HttpResponse("invalid form")
	    #form = RowerForm(instance=r)
	    powerform = RowerPowerForm(instance=r)
            powerzonesform = RowerPowerZonesForm(instance=r)
            userform = UserForm(instance=r.user)
            accountform = AccountRowerForm(instance=r)
	    return render(request, 'rower_form.html',
			  {'form':form,
                           'teams':get_my_teams(request.user),
                           'powerzonesform':powerzonesform,
                           'userform':userform,
                           'accountform':accountform,
                           'powerform':powerform,
                           'rower':r,
                          })

			  

	return response
    elif request.method == 'POST' and "ftp" in request.POST:
	powerform = RowerPowerForm(request.POST)
	if powerform.is_valid():
	    cd = powerform.cleaned_data
            hrftp = cd['hrftp']
            if hrftp == 0:
                hrftp = int((r.an+r.tr)/2.)
	    ftp = cd['ftp']
            otwslack = cd['otwslack']
	    try:
                powerfrac = 100*np.array([r.pw_ut2,
                                          r.pw_ut1,
                                          r.pw_at,
                                          r.pw_tr,r.pw_an])/r.ftp
		r.ftp = max(min(ftp,650),50)
                r.otwslack = max(min(otwslack,50),0)
                ut2,ut1,at,tr,an = (r.ftp*powerfrac/100.).astype(int)
                r.pw_ut2 = ut2
                r.pw_ut1 = ut1
                r.pw_at = at
                r.pw_tr = tr
                r.pw_an = an
                r.hrftp = hrftp
		r.save()
		message = "FTP and/or OTW slack values changed."
                messages.info(request,message)
		url = reverse(rower_edit_view,
                              kwargs = {
                                  'rowerid':r.id,
                              })
		response = HttpResponseRedirect(url)
	    except Rower.DoesNotExist:
		message = "Funny. This user doesn't exist."
                messages.error(request,message)
		url = reverse(rower_edit_view)
		response = HttpResponseRedirect(url)	    
	else:
	    message = HttpResponse("invalid form")
	    form = RowerForm(instance=r)
	    #powerform = RowerPowerForm(instance=r)
            powerzonesform = RowerPowerZonesForm(instance=r)
            userform = UserForm(instance=r.user)
            accountform = AccountRowerForm(instance=r)
	    return render(request, 'rower_form.html',
			  {'form':form,
                           'teams':get_my_teams(request.user),
			   'powerform':powerform,
                           'rower':r,
                           'userform':userform,
                           'accountform':accountform,
			   })
			  
	    
	return response
    elif request.method == 'POST' and "ut3name" in request.POST:
	powerzonesform = RowerPowerZonesForm(request.POST)
	if powerzonesform.is_valid():
	    cd = powerzonesform.cleaned_data
            pw_ut2 = cd['pw_ut2']
            pw_ut1 = cd['pw_ut1']
            pw_at = cd['pw_at']
            pw_tr = cd['pw_tr']
            pw_an = cd['pw_an']
            ut3name = cd['ut3name']
            ut2name = cd['ut2name']
            ut1name = cd['ut1name']
            atname = cd['atname']
            trname = cd['trname']
            anname = cd['anname']
            powerzones = [ut3name,ut2name,ut1name,atname,trname,anname]
            try:
                r.pw_ut2 = pw_ut2
                r.pw_ut1 = pw_ut1
                r.pw_at = pw_at
                r.pw_tr = pw_tr
                r.pw_an = pw_an
                r.powerzones = powerzones
                r.save()
                successmessage = "Your Power Zone data were changed"
                messages.info(request,successmessage)
	        form = RowerForm(instance=r)
                accountform = AccountRowerForm(instance=r)
                userform = UserForm(instance=r.user)
	        powerform = RowerPowerForm(instance=r)
                powerzonesform = RowerPowerZonesForm(instance=r)
                return render(request, 'rower_form.html',
			  {'form':form,
                           'teams':get_my_teams(request.user),
                           'powerzonesform':powerzonesform,
                           'powerform':powerform,
                           'userform':userform,
                           'accountform':accountform,
                           'rower':r,
                          })
            except Rower.DoesNotExist:
		message = "Funny. This user doesn't exist."
                messages.error(request,message)
		url = reverse(workouts_view)
		response = HttpResponseRedirect(url)
            return response
        else:
	    form = RowerForm(instance=r)
	    powerform = RowerPowerForm(instance=r)
            accountform = AccountRowerForm(instance=r)
            userform = UserForm(instance=r.user)
            #powerzonesform = RowerPowerZonesForm(instance=r)
	    message = HttpResponse("invalid form")
	    return render(request, 'rower_form.html',
		          {'form':form,
                           'teams':get_my_teams(request.user),
		           'powerform':powerform,
                           'powerzonesform':powerzonesform,
                           'accountform':accountform,
                           'userform':userform,
                           'rower':r,
		          })
    elif request.method == 'POST' and "weightcategory" in request.POST:
        accountform = AccountRowerForm(request.POST)
        userform = UserForm(request.POST,instance=r.user)
        if accountform.is_valid() and userform.is_valid():
            # process
            cd = accountform.cleaned_data
            ucd = userform.cleaned_data
            first_name = ucd['first_name']
            last_name = ucd['last_name']
            email = ucd['email']
            sex = cd['sex']
            defaultlandingpage = cd['defaultlandingpage']
            weightcategory = cd['weightcategory']
            birthdate = cd['birthdate']
            showfavoritechartnotes = cd['showfavoritechartnotes']
            getemailnotifications = cd['getemailnotifications']
            getimportantemails = cd['getimportantemails']
            defaulttimezone=cd['defaulttimezone']
            u = r.user
            if u.email != email and len(email):
                resetbounce = True
            else:
                resetbounce = False
            if len(first_name):
                u.first_name = first_name
            u.last_name = last_name
            if len(email): ## and check_email_freeforuse(u,email):
                u.email = email
                resetbounce = True


            u.save()
            r.defaulttimezone=defaulttimezone
            r.weightcategory = weightcategory
            r.getemailnotifications = getemailnotifications
            r.getimportantemails = getimportantemails
            r.defaultlandingpage = defaultlandingpage
            r.showfavoritechartnotes = showfavoritechartnotes
            r.sex = sex
            r.birthdate = birthdate
            if resetbounce and r.emailbounced:
                r.emailbounced = False
            r.save()
            form = RowerForm(instance=r)
	    powerform = RowerPowerForm(instance=r)
            powerzonesform = RowerPowerZonesForm(instance=r)
            accountform = AccountRowerForm(instance=r)
            userform = UserForm(instance=u)
            successmessage = 'Account Information changed'
            messages.info(request,successmessage)
            return render(request, 'rower_form.html',
			  {'form':form,
                           'teams':get_my_teams(request.user),
                           'powerzonesform':powerzonesform,
                           'powerform':powerform,
                           'accountform':accountform,
                           'userform':userform,
                           'rower':r,
                          })
        else:
            form = RowerForm(instance=r)
	    powerform = RowerPowerForm(instance=r)
            powerzonesform = RowerPowerZonesForm(instance=r)
            return render(request, 'rower_form.html',
			  {'form':form,
                           'teams':get_my_teams(request.user),
                           'powerzonesform':powerzonesform,
                           'powerform':powerform,
                           'accountform':accountform,
                           'userform':userform,
                           'rower':r,
                          })
        
	    
    else:
	try:
	    form = RowerForm(instance=r)
	    powerform = RowerPowerForm(instance=r)
            powerzonesform = RowerPowerZonesForm(instance=r)
            accountform = AccountRowerForm(instance=r)
            userform = UserForm(instance=r.user)
            grants = AccessToken.objects.filter(user=request.user)
	    return render(request, 'rower_form.html',
			  {
			      'form':form,
                              'teams':get_my_teams(request.user),
			      'powerform':powerform,
                              'powerzonesform':powerzonesform,
                              'userform':userform,
                              'accountform':accountform,
                              'grants':grants,
                              'rower':r,
			      })
	except Rower.DoesNotExist:
	    raise Http404("This user doesn't exist")

# Revoke an app that you granted access through the API.
# this views is called when you press a button on the User edit page
# the button is only there when you have granted access to an app
@login_required()
def rower_revokeapp_view(request,id=0):
    try:
        tokens = AccessToken.objects.filter(user=request.user,application=id)
        refreshtokens = AccessToken.objects.filter(user=request.user,application=id)
        for token in tokens:
            token.revoke()
        for token in refreshtokens:
            token.revoke()

        r = getrower(request.user)
        form = RowerForm(instance=r)
        powerform = RowerPowerForm(instance=r)
        grants = AccessToken.objects.filter(user=request.user)
        return render(request, 'rower_form.html',
		      {
		          'form':form,
                          'teams':get_my_teams(request.user),
		          'powerform':powerform,
                          'grants':grants,
                      })
    except AccessToken.DoesNotExist:
        raise Http404("Access token doesn't exist")



# Creates unix time stamp from a datetime object
def totimestamp(dt, epoch=datetime.datetime(1970,1,1,tzinfo=tz('UTC'))):
    td = dt - epoch
    # return td.total_seconds()
    return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6
# Check if a column of a dataframe has the required (aantal)
# number of elements. Also checks if the column is a numerical type
# Replaces any faulty columns with zeros
def trydf(df,aantal,column):
    try:
        s = df[column]
        if len(s) != aantal:
            return np.zeros(aantal)
        if not np.issubdtype(s,np.number):
            return np.zeros(aantal)
    except KeyError:
        s = np.zeros(aantal)

    return s

# Stroke data form to test API upload
@login_required()
def strokedataform(request,id=0):
    if request.method == 'GET':
        form = StrokeDataForm()
        return render(request, 'strokedata_form.html',
		      {
		          'form':form,
                          'teams':get_my_teams(request.user),
                          'id':int(id),
		      })
    elif request.method == 'POST':
        form = StrokeDataForm()

    return render(request, 'strokedata_form.html',
		  {
		      'form':form,
                      'teams':get_my_teams(request.user),
                      'id':int(id),
		  })

# Process the POSTed stroke data according to the API definition
# Return the GET stroke data according to the API definition
from rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer

@csrf_exempt
@login_required()
@api_view(['GET','POST'])
def strokedatajson(request,id):
    """
    POST: Add Stroke data to workout
    GET: Get stroke data of workout
    """
    row = get_workout_permitted(request.user,id)

    try:
        id = int(id)
    except ValueError:
        return HttpResponse("Not a valid workout number",status=400)


    if request.method == 'GET':
        # currently only returns a subset. 
        columns = ['spm','time','hr','pace','power','distance']
        datadf = dataprep.getsmallrowdata_db(columns,ids=[id])
        with open('media/apilog.log','a') as logfile:
            logfile.write(str(timezone.now())+": ")
            logfile.write(request.user.username+"(GET) \n")
        return JSONResponse(datadf)

    if request.method == 'POST':
        checkdata,r = dataprep.getrowdata_db(id=row.id)
        if not checkdata.empty:
            return HttpResponse("Duplicate Error",409)
        # strokedata = request.POST['strokedata']
        # checking/validating and cleaning
        try:
            strokedata = json.loads(request.POST['strokedata'])
        except:
            return HttpResponse("No JSON object could be decoded",400)

        df = pd.DataFrame(strokedata)
        df.index = df.index.astype(int)
        df.sort_index(inplace=True)
        # time, hr, pace, spm, power, drivelength, distance, drivespeed, dragfactor, strokerecoverytime, averagedriveforce, peakdriveforce, lapidx
        try:
            time = df['time']/1.e3
        except KeyError:
            return HttpResponse("There must be time values",status=400)
        aantal = len(time)
        pace = df['pace']/1.e3
        if len(pace) != aantal:
            return HttpResponse("Pace array has incorrect length",status=400)
        distance = df['distance']
        if len(distance) != aantal:
            return HttpResponse("Distance array has incorrect length",status=400)
        
        spm = df['spm']
        if len(spm) != aantal:
            return HttpResponse("SPM array has incorrect length",status=400)

        res = dataprep.testdata(time,distance,pace,spm)
        if not res:
            return HttpResponse("Data are not numerical",status=400)
            
        power = trydf(df,aantal,'power')
        drivelength = trydf(df,aantal,'drivelength')
        drivespeed = trydf(df,aantal,'drivespeed')
        dragfactor = trydf(df,aantal,'dragfactor')
        drivetime = trydf(df,aantal,'drivetime')
        strokerecoverytime = trydf(df,aantal,'strokerecoverytime')
        averagedriveforce = trydf(df,aantal,'averagedriveforce')
        peakdriveforce = trydf(df,aantal,'peakdriveforce')
        wash = trydf(df,aantal,'wash')
        catch = trydf(df,aantal,'catch')
        finish = trydf(df,aantal,'finish')
        peakforceangle = trydf(df,aantal,'peakforceangle')
        driveenergy = trydf(df,aantal,'driveenergy')
        slip = trydf(df,aantal,'slip')
        lapidx = trydf(df,aantal,'lapidx')
        hr = trydf(df,aantal,'hr')

        starttime = totimestamp(row.startdatetime)+time[0]
        unixtime = starttime+time

        with open('media/apilog.log','a') as logfile:
            logfile.write(str(starttime)+": ")
            logfile.write(request.user.username+"(POST) \r\n")
            
        data = pd.DataFrame({'TimeStamp (sec)':unixtime,
			     ' Horizontal (meters)': distance,
			     ' Cadence (stokes/min)':spm,
			     ' HRCur (bpm)':hr,
			     ' DragFactor':dragfactor,
			     ' Stroke500mPace (sec/500m)':pace,
			     ' Power (watts)':power,
			     ' DriveLength (meters)':drivelength,
			     ' DriveTime (ms)':drivetime,
			     ' StrokeRecoveryTime (ms)':strokerecoverytime,
			     ' AverageDriveForce (lbs)':averagedriveforce,
			     ' PeakDriveForce (lbs)':peakdriveforce,
			     ' lapIdx':lapidx,
			     ' ElapsedTime (sec)':time,
                             'catch':catch,
                             'slip':slip,
                             'finish':finish,
                             'wash':wash,
                             'driveenergy':driveenergy,
                             'peakforceangle':peakforceangle,
	})

        # Following part should be replaced with dataprep.new_workout_from_df

	r = getrower(request.user)
        
        timestr = row.startdatetime.strftime("%Y%m%d-%H%M%S")
        csvfilename ='media/Import_'+timestr+'.csv'
        
        res =  data.to_csv(csvfilename+'.gz',index_label='index',
                           compression='gzip')
        row.csvfilename = csvfilename
        row.save()

        powerperc = 100*np.array([r.pw_ut2,
                                  r.pw_ut1,
                                  r.pw_at,
                                  r.pw_tr,r.pw_an])/r.ftp

        ftp = float(r.ftp)
        if row.workouttype in types.otwtypes:
            ftp = ftp*(100.-r.otwslack)/100.
            
        rr = rrower(hrmax=r.max,hrut2=r.ut2,
		    hrut1=r.ut1,hrat=r.at,
		    hrtr=r.tr,hran=r.an,ftp=ftp,
                    powerperc=powerperc,powerzones=r.powerzones)
        rowdata = rdata(row.csvfilename,rower=rr).df
        
        datadf = dataprep.dataprep(rowdata,id=row.id,bands=True,barchart=True,otwpower=True,empower=True)    
        # mangling

        #
        return HttpResponse(row.id,status=201)

    #Method not supported
    return HttpResponseNotAllowed("Method not supported")


# Teams related views
import teams

@login_required()
def team_view(request,id=0):
    ismember = 0
    hasrequested = 0
    r = getrower(request.user)
    myteams = Team.objects.filter(manager=request.user)
    
    try:
        t = Team.objects.get(id=id)
    except Team.DoesNotExist:
        raise Http404("Team doesn't exist")

    
    if request.method == 'POST' and request.user == t.manager:
        inviteform = TeamInviteForm(request.POST)
        inviteform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct().exclude(rower__team__name=t.name)
        if inviteform.is_valid():
            cd = inviteform.cleaned_data
            newmember = cd['user']
            email = cd['email']
            inviteid,text = teams.create_invite(t,t.manager,
                                                   user=newmember,
                                                   email=email)
            if inviteid:
                teams.send_invite_email(inviteid)
                successmessage = text
                messages.info(request,successmessage)
            else:
                message = text
                messages.error(request,message)
                
    elif request.user == t.manager:
        inviteform = TeamInviteForm()
        inviteform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct().exclude(rower__team__name=t.name)
    else:
        inviteform = ''
        
    members = Rower.objects.filter(team=t).order_by('user__last_name','user__first_name')
    thisteammyrequests = TeamRequest.objects.filter(team=t,user=request.user)
    if len(thisteammyrequests):
        hasrequested = 1

    if r in members:
        ismember = 1



    return render(request, 'team.html',
                  {
                      'team':t,
                      'teams':get_my_teams(request.user),
                      'members':members,
                      'inviteform':inviteform,
                      'ismember':ismember,
                      'hasrequested':hasrequested,
                      })

@login_required()
def team_leaveconfirm_view(request,id=0):
    try:
        t = Team.objects.get(id=id)
    except Team.DoesNotExist:
        raise Http404("Team doesn't exist")

    return render(request,'teamleaveconfirm.html',
                  {
                      'team':t,
                      'teams':get_my_teams(request.user),
                      })

@login_required()
def rower_calcdps_view(request):
    r = getrower(request.user)

    ws = [(w.id,w.csvfilename) for w in Workout.objects.filter(user=r)]
    res = myqueue(queue,handle_updatedps,r.user.email,ws,debug=False,
                  emailbounced=r.emailbounced) 

    messages.info(request,"Your workouts are being updated in the background. You will receive email when this is done.")

    url = reverse(workouts_view)
    return HttpResponseRedirect(url)

@login_required()
def rower_update_empower_view(
        request,
        startdate=timezone.now()-datetime.timedelta(days=365),
        enddate=timezone.now()
):
    try:
        r = getrower(request.user)
    except Rower.DoesNotExist:
        raise Http404("Rower doesn't exist")
        
    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])

    if request.method == 'POST' and 'daterange' in request.POST:
        dateform = DateRangeForm(request.POST)
        if dateform.is_valid():
            startdate = dateform.cleaned_data['startdate']
            enddate = dateform.cleaned_data['enddate']
            startdatestring = startdate.strftime('%Y-%m-%d')
            enddatestring = enddate.strftime('%Y-%m-%d')
            request.session['startdate'] = startdatestring
            request.session['enddate'] = enddatestring
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })
        

    if request.method == 'POST' and 'workouts' in request.POST:
        form = WorkoutMultipleCompareForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            workouts = cd['workouts']
            workoutdicts = []
            
            for w in workouts:
                if w.user != r:
                    message = "You can only alter your own workouts"
                    messages.error(request,message)
                if 'x' in w.boattype and w.oarlength is not None and w.oarlength > 3.30:
                    message = "Oarlength and boat type mismatch for workout "+str(w.id)+". Skipping workout"
                    messages.error(request,message)
                elif 'x' not in w.boattype and w.oarlength is not None and w.oarlength <= 3.30:
                    message = "Oarlength and boat type mismatch for workout "+str(w.id)+". Skipping workout"
                    messages.error(request,message)
                elif w.oarlength is None:
                    message = "Incorrect oarlength in workout "+str(w.id)+". Skipping workout"
                    messages.error(request,message)
                else:

                    
                    workoutdict = {
                        'id':w.id,
                        'boattype':w.boattype,
                        'filename':w.csvfilename,
                        'inboard':w.inboard,
                        'oarlength':w.oarlength
                    }

                    workoutdicts.append(workoutdict)

                    w.workoutsource = 'speedcoach2corrected'
                    w.save()

                    
            job = myqueue(queuelow,handle_update_empower,
                          request.user.email,workoutdicts,
                          debug=False,
                          emailbounced=r.emailbounced)

            try:
                request.session['async_tasks'] += [(job.id,'update_empower')]
            except KeyError:
                request.session['async_tasks'] = [(job.id,'update_empower')]

            successmessage = 'Your workouts are being updated in the background. You will receive email when this is done. You can check the status of your calculations <a href="/rowers/jobs-status" target="_blank">here</a>'

            messages.info(request,successmessage)

            url = reverse(workouts_view)
            return HttpResponseRedirect(url)
    else:

        workouts = Workout.objects.filter(
            startdatetime__gte=startdate,
            startdatetime__lte=enddate,
            workoutsource='speedcoach2',
            user=r,
        ).order_by("-date","-starttime")
        
        form = WorkoutMultipleCompareForm()
        form.fields["workouts"].queryset = workouts
        # GET request = prepare form

        return render(request, 'empower_fix.html',
                      {'workouts':workouts,
                       'dateform':dateform,
                       'form':form,
                       'rower':r
                       })

@login_required()
def team_leave_view(request,id=0):
    r = getrower(request.user)
    teams.remove_member(id,r)
                            
    url = reverse(rower_teams_view)
    response = HttpResponseRedirect(url)
    return response

from rowers.forms import TeamInviteCodeForm

@login_required()
def rower_teams_view(request,message='',successmessage=''):
    if request.method == 'POST':
        form = TeamInviteCodeForm(request.POST)
        if form.is_valid():
            code = form.cleaned_data['code']
            res,text = teams.process_invite_code(request.user,code)
            if res:
                successmessage = text
            else:
                message = text
    else:
        form = TeamInviteCodeForm()
            
    r = getrower(request.user)
    ts = Team.objects.filter(rower=r)
    myteams = Team.objects.filter(manager=request.user)
    otherteams = Team.objects.filter(private='open').exclude(rower=r).exclude(manager=request.user).order_by('name')
    teams.remove_expired_invites()

    invites = TeamInvite.objects.filter(user=request.user)
    requests = TeamRequest.objects.filter(user=request.user)
    myrequests = TeamRequest.objects.filter(team__in=myteams)
    myinvites = TeamInvite.objects.filter(team__in=myteams)
    clubsize = teams.count_invites(request.user)+teams.count_club_members(request.user)
    max_clubsize = r.clubsize

    messages.info(request,successmessage)
    messages.error(request,message)
    return render(request, 'teams.html',
		  {
                      'teams':ts,
                      'clubsize':clubsize,
                      'max_clubsize':max_clubsize,
                      'myteams':myteams,
                      'invites':invites,
                      'otherteams':otherteams,
                      'requests':requests,
                      'myrequests':myrequests,
                      'form':form,
                      'myinvites':myinvites,
		  })

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def invitation_revoke_view(request,id):
    res,text = teams.revoke_invite(request.user,id)
    if res:
        messages.info(request,text)
        successmessage = text
    else:
        message = text
        messages.error(request,text)

    url = reverse(rower_teams_view)

    return HttpResponseRedirect(url)

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def manager_member_drop_view(request,teamid,userid,
                             message='',successmessage=''):
    rower = Rower.objects.get(user__id=userid)
    res, text = teams.mgr_remove_member(teamid,request.user,rower)
    if res:
        messages.info(request,text)
    else:
        messages.error(request,text)
        
    url = reverse(rower_teams_view)

    return HttpResponseRedirect(url)

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def manager_requests_view(request,code=None,message='',successmessage=''):
    if code:
        res,text = teams.process_request_code(request.user,code)
        if res:
            successmessage = text
            message = ''
        else:
            message = text
            successmessage = ''

    messages.info(request,successmessage)
    messages.error(request,message)
    url = reverse(rower_teams_view,kwargs={
    })
    return HttpResponseRedirect(url)


@login_required()
def team_requestmembership_view(request,teamid,userid):
    try:
        t = Team.objects.get(id=teamid)
    except Team.DoesNotExist:
        raise Http404("Team doesn't exist")
    
    res,text = teams.create_request(t,userid)
    if res:
        messages.info(request,text)
    else:
        messages.error(request,text)
        
    url = reverse(team_view,kwargs={
	'id':int(teamid),
        })


    return HttpResponseRedirect(url)

@login_required()
def request_revoke_view(request,id=0):
    res,text = teams.revoke_request(request.user,id)

    if res:
        messages.info(request,text)

    else:
        messages.error(request,text)

    url = reverse(rower_teams_view)

    return HttpResponseRedirect(url)

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def request_reject_view(request,id=0):
    res,text = teams.reject_request(request.user,id)

    if res:
        messages.info(request,text)
    else:
        messages.error(request,text)

    url = reverse(rower_teams_view)

    return HttpResponseRedirect(url)

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def invitation_reject_view(request,id=0):
    res,text = teams.reject_invitation(request.user,id)

    if res:
        messages.info(request,text)
    else:
        messages.error(request,text)

    url = reverse(rower_teams_view)

    return HttpResponseRedirect(url)

@login_required()
def rower_invitations_view(request,code=None,message='',successmessage=''):

    if code:
        teams.remove_expired_invites()
        res,text = teams.process_invite_code(request.user,code)
        if res:
            messages.info(request,text)
            teamid=res
            url = reverse(team_view,kwargs={
	        'id':teamid,
            })
        else:
            messages.error(request,text)

            url = reverse(rower_teams_view)

        return HttpResponseRedirect(url)

    url = reverse(rower_teams_view,kwargs={
    })
    return HttpResponseRedirect(url)
    
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def team_edit_view(request,id=0):
    try:
        t = Team.objects.get(id=id)
    except Team.DoesNotExist:
        raise Http404("Team does not exist")
        
    if request.method == 'POST':
        teamcreateform = TeamForm(request.POST,instance=t)
        if teamcreateform.is_valid():
            cd = teamcreateform.cleaned_data
            name = cd['name']
            notes = cd['notes']
            manager = request.user
            private = cd['private']
            viewing = cd['viewing']
            res,message=teams.update_team(t,name,manager,private,notes,
                                          viewing)
            if res:
                messages.info(request,message)
            else:
                messages.error(request,message)

            url = reverse(team_view,
                          kwargs={
                              'id':int(id),
                          }
            )
                
            response = HttpResponseRedirect(url)
            return response

    else:
        teamcreateform = TeamForm(instance=t)

    return render(request,'teamedit.html',
                  {
                      'form':teamcreateform,
                      'teams':get_my_teams(request.user),
                      'team':t,
                      })

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def team_create_view(request):
    if request.method == 'POST':
        teamcreateform = TeamForm(request.POST)
        if teamcreateform.is_valid():
            cd = teamcreateform.cleaned_data
            name = cd['name']
            notes = cd['notes']
            manager = request.user
            private = cd['private']
            viewing = cd['viewing']
            res,message=teams.create_team(name,manager,private,notes,
                                          viewing)
            url = reverse(rower_teams_view)
            response = HttpResponseRedirect(url)
            return response

    else:
        teamcreateform = TeamForm()

    return render(request,'teamcreate.html',
                  {
                      'teams':get_my_teams(request.user),
                      'form':teamcreateform,
                      })

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def team_deleteconfirm_view(request,id):
    r = getrower(request.user)
    try:
        t = Team.objects.get(id=id)
    except Team.DoesNotExist:
        raise Http404("This team doesn't exist")
    if t.manager != request.user:
        raise PermissionDenied("You are not allowed to delete this team")

    return render(request,'teamdeleteconfirm.html',
                  {
                      'teams':get_my_teams(request.user),
                      'team':t
                  })

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def team_delete_view(request,id):
    r = getrower(request.user)
    try:
        t = Team.objects.get(id=id)
    except Team.DoesNotExist:
        raise Http404("This team doesn't exist")
    if t.manager != request.user:
        raise PermissionDenied("You are not allowed to delete this team")

    teams.remove_team(t.id)
    
    url = reverse(rower_teams_view)
    response = HttpResponseRedirect(url)
    return response

@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
def team_members_stats_view(request,id):
    r = getrower(request.user)
    try:
        t = Team.objects.get(id=id)
    except Team.DoesNotExist:
        raise Http404("This team doesn't exist")
    if t.manager != request.user:
        raise PermissionDenied("You are not allowed to see this page")

    members = Rower.objects.filter(team=t).order_by("user__last_name","user__first_name")
    
    theusers = [member.user for member in members]

    
    
    response = render(request,'teamstats.html',
                  {
                      'teams':get_my_teams(request.user),
                      'team':t,
                      'theusers':theusers,
                  })

    return response

from rowers.models import C2WorldClassAgePerformance

def agegroupcpview(request,age,normalize=0):
    script,div = interactive_agegroupcpchart(age,normalized=normalize)

    response = render(request,'agegroupcp.html',
                      {
                          'interactiveplot':script,
                          'the_div':div,
                          }
                      )

    return response

def agegrouprecordview(request,sex='male',weightcategory='hwt',
                       distance=2000,duration=None):
    if not duration:
        df = pd.DataFrame(
            list(
                C2WorldClassAgePerformance.objects.filter(
                    distance=distance,
                    sex=sex,
                    weightcategory=weightcategory
                ).values()
            )
        )
    else:
        duration = int(duration)*60
        df = pd.DataFrame(
            list(
                C2WorldClassAgePerformance.objects.filter(
                    duration=duration,
                    sex=sex,
                    weightcategory=weightcategory
                ).values()
            )
        )
        

    script,div = interactive_agegroup_plot(df,sex=sex,distance=distance,
                                           duration=duration,
                                           weightcategory=weightcategory)
    
    return render(request, 'agegroupchart.html',
		  {
		   'interactiveplot':script,
		   'the_div':div,
		   })

# Cloning sessions
@user_passes_test(hasplannedsessions,login_url="/rowers/planmembership/",
                  redirect_field_name=None)
def plannedsession_multiclone_view(
        request,timeperiod='none',
        rowerid=0,
        startdate=timezone.now()-datetime.timedelta(days=30),
        enddate=timezone.now()):

    r = getrequestrower(request,rowerid=rowerid)

    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])


    if 'enddate' in request.session:
        enddate = iso8601.parse_date(request.session['enddate'])

    if timeperiod != 'none':
        startdate,enddate = get_dates_timeperiod(timeperiod)
        
        
    if request.method == 'POST' and 'daterange' in request.POST:
        dateform = DateRangeForm(request.POST)
        if dateform.is_valid():
            startdate = dateform.cleaned_data['startdate']
            enddate = dateform.cleaned_data['enddate']
            startdatestring = startdate.strftime('%Y-%m-%d')
            enddatestring = enddate.strftime('%Y-%m-%d')
            request.session['startdate'] = startdatestring
            request.session['enddate'] = enddatestring
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })

    if request.method == 'POST' and 'plannedsessions' in request.POST:
        form = PlannedSessionMultipleCloneForm(request.POST)
        dateshiftform = SessionDateShiftForm(request.POST)
        if form.is_valid() and dateshiftform.is_valid():
            cd = form.cleaned_data
            sps = cd['plannedsessions']
            std = min([ps.startdate for ps in sps])
            shiftstartdate = dateshiftform.cleaned_data['shiftstartdate']
            delta = shiftstartdate-std
            for ps in sps:
                rowers = ps.rower.all()
                teams = ps.team.all()
                ps.pk = None
                ps.startdate += delta
                ps.preferreddate += delta
                ps.enddate += delta
                ps.save()
                for rower in rowers:
                    add_rower_session(rower,ps)
                for team in teams:
                    add_team_session(team,ps)

            url = reverse(plannedsession_multicreate_view,
                          kwargs = {
                              'rowerid':r.id,
                              'timeperiod':timeperiod,
                              })

            return HttpResponseRedirect(url)

    sps = PlannedSession.objects.filter(
        manager=request.user,
        rower__in=[r],
        startdate__lte=enddate,
        enddate__gte=startdate).order_by(
            "startdate","preferreddate","enddate")

    query = request.GET.get('q')
    if query:
        query_list = query.split()
        sps = sps.filter(
            reduce(operator.and_,
                   (Q(name__icontains=q) for q in query_list)) |
            reduce(operator.and_,
                   (Q(comment__icontains=q) for q in query_list))
            )

    form = PlannedSessionMultipleCloneForm()
    form.fields["plannedsessions"].queryset = sps

    dateshiftform = SessionDateShiftForm()

    return render(request, 'plannedsessions_multiclone_select.html',
                  {'plannedsessions':sps,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'form':form,
                   'dateshiftform':dateshiftform,
                   'rower':r,
                   'timeperiod':timeperiod,
                   }
                  )
    
# Individual user creates training for himself
@user_passes_test(hasplannedsessions,login_url="/rowers/planmembership/",
                  redirect_field_name=None)
def plannedsession_create_view(request,timeperiod='thisweek',rowerid=0):

    r = getrequestrower(request,rowerid=rowerid)
        
    if request.method == 'POST':
        sessioncreateform = PlannedSessionForm(request.POST)
        if sessioncreateform.is_valid():
            cd = sessioncreateform.cleaned_data
            startdate = cd['startdate']
            enddate = cd['enddate']
            preferreddate = cd['preferreddate']
            sessiontype = cd['sessiontype']
            sessionmode = cd['sessionmode']
            criterium = cd['criterium']
            sessionvalue = cd['sessionvalue']
            sessionunit = cd['sessionunit']
            comment = cd['comment']
            course = cd['course']
            name = cd['name']

            if sessionunit == 'min':
                sessionmode = 'time'
            elif sessionunit in ['km','m']:
                sessionmode = 'distance'

            ps = PlannedSession(
                name=name,
                startdate=startdate,
                enddate=enddate,
                preferreddate=preferreddate,
                course=course,
                sessiontype=sessiontype,
                sessionmode=sessionmode,
                sessionvalue=sessionvalue,
                sessionunit=sessionunit,
                comment=comment,
                criterium=criterium,
                manager=request.user)

            ps.save()

            add_rower_session(r,ps)

            request.session['fstartdate'] = str(arrow.get(startdate))
            request.session['fenddate'] = str(arrow.get(enddate))
            request.session['fprefdate'] = str(arrow.get(preferreddate))

            url = reverse(plannedsession_create_view,
                          kwargs = {
                              'rowerid':r.id,
                              'timeperiod':timeperiod,
                          })
            return HttpResponseRedirect(url)
    else:
        if 'fstartdate' in request.session:
            try:
                fstartdate = arrow.get(request.session['fstartdate']).date()
            except KeyError:
                fstartdate = timezone.now().date()
            try:
                fenddate = arrow.get(request.session['fenddate']).date()
            except KeyError:
                fenddate = timezone.now().date()
            try:
                fprefdate = arrow.get(request.session['fprefdate']).date()
            except KeyError:
                fprefdate = timezone.now().date()

            forminitial = {
                'startdate':fstartdate,
                'enddate':fenddate,
                'preferreddate':fprefdate
                }
        else:
            forminitial = {}

        sessioncreateform = PlannedSessionForm(initial=forminitial)

    startdate,enddate = get_dates_timeperiod(timeperiod)
    sps = get_sessions(r,startdate=startdate,enddate=enddate)
        
    return render(request,'plannedsessioncreate.html',
                  {
                      'teams':get_my_teams(request.user),
                      'form':sessioncreateform,
                      'plannedsessions':sps,
                      'rower':r,
                      'timeperiod':timeperiod,
                  })

@user_passes_test(hasplannedsessions,login_url="/rowers/planmembership/",
                  redirect_field_name=None)
def plannedsession_multicreate_view(request,timeperiod='thisweek',
                                    teamid=0,rowerid=0,extrasessions=0):

    extrasessions=int(extrasessions)

    r = getrequestrower(request,rowerid=rowerid)

    startdate,enddate = get_dates_timeperiod(timeperiod)
    sps = get_sessions(r,startdate=startdate,enddate=enddate)

    m = Rower.objects.get(user=request.user)

    if m.rowerplan == 'coach':
        teams = Team.objects.filter(manager=request.user)
        members = Rower.objects.filter(team__in=teams).distinct()
        if r in members:
            qset = PlannedSession.objects.filter(
                rower__in=[r],
                startdate__lte=enddate,
                enddate__gte=startdate,
            ).order_by("startdate","preferreddate","enddate")
        else:
            qset = []
    else:
        qset = []

    if not qset:
            qset = PlannedSession.objects.filter(
                rower__in=[r],
                manager = request.user,
                startdate__lte=enddate,
                enddate__gte=startdate,
            ).order_by("startdate","preferreddate","enddate")
        


    initial = {
        'startdate':startdate,
        'enddate':enddate,
        'sessionvalue':60,
        'manager':request.user,
        'name': 'NEW SESSION'
    }

    
        
    initials = [initial for i in range(extrasessions)]
    PlannedSessionFormSet = modelformset_factory(
        PlannedSession,
        form=PlannedSessionFormSmall,
        can_delete=True,
        extra=extrasessions,
    )
    if request.method == "POST":
        ps_formset = PlannedSessionFormSet(queryset = qset,
                                           data = request.POST)
        if ps_formset.is_valid():
            instances = ps_formset.save(commit=False)
            for ps in instances:
                ps.save()
                add_rower_session(r,ps)
                messages.info(request,"Saved changes for Planned Session "+str(ps))
            for obj in ps_formset.deleted_objects:
                messages.info(request,"Deleted Planned Session "+str(obj))
                obj.delete()
        else:
            print ps_formset.errors

        url = reverse(plannedsession_multicreate_view,
                      kwargs = {
                          'rowerid':r.id,
                          'timeperiod':timeperiod
                          }
                      )
        return HttpResponseRedirect(url)

    ps_formset = PlannedSessionFormSet(queryset = qset,
                                       initial=initials)

    context = {
        'ps_formset':ps_formset,
        'rower':r,
        'timeperiod':timeperiod,
        'teams':get_my_teams(request.user),
        'extrasessions': extrasessions+1
        }

    return render(request,'plannedsession_multicreate.html',context)

# Manager creates sessions for entire team
@user_passes_test(iscoachmember,login_url="/rowers/planmembership/",
                  redirect_field_name=None)
def plannedsession_teamcreate_view(request,timeperiod='thisweek',
                                   teamid=0):


    teams = Team.objects.filter(manager=request.user)
    if len(teams)>0:
        teamchoices = [(team.id, team.name) for team in teams]
        teaminitial = [str(teams[0].id)]
    else:
        messages.info(request,"You have no teams established yet. We are redirecting you to the Team Management page.")
        url = reverse(rower_teams_view)
        return HttpResponseRedirect(url)

    startdate,enddate = get_dates_timeperiod(timeperiod)

    sps = []
    for team in teams:
        res = get_sessions_manager(request.user,startdate=startdate,enddate=enddate)
        sps += res

    sps = list(set(sps))
        
    if request.method == 'POST':
        sessioncreateform = PlannedSessionForm(request.POST)
        sessionteamselectform = PlannedSessionTeamForm(
            request.user,request.POST
        ) 
        if sessioncreateform.is_valid():
            cd = sessioncreateform.cleaned_data
            startdate = cd['startdate']
            enddate = cd['enddate']
            preferreddate = cd['preferreddate']
            sessiontype = cd['sessiontype']
            sessionmode = cd['sessionmode']
            criterium = cd['criterium']
            sessionvalue = cd['sessionvalue']
            sessionunit = cd['sessionunit']
            comment = cd['comment']
            course = cd['course']
            name = cd['name']

            if sessionunit == 'min':
                sessionmode = 'time'
            elif sessionunit in ['km','m']:
                sessionmode = 'distance'

            ps = PlannedSession(
                name=name,
                startdate=startdate,
                enddate=enddate,
                preferreddate=preferreddate,
                sessiontype=sessiontype,
                sessionmode=sessionmode,
                sessionvalue=sessionvalue,
                sessionunit=sessionunit,
                comment=comment,
                criterium=criterium,
                course=course,
                manager=request.user)

            ps.save()

            # some logic when to add all selected rowers 
            if sessionteamselectform.is_valid():
                cd = sessionteamselectform.cleaned_data
                teams = cd['team']
                for team in teams:
                    add_team_session(team,ps)
                    rs = Rower.objects.filter(team__in=[team])
                    for r in rs:
                        add_rower_session(r,ps)
            
            
            url = reverse(plannedsession_teamcreate_view,
                          kwargs = {
                              'timeperiod':timeperiod,
                          })
            return HttpResponseRedirect(url)
    else:
        sessioncreateform = PlannedSessionForm()
        sessionteamselectform = PlannedSessionTeamForm(
            request.user
        )

    return render(request,'plannedsessionteamcreate.html',
                  {
                      'teams':get_my_teams(request.user),
                      'form':sessioncreateform,
                      'teamform':sessionteamselectform,
                      'timeperiod':timeperiod,
                      'plannedsessions':sps,
                      'rower':getrower(request.user),
                  })

# Manager edits sessions for entire team
@user_passes_test(iscoachmember,login_url="/rowers/planmembership/",
                  redirect_field_name=None)
def plannedsession_teamedit_view(request,timeperiod='thisweek',
                                   sessionid=0):

    try:
        ps = PlannedSession.objects.get(id=sessionid)
    except PlannedSession.DoesNotExist:
        raise Http404("This session doesn't exist")
    if not ps.manager == request.user:
        raise PermissionDenied("You are not the manager of this session")
        
    teams = Team.objects.filter(manager=request.user)
    teamchoices = [(team.id, team.name) for team in teams]

    teaminitial = ps.team.all()

    startdate,enddate = get_dates_timeperiod(timeperiod)

    sps = []
    rowers = []
    for team in teams:
        res = get_sessions_manager(request.user,startdate=startdate,enddate=enddate)
        sps += res
        rowers += Rower.objects.filter(team__in=[team])

    rowers = list(set(rowers))


    sps = list(set(sps))
        
    if request.method == 'POST':
        sessioncreateform = PlannedSessionForm(request.POST,instance=ps)
        sessionteamselectform = PlannedSessionTeamForm(
            request.user,request.POST
        )
        sessionrowerform = PlannedSessionTeamMemberForm(ps,request.POST)
        if sessioncreateform.is_valid():
            cd = sessioncreateform.cleaned_data

            if cd['sessionunit'] == 'min':
                cd['sessionmode'] = 'time'
            elif cd['sessionunit'] in ['km','m']:
                cd['sessionmode'] = 'distance'
 

            res,message = update_plannedsession(ps,cd)
                
            if res:
                messages.info(request,message)
            else:
                messages.error(request,message)


            # some logic when to add all selected rowers 
            if sessionteamselectform.is_valid():
                cd = sessionteamselectform.cleaned_data
                selectedteams = cd['team']
                for team in teams:
                    if team in selectedteams:
                        add_team_session(team,ps)
                        rs = Rower.objects.filter(team__in=[team])
                        for r in rs:
                            add_rower_session(r,ps)
                    else:
                        remove_team_session(team,ps)
            else:
                selectedteams = []
                            
                            
            if sessionrowerform.is_valid():
                cd = sessionrowerform.cleaned_data
                selectedrowers = cd['members']
                for r in rowers:
                    if r in selectedrowers:
                        add_rower_session(r,ps)
                    else:
                        remove_rower_session(r,ps)
                        for t in selectedteams:
                            if t in r.team.all():
                                add_rower_session(r,ps)
                            
            
            url = reverse(plannedsession_teamedit_view,
                          kwargs = {
                              'sessionid':sessionid,
                              'timeperiod':timeperiod,
                          })
            return HttpResponseRedirect(url)
    else:
        sessioncreateform = PlannedSessionForm(instance=ps)
        sessionteamselectform = PlannedSessionTeamForm(
            request.user
        )
        sessionteamselectform.fields['team'].initial = teaminitial
        sessionrowerform = PlannedSessionTeamMemberForm(
            ps
            )

        
        sessionrowerform.fields['members'].initial = ps.rower.all()

    return render(request,'plannedsessionteamedit.html',
                  {
                      'plannedsession':ps,
                      'teams':get_my_teams(request.user),
                      'form':sessioncreateform,
                      'teamform':sessionteamselectform,
                      'rowersform':sessionrowerform,
                      'timeperiod':timeperiod,
                      'plannedsessions':sps,
                  })

@user_passes_test(iscoachmember,login_url="/rowers/planmembership/",
                  redirect_field_name=None)
def plannedsessions_coach_view(request,timeperiod='thisweek',
                               teamid=0):

    startdate,enddate = get_dates_timeperiod(timeperiod)

    if teamid != 0:
        try:
            theteam = Team.objects.get(id=teamid)
        except Team.DoesNotExist:
            theteam = False
    else:
        theteam = False
            
    sps = get_sessions_manager(request.user,teamid=teamid,
                               enddate=enddate,
                               startdate=startdate)

    rowers = []
    for ps in sps:
        rowers += ps.rower.all()

    rowers = list(set(rowers))

    statusdict = []
    
    for ps in sps:
        rowerstatus = {}
        for r in rowers:
            ratio, status,completiondate = is_session_complete(r,ps)
            rowerstatus[r.id] = status
        sessiondict = {
            'id': ps.id,
            'results':rowerstatus,
            'name': ps.name,
            'startdate': ps.startdate,
            'preferreddate': ps.preferreddate,
            'enddate': ps.enddate,
            }
        statusdict.append(sessiondict)

    unmatchedworkouts = []
    for r in rowers:
        unmatchedworkouts += Workout.objects.filter(
        user=r,
        plannedsession=None,
        date__gte=startdate,date__lte=enddate)
        
        
    myteams = Team.objects.filter(manager=request.user)
    
    return render(request,'plannedsessionscoach.html',
                  {
                      'myteams':myteams,
                      'plannedsessions':sps,
                      'statusdict':statusdict,
                      'timeperiod':timeperiod,
                      'rowers':rowers,
                      'theteam':theteam,
                      'unmatchedworkouts':unmatchedworkouts,
                      'rower':getrower(request.user)
                      }
                  )

@login_required()
def plannedsessions_view(request,timeperiod='thisweek',rowerid=0):

    r = getrequestrower(request,rowerid=rowerid)

    startdate,enddate = get_dates_timeperiod(timeperiod)
        
    sps = get_sessions(r,startdate=startdate,enddate=enddate)

    completeness = {}
    actualvalue = {}
    completiondate = {}
    
    for ps in sps:
        ratio,status,cdate = is_session_complete(r,ps)
        actualvalue[ps.id] = int(ps.sessionvalue*ratio)
        completeness[ps.id] = status
        ws = Workout.objects.filter(user=r,plannedsession=ps)
        completiondate[ps.id] = cdate

    unmatchedworkouts = Workout.objects.filter(
        user=r,
        plannedsession=None,
        date__gte=startdate,date__lte=enddate)
            
    return render(request,'plannedsessions.html',
                  {
                      'teams':get_my_teams(request.user),
                      'plannedsessions':sps,
                      'rower':r,
                      'timeperiod':timeperiod,
                      'completeness':completeness,
                      'actualvalue':actualvalue,
                      'completiondate':completiondate,
                      'unmatchedworkouts':unmatchedworkouts,
                  })

@login_required()
def plannedsessions_print_view(request,timeperiod='thisweek',rowerid=0):

    r = getrequestrower(request,rowerid=rowerid)

    startdate,enddate = get_dates_timeperiod(timeperiod)
        
    sps = get_sessions(r,startdate=startdate,enddate=enddate)

    completeness = {}
    actualvalue = {}
    completiondate = {}
    
    return render(request,'plannedsessions_print.html',
                  {
                      'teams':get_my_teams(request.user),
                      'plannedsessions':sps,
                      'rower':r,
                      'startdate':startdate,
                      'enddate':enddate,
                      'timeperiod':timeperiod,
                  })


@login_required()
def plannedsessions_manage_view(request,timeperiod='thisweek',rowerid=0,
                                initialsession=0):

    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    r = getrequestrower(request,rowerid=rowerid)

    startdate,enddate = get_dates_timeperiod(timeperiod)
                
    sps = get_sessions(r,startdate=startdate,enddate=enddate)
    if initialsession==0:
        try:
            initialsession=sps[0].id
        except IndexError:
            initialsession=0

    if initialsession:
        ps0 = PlannedSession.objects.get(id=initialsession)
    else:
        ps0 = None

    ws = Workout.objects.filter(
        user=r,date__gte=startdate,
        date__lte=enddate
    ).order_by(
        "date","startdatetime","id"
        )


    initialworkouts = [w.id for w in Workout.objects.filter(user=r,plannedsession=ps0)]

    linkedworkouts = []
    for w in ws:
        if w.plannedsession is not None:
            linkedworkouts.append(w.id)

    plannedsessionstuple = []

    for ps in sps:
        sessiontpl = (ps.id,ps.__unicode__())
        plannedsessionstuple.append(sessiontpl)

    plannedsessionstuple = tuple(plannedsessionstuple)

    workoutdata = {}
    workoutdata['initial'] = []

    choices = []
    
    for w in ws:
        wtpl = (w.id, w.__unicode__())
        choices.append(wtpl)
        if w.id in initialworkouts:
            workoutdata['initial'].append(w.id)

    workoutdata['choices'] = tuple(choices)

    if request.method == 'POST':
        ps_form = PlannedSessionSelectForm(plannedsessionstuple,request.POST)
        w_form = WorkoutSessionSelectForm(workoutdata,request.POST)

        if ps_form.is_valid():
            ps = PlannedSession.objects.get(id=ps_form.cleaned_data['plannedsession'])
            if w_form.is_valid():
                selectedworkouts = w_form.cleaned_data['workouts']
            else:
                selectedworkouts = []

            if len(selectedworkouts)==0:
                for w in ws:
                    remove_workout_plannedsession(w,ps)

            if selectedworkouts:
                workouts = Workout.objects.filter(user=r,id__in=selectedworkouts)
                for w in ws:
                    if w.id not in selectedworkouts:
                        remove_workout_plannedsession(w,ps)
                        
                result,comments,errors = add_workouts_plannedsession(workouts,ps,r)
                for c in comments:
                    messages.info(request,c)
                for er in errors:
                    messages.error(request,er)


    ps_form = PlannedSessionSelectForm(plannedsessionstuple,
                                       initialsession=initialsession)
    w_form = WorkoutSessionSelectForm(workoutdata=workoutdata)


    if is_ajax:
        ajax_workouts = []
        for id,name in workoutdata['choices']:
            ininitial = id in initialworkouts
            inlinked = id in linkedworkouts
            ajax_workouts.append((id,name,ininitial,inlinked))
                
        ajax_response = {
            'workouts':ajax_workouts,
            'plannedsessionstuple':plannedsessionstuple,
        }

        
        return JSONResponse(ajax_response)

    
    return render(request,'plannedsessionsmanage.html',
                  {
                      'teams':get_my_teams(request.user),
                      'plannedsessions':sps,
                      'workouts':ws,
                      'timeperiod':timeperiod,
                      'rower':r,
                      'ps_form':ps_form,
                      'w_form':w_form,
                  })
    

# Clone an existing planned session
@user_passes_test(hasplannedsessions,login_url="/rowers/planmembership/",
                  redirect_field_name=None)
def plannedsession_clone_view(request,id=0,rowerid=0,
                              timeperiod='thisweek'):

    r = getrequestrower(request,rowerid=rowerid)

    startdate,enddate = get_dates_timeperiod(timeperiod)

    try:
        ps = PlannedSession.objects.get(id=id)
    except PlannedSession.DoesNotExist:
        raise Http404("Planned Session does not exist")
        
    if ps.manager != request.user:
        raise PermissionDenied("You are not allowed to clone this planned session")

    rowers = ps.rower.all()
    teams = ps.team.all()
    
    ps.pk = None

    deltadays = ps.enddate-ps.startdate
    
    ps.startdate = timezone.now().date()
    ps.enddate = (timezone.now()+deltadays).date()
    ps.name += ' (copy)'
    
    ps.save()

    for rower in rowers:
        add_rower_session(rower,ps)
    for team in teams:
        add_team_session(team,ps)

    url = reverse(plannedsession_edit_view,
                  kwargs = {
                      'id':ps.id,
                      'timeperiod':timeperiod,
                      'rowerid':r.id,
                      }
                  )

    return HttpResponseRedirect(url)


# Edit an existing planned session
@user_passes_test(hasplannedsessions,login_url="/rowers/planmembership/",
                  redirect_field_name=None)
def plannedsession_edit_view(request,id=0,timeperiod='thisweek',rowerid=0):

    r = getrequestrower(request,rowerid=rowerid)

    startdate,enddate = get_dates_timeperiod(timeperiod)


    try:
        ps = PlannedSession.objects.get(id=id)
    except PlannedSession.DoesNotExist:
        raise Http404("Planned Session does not exist")
        
    if ps.manager != request.user:
        raise PermissionDenied("You are not allowed to edit this planned session")

    if ps.team.all() or len(ps.rower.all())>1:
        url = reverse(plannedsession_teamedit_view,
                      kwargs={
                          'timeperiod':timeperiod,
                          'sessionid':id,
                          })
        return HttpResponseRedirect(url)

    if request.method == 'POST':
        sessioncreateform = PlannedSessionForm(request.POST,instance=ps)
        if sessioncreateform.is_valid():
            cd = sessioncreateform.cleaned_data

            if cd['sessionunit'] == 'min':
                cd['sessionmode'] = 'time'
            elif cd['sessionunit'] in ['km','m']:
                cd['sessionmode'] = 'distance'
            

            res,message = update_plannedsession(ps,cd)

            if res:
                messages.info(request,message)
            else:
                messages.error(request,message)

            url = reverse(plannedsession_edit_view,
                          kwargs={
                              'id':int(ps.id),
                              'timeperiod':timeperiod,
                              'rowerid':r.id,
                          })
            return HttpResponseRedirect(url)
    else:
        sessioncreateform = PlannedSessionForm(instance=ps)

    sps = get_sessions(r,startdate=startdate,enddate=enddate)
        
    return render(request,'plannedsessionedit.html',
                  {
                      'teams':get_my_teams(request.user),
                      'form':sessioncreateform,
                      'plannedsessions':sps,
                      'thesession':ps,
                      'rower':r,
                      'timeperiod':timeperiod,
                  })



@login_required()
def plannedsession_view(request,id=0,rowerid=0,
                        timeperiod='thisweek'):

    m = getrower(request.user)


    if not rowerid:
        r = m
    else:
        r = Rower.objects.get(id=rowerid)

    try:
        ps = PlannedSession.objects.get(id=id)
    except PlannedSession.DoesNotExist:
        raise Http404("Planned Session does not exist")


    if ps.course:
        coursescript,coursediv = course_map(ps.course)
    else:
        coursescript = ''
        coursediv = ''

    if ps.manager != request.user:
        if r.rowerplan == 'coach':
            teams = Team.objects.filter(manager=request.user)
            members = Rower.objects.filter(team__in=teams).distinct()
            teamusers = [m.user for m in members]
            if ps.manager not in teamusers:
                raise PermissionDenied("You do not have access to this session")
        elif r not in ps.rower.all():
            raise PermissionDenied("You do not have access to this session")

    resultsdict = get_session_metrics(ps)
    resultsdict = pd.DataFrame(resultsdict).transpose().to_dict()
    
    psdict = my_dict_from_instance(ps,PlannedSession)

    ws = get_workouts_session(r,ps)

    ratio,status,completiondate = is_session_complete(r,ps)
    
    ratio = int(100.*ratio)

    # ranking for test
    ranking = []

    if ps.sessiontype in ['test','coursetest']:
        if ps.sessionmode == 'distance':
            rankws = Workout.objects.filter(
                plannedsession=ps).order_by("duration")
        else:
            rankws = Workout.objects.filter(
                plannedsession=ps).order_by("-distance")
        for w in rankws:
            dd = w.duration
            dddelta = datetime.timedelta(hours=dd.hour,
                                         minutes=dd.minute,
                                         seconds=dd.second,
                                         microseconds=dd.microsecond)
            wdict = {
                'name': w.user.user.first_name+' '+w.user.user.last_name,
                'date': w.date,
                'distance': w.distance,
                'time': dddelta,
                'type': w.workouttype,
            }
            if ps.sessiontype == 'coursetest':
                vs = CourseTestResult.objects.filter(plannedsession=ps)
                if vs:
                    for record in vs:
                        if record.workoutid == w.id:
                            coursemeters = record.distance
                            coursecompleted = record.coursecompleted
                            t = record.duration
                            wdict['time'] = datetime.timedelta(
                                hours=t.hour,
                                seconds=t.second,
                                minutes=t.minute,
                                microseconds=t.microsecond
                            )
                            wdict['distance'] = int(round(coursemeters))
                else:
                    (
                        coursetimeseconds,
                        coursemeters,
                        coursecompleted
                    ) = courses.get_time_course([w],ps.course)
                    intsecs = int(coursetimeseconds)
                    microsecs = int(1.e6*(coursetimeseconds-intsecs))

                    wdict['time'] = datetime.timedelta(
                        seconds=intsecs,
                        microseconds=microsecs
                    )
                    wdict['distance'] = int(round(coursemeters))

                
            ranking.append(wdict)
            if ps.sessiontype == 'coursetest':
                ranking = sorted(ranking, key=lambda k: k['time'])

            # if coursetest, need to reorder the ranking

    
    return render(request,'plannedsessionview.html',
                  {
                      'psdict': psdict,
                      'attrs':[
                          'name','startdate','enddate','preferreddate',
                          'sessiontype',
                          'sessionmode','criterium',
                          'sessionvalue','sessionunit','comment',
                      ],
                      'workouts': ws,
                      'manager':m,
                      'rower':r,
                      'ratio':ratio,
                      'status':status,
                      'results':resultsdict,
                      'plannedsession':ps,
                      'timeperiod':timeperiod,
                      'ranking':ranking,
                      'coursescript': coursescript,
                      'coursediv': coursediv
                      }
                  )

@login_required()
def plannedsession_delete_view(request,id=0):
    r = getrower(request.user)

    try:
        ps = PlannedSession.objects.get(id=id)
    except PlannedSession.DoesNotExist:
        raise Http404("Planned Session does not exist")


    if ps.manager != request.user:
        raise PermissionDenied("You are not allowed to delete this planned session")

    ws = Workout.objects.filter(plannedsession=ps)
    for w in ws:
        w.plannedsession=None
        w.save()
    
    ps.delete()

    url = reverse(plannedsessions_view)

    return HttpResponseRedirect(url)
    
@login_required()
def plannedsession_deleteconfirm_view(request,id=0):

    r = getrower(request.user)

    try:
        ps = PlannedSession.objects.get(id=id)
    except PlannedSession.DoesNotExist:
        raise Http404("Planned Session does not exist")


    if ps.manager != request.user:
        raise PermissionDenied("You are not allowed to delete this planned session")

    
    psdict = my_dict_from_instance(ps,PlannedSession)
    
    return render(request,'plannedsessiondeleteconfirm.html',
                  {
                      'ps':ps,
                      'psdict': psdict,
                      'attrs':[
                          'name','startdate','enddate','sessiontype',
                      ],
                      'rower':r,
                      }
                  
                  )

def virtualevents_view(request):
    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    # default races
    races1 = VirtualRace.objects.filter(
        startdate__gte=datetime.date.today(),
    )
    races2 = VirtualRace.objects.filter(
        startdate__lte=datetime.date.today(),
        evaluation_closure__gte=timezone.now(),
    )

                
    races = (races1 | races2).order_by("startdate","start_time")

    if not request.user.is_anonymous():
        r = getrower(request.user)
    else:
        r = None

    if request.method == 'POST':
        # process form
        form = VirtualRaceSelectForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            country = cd['country']
            regattatype = cd['regattatype']
            if country == 'All':
                countries = VirtualRace.objects.order_by('country').values_list('country').distinct()
            else:
                countries = [country]

            if regattatype == 'upcoming':
                races1 = VirtualRace.objects.filter(
                    startdate__gte=datetime.date.today(),
                    country__in=countries
                )
                races2 = VirtualRace.objects.filter(
                    startdate__lte=datetime.date.today(),
                    evaluation_closure__gte=timezone.now(),
                    country__in=countries
                    )

                
                races = (races1 | races2).order_by("startdate","start_time")


            elif regattatype == 'previous':
                races = VirtualRace.objects.filter(
                    evaluation_closure__lt=timezone.now(),
                    country__in=countries
                    ).order_by("startdate","start_time")
            elif regattatype == 'ongoing':
                races = VirtualRace.objects.filter(
                    startdate__lte=datetime.date.today(),
                    evaluation_closure__gte=timezone.now(),
                    country__in=countries
                    ).order_by("startdate","start_time")
            elif regattatype == 'my':
                mysessions = get_my_session_ids(r)
                races = VirtualRace.objects.filter(
                    id__in=mysessions,
                    country__in=countries
                    ).order_by("startdate","start_time")
            elif regattatype == 'all':
                races = VirtualRace.objects.filter(
                    country__in=countries
                    ).order_by("startdate","start_time")
    else:
    
        form = VirtualRaceSelectForm()

    if is_ajax:
        return render(request,'racelist.html',
                      { 'races':races,
                        'rower':r,
                        })
        
    return render(request,'virtualevents.html',
                  { 'races':races,
                    'form':form,
                    'rower':r,
                  }
    )

def virtualevent_view(request,id=0):
    if not request.user.is_anonymous():
        r = getrower(request.user)
    else:
        r = None

        
    try:
        race = VirtualRace.objects.get(id=id)
    except VirtualRace.DoesNotExist:
        raise Http404("Virtual Race does not exist")

    script,div = course_map(race.course)


    records = VirtualRaceResult.objects.filter(
        race=race
        )
    
    buttons = []

    if not request.user.is_anonymous():
        if race_can_register(r,race):
            buttons += ['registerbutton']

        if race_can_adddiscipline(r,race):
            buttons += ['adddisciplinebutton']

        if race_can_submit(r,race):
            buttons += ['submitbutton']

        if race_can_resubmit(r,race):
            buttons += ['resubmitbutton']

        if race_can_withdraw(r,race):
            buttons += ['withdrawbutton']

        if race_can_edit(r,race):
            buttons += ['editbutton']

    if request.method == 'POST':
        form = RaceResultFilterForm(request.POST,records=records)
        if form.is_valid():
            cd = form.cleaned_data
            try:
                sex = cd['sex']
            except KeyError:
                sex = ['female','male','mixed']

            try:
                boattype = cd['boattype']
            except KeyError:
                boattype = types.waterboattype

            try:                
                boatclass = cd['boatclass']
            except KeyError:
                boatclass = [t for t in types.otwtypes]
                
            age_min = cd['age_min']
            age_max = cd['age_max']

            try:
                weightcategory = cd['weightcategory']
            except KeyError:
                weightcategory = ['hwt','lwt']

            results = VirtualRaceResult.objects.filter(
                race=race,
                workoutid__isnull=False,
                boatclass__in=boatclass,
                boattype__in=boattype,
                sex__in=sex,
                weightcategory__in=weightcategory,
                age__gte=age_min,
                age__lte=age_max
                ).order_by("duration")
        
            # to-do - add DNS
            dns = []
            if timezone.now() > race.evaluation_closure:
                dns = VirtualRaceResult.objects.filter(
                    race=race,
                    workoutid__isnull=True,
                    boatclass__in=boatclass,
                    boattype__in=boattype,
                    sex__in=sex,
                    weightcategory__in=weightcategory,
                    age__gte=age_min,
                    age__lte=age_max
                )
    else:
        results = VirtualRaceResult.objects.filter(
            race=race,
            workoutid__isnull=False,
        ).order_by("duration")

        if results:
            form = RaceResultFilterForm(records=records)
        else:
            form = None
            
        # to-do - add DNS
        dns = []
        if timezone.now() > race.evaluation_closure:
            dns = VirtualRaceResult.objects.filter(
                race=race,
                workoutid__isnull=True,
            )

        
        

    return render(request,'virtualevent.html',
                  {
                      'coursescript':script,
                      'coursediv':div,
                      'race':race,
                      'rower':r,
                      'results':results,
                      'buttons':buttons,
                      'dns':dns,
                      'records':records,
                      'form':form,
                      })

@login_required()
def virtualevent_withdraw_view(request,id=0,recordid=None):
    r = getrower(request.user)
    try:
        race = VirtualRace.objects.get(id=id)
    except VirtualRace.DoesNotExist:
        raise Http404("Virtual Race does not exist")

    if race_can_withdraw(r,race):
        remove_rower_race(r,race,recordid=recordid)
        messages.info(request,
                      "You have successfully withdrawn from this race.")
    else:
        messages.error(request,"You cannot withdraw from this race")

    url = reverse(virtualevent_view,
                  kwargs = {
                      'id':race.id
                      })

    return HttpResponseRedirect(url)

@login_required()
def virtualevent_addboat_view(request,id=0):
    r = getrower(request.user)
    try:
        race = VirtualRace.objects.get(id=id)
    except VirtualRace.DoesNotExist:
        raise Http404("Virtual Race does not exist")

    if not race_can_adddiscipline(r,race):
        messages.error(request,"You cannot register for this race")

        url = reverse(virtualevent_view,
                      kwargs = {
                          'id':race.id
                      })

        return HttpResponseRedirect(url)

    records = VirtualRaceResult.objects.filter(
        userid = r.id,
        race = race
        )

    boattypes = [record.boattype for record in records]
    boatclasses = [record.boatclass for record in records]
    allowedboats = tuple([ type for type in types.boattypes if type[0] not in boattypes] )
    

    # we're still here
    if request.method == 'POST':
        # process form
        form = VirtualRaceResultForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            teamname = cd['teamname']
            boattype = cd['boattype']
            boatclass = cd['boatclass']
            weightcategory = cd['weightcategory']
            age = cd['age']
            mix = cd['mix']

            sex = r.sex
            if mix:
                sex = 'mixed'
            
            if boattype == '1x' and r.birthdate:
                age = calculate_age(r.birthdate)
                sex = r.sex

            if sex == 'not specified':
                sex = 'male'
            
            if boattype in boattypes and boatclass in boatclasses:
                # check if different sexes
                therecords = records.filter(
                    boattype=boattype,
                    boatclass=boatclass)

                thesexes = [record.sex for record in therecords]
                if sex in thesexes:
                
                    messages.error(
                        request,
                        "You have already registered in that boat class/type"
                    )
                    url = reverse(virtualevent_view,
                                  kwargs = {
                                      'id': race.id
                                  }
                              )

                    return HttpResponseRedirect(url)

            record = VirtualRaceResult(
                userid=r.id,
                teamname=teamname,
                race=race,
                username = u'{f} {l}'.format(
                    f = r.user.first_name,
                    l = r.user.last_name
                ),
                weightcategory=weightcategory,
                duration=datetime.time(0,0),
                boattype=boattype,
                boatclass=boatclass,
                coursecompleted=False,
                sex=sex,
                age=age
                )

            record.save()
                
            add_rower_race(r,race)

            
            
            messages.info(
                request,
                "You have successfully registered for this race. Good luck!"
            )

            url = reverse(virtualevent_view,
                          kwargs = {
                              'id':race.id
                          })

            return HttpResponseRedirect(url)
        
    else:
        initial = {
            'age': calculate_age(r.birthdate),
            'weightcategory': r.weightcategory,
            }
        
        form = VirtualRaceResultForm(initial=initial)

    return render(request,'virtualeventregister.html',
                  {
                      'form':form,
                      'race':race,
                      'rowerid':r.id,

                  })

@login_required()
def virtualevent_register_view(request,id=0):
    r = getrower(request.user)
    try:
        race = VirtualRace.objects.get(id=id)
    except VirtualRace.DoesNotExist:
        raise Http404("Virtual Race does not exist")

    if not race_can_register(r,race):
        messages.error(request,"You cannot register for this race")

        url = reverse(virtualevent_view,
                      kwargs = {
                          'id':race.id
                      })

        return HttpResponseRedirect(url)

    # we're still here
    if request.method == 'POST':
        # process form
        form = VirtualRaceResultForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            teamname = cd['teamname']
            boattype = cd['boattype']
            boatclass = cd['boatclass']
            weightcategory = cd['weightcategory']
            age = cd['age']
            mix = cd['mix']

            sex = r.sex
            if mix:
                sex = 'mixed'
            
            if boattype == '1x' and r.birthdate:
                age = calculate_age(r.birthdate)
                sex = r.sex

            if sex == 'not specified':
                sex = 'male'

            record = VirtualRaceResult(
                userid=r.id,
                teamname=teamname,
                race=race,
                username = u'{f} {l}'.format(
                    f = r.user.first_name,
                    l = r.user.last_name
                ),
                weightcategory=weightcategory,
                duration=datetime.time(0,0),
                boatclass=boatclass,
                boattype=boattype,
                coursecompleted=False,
                sex=sex,
                age=age
                )

            record.save()
                
            add_rower_race(r,race)

            
            
            messages.info(
                request,
                "You have successfully registered for this race. Good luck!"
            )

            url = reverse(virtualevent_view,
                          kwargs = {
                              'id':race.id
                          })

            return HttpResponseRedirect(url)
        
    else:
        initial = {
            'age': calculate_age(r.birthdate),
            'weightcategory': r.weightcategory,
            }
        
        form = VirtualRaceResultForm(initial=initial)

    return render(request,'virtualeventregister.html',
                  {
                      'form':form,
                      'race':race,
                      'rowerid':r.id,

                  })

@login_required()
def virtualevent_create_view(request):
    r = getrower(request.user)
        
    if request.method == 'POST':
        racecreateform = VirtualRaceForm(request.POST)
        if racecreateform.is_valid():
            cd = racecreateform.cleaned_data
            startdate = cd['startdate']
            start_time = cd['start_time']
            enddate = cd['enddate']
            end_time = cd['end_time']
            comment = cd['comment']
            course = cd['course']
            name = cd['name']
            registration_form = cd['registration_form']
            registration_closure = cd['registration_closure']
            evaluation_closure = cd['evaluation_closure']
            contact_phone = cd['contact_phone']
            contact_email = cd['contact_email']

            # correct times

            geocourse = GeoCourse.objects.get(id= course.id)
            timezone_str = courses.get_course_timezone(geocourse)

            startdatetime = datetime.datetime.combine(startdate,start_time)
            enddatetime = datetime.datetime.combine(enddate,end_time)

            
            startdatetime = pytz.timezone(timezone_str).localize(
                startdatetime
            )
            enddatetime = pytz.timezone(timezone_str).localize(
                enddatetime
            )
            evaluation_closure = pytz.timezone(timezone_str).localize(
                evaluation_closure.replace(tzinfo=None)
            )

            if registration_form == 'manual':
                try:
                    registration_closure = pytz.timezone(
                        timezone_str
                    ).localize(
                        registration_closure.replace(tzinfo=None)
                    )
                except AttributeError:
                    registration_closure = startdatetime
            elif registration_form == 'windowstart':
                registration_closure = startdatetime
            elif registration_form == 'windowend':
                registration_closure = enddatetime
            else:
                registration_closure = evaluation_closure
                
            
            vs = VirtualRace(
                name=name,
                startdate=startdate,
                preferreddate = startdate,
                start_time = start_time,
                enddate=enddate,
                end_time=end_time,
                course=geocourse,
                comment=comment,
                sessiontype = 'race',
                timezone=timezone_str,
                evaluation_closure=evaluation_closure,
                registration_closure=registration_closure,
                contact_phone=contact_phone,
                contact_email=contact_email,
                country = course.country,
                manager=request.user,
            )

            vs.save()

            # create Site Announcement & Tweet
            if settings.DEBUG:
                dotweet = False
            elif 'dev' in settings.SITE_URL:
                dotweet = False
            else:
                dotweet = True
            try:
                sa = SiteAnnouncement(
                    announcement = "New Virtual Race on rowsandall.com: {name} on course {course}".format(
                        name = name.encode('utf8'),
                        course = course.name.encode('utf8')
                    ),
                    dotweet = dotweet
                )

                sa.save()
            except UnicodeEncodeError:
                sa = SiteAnnouncement(
                    announcement = "New Virtual Race on rowsandall.com: {name} on course {course}".format(
                        name = name,
                        course = str(course.name.encode('utf8','ignore'))
                    ),
                    dotweet = dotweet
                )
                

                sa.save()

            url = reverse(virtualevents_view)
            return HttpResponseRedirect(url)
    else:

        racecreateform = VirtualRaceForm()

        
    return render(request,'virtualeventcreate.html',
                  {
                      'form':racecreateform,
                      'rower':r,

                  })

@login_required()
def virtualevent_edit_view(request,id=0):
    r = getrower(request.user)
        
    try:
        race = VirtualRace.objects.get(id=id)
        if race.manager != request.user:
            raise PermissionDenied("Access denied")
    except VirtualRace.DoesNotExist:
        raise Http404("Virtual Race does not exist")

    start_time = race.start_time
    start_date = race.startdate
    startdatetime = datetime.datetime.combine(start_date,start_time)
    startdatetime = pytz.timezone(race.timezone).localize(
        startdatetime
        )

    if timezone.now() > startdatetime:
        messages.error(request,"You cannot edit a race after the start of the race window")
        url = reverse(virtualevent_view,
                      kwargs={
                          'id':race.id,
                          })

    if request.method == 'POST':
        racecreateform = VirtualRaceForm(request.POST,instance=race)
        if racecreateform.is_valid():
            cd = racecreateform.cleaned_data
            
            res, message = update_virtualrace(race,cd)

            if res:
                messages.info(request,message)
            else:
                messages.error(request,message)

            url = reverse(virtualevent_view,
                          kwargs = {
                              'id':race.id
                              })
            
            return HttpResponseRedirect(url)

    else:

        racecreateform = VirtualRaceForm(instance=race)

        
    return render(request,'virtualeventedit.html',
                  {
                      'form':racecreateform,
                      'rower':r,
                      'race':race,

                  })

@login_required()
def virtualevent_submit_result_view(request,id=0):

    r = getrower(request.user)

    try:
        race = VirtualRace.objects.get(id=id)
    except VirtualRace.DoesNotExist:
        raise Http404("Virtual Race does not exist")

    start_time = race.start_time
    start_date = race.startdate
    startdatetime = datetime.datetime.combine(start_date, start_time)
    startdatetime = pytz.timezone(race.timezone).localize(startdatetime)
    
    end_time = race.end_time
    end_date = race.enddate
    enddatetime = datetime.datetime.combine(end_date, end_time)
    enddatetime = pytz.timezone(race.timezone).localize(enddatetime)

    can_submit = race_can_submit(r,race) or race_can_resubmit(r,race)

    records = VirtualRaceResult.objects.filter(
        userid = r.id,
        race=race
        )

    entrychoices = []
    
    for record in records:
        rtpl = (record.id, record.__unicode__())
        entrychoices.append(rtpl)

    entries = {}
    entries['choices'] = entrychoices
    entries['initial'] = [records[0].id]

    if not can_submit:
        messages.error(request,'You cannot submit a result to this race')
        url = reverse(virtualevent_view,
                      kwargs = {
                          'id':id
                          }
                      )
        return HttpResponseRedirect(url)
    
    ws = Workout.objects.filter(
        user=r,
        startdatetime__gte=startdatetime,
        startdatetime__lte=enddatetime,
        ).order_by("date","startdatetime","id")

    initialworkouts = [w.id for w in Workout.objects.filter(
        user=r,plannedsession=race
    )]

    workoutdata = {}
    workoutdata['initial'] = []

    choices = []
    
    for w in ws:
        wtpl = (w.id, w.__unicode__())
        choices.append(wtpl)
        if w.id in initialworkouts:
            workoutdata['initial'].append(w.id)

    workoutdata['choices'] = tuple(choices)

    if request.method == 'POST':
        w_form = WorkoutRaceSelectForm(workoutdata,entries,request.POST)

        if w_form.is_valid():
            selectedworkout = w_form.cleaned_data['workouts']
            splitsecond = 0
            recordid = w_form.cleaned_data['record']
#            splittime = w_form.cleaned_data['evaluate_after']
#            if splittime is not None:
#                splitsecond = splittime.hour*3600
#                splitsecond += splittime.minute*60
#                splitsecond += splittime.second
#                splitsecond += splittime.microsecond/1.e6
#            else:
#                splitsecond = 0
        else:
            selectedworkout = None


        if selectedworkout is not None:


            workouts = Workout.objects.filter(id=selectedworkout)

            result,comments,errors,jobid = add_workout_race(
                workouts,race,r,
                splitsecond=splitsecond,recordid=recordid)
#            if result:
#                for w in ws:
#                    remove_workout_plannedsession(w,race)
#                    delete_race_result(w,race)

            for c in comments:
                messages.info(request,c)
            for er in errors:
                messages.error(request,er)

            if jobid:
                try:
                    request.session['async_tasks'] += [(jobid,'submit_race')]
                except KeyError:
                    request.session['async_tasks'] = [(jobid,'submit_race')]

                messages.info(request,"We are evaluating your result. The page will reload when we're done. Your result will show up if you adhered to the course")
                
            # redirect to race page
            url = reverse(virtualevent_view,
                          kwargs = {
                              'id':race.id
                          })
            
            return HttpResponseRedirect(url)

    else:
        w_form = WorkoutRaceSelectForm(workoutdata,entries)

    return render(request,'race_submit.html',
                  {
                      'race':race,
                      'workouts':ws,
                      'rower':r,
                      'w_form':w_form,
                      })

                    
        
