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

import hashlib
from shutil import copyfile
from six import iterlists
from rowers.views.statements import *
import rowers.teams as teams
import rowers.mytypes as mytypes
import numpy
from rowers.mailprocessing import send_confirm
import rowers.uploads as uploads

from urllib.parse import urlparse, parse_qs
from json.decoder import JSONDecodeError

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

def get_video_id(url):
    """Returns Video_ID extracting from the given url of Youtube

    Examples of URLs:
      Valid:
        'http://youtu.be/_lOT2p_FCvA',
        'www.youtube.com/watch?v=_lOT2p_FCvA&feature=feedu',
        'http://www.youtube.com/embed/_lOT2p_FCvA',
        'http://www.youtube.com/v/_lOT2p_FCvA?version=3&amp;hl=en_US',
        'https://www.youtube.com/watch?v=rTHlyTphWP0&index=6&list=PLjeDyYvG6-40qawYNR4juzvSOg-ezZ2a6',
        'youtube.com/watch?v=_lOT2p_FCvA',

      Invalid:
        'youtu.be/watch?v=_lOT2p_FCvA',
    """

    if url.startswith(('youtu', 'www')):
        url = 'http://' + url
    elif 'http' not in url:
        return url

    query = urlparse(url)

    if 'youtube' in query.hostname:
        if query.path == '/watch':
            return parse_qs(query.query)['v'][0]
        elif query.path.startswith(('/embed/', '/v/')):
            return query.path.split('/')[2]
    elif 'youtu.be' in query.hostname:
        return query.path[1:]
    else:
        raise ValueError

# Show a video compared with data
def workout_video_view_mini(request,id=''):
    try:
        id = encoder.decode_hex(id)
        analysis = VideoAnalysis.objects.get(id=id)
    except VideoAnalysis.DoesNotExist:
        raise Http404("Video Analysis does not exist")

    w = analysis.workout
    delay = analysis.delay

    if w.workouttype in mytypes.otwtypes:
        mode = 'water'
    else:
        mode = 'erg'



    if request.user.is_authenticated:
        mayedit = is_workout_user(request.user,w) and is_promember(request.user)
        rower = request.user.rower
    else:
        mayedit = False
        rower = None

    # get video ID and offset
    if mayedit and request.method == 'POST':
        form = VideoAnalysisCreateForm(request.POST)
        metricsform = VideoAnalysisMetricsForm(request.POST,mode=mode)
        if form.is_valid() and metricsform.is_valid():
            video_id = form.cleaned_data['url']
            try:
                video_id = get_video_id(form.cleaned_data['url'])
            except (TypeError,ValueError):
                pass
            delay = form.cleaned_data['delay']
            metricsgroups = metricsform.cleaned_data['groups']
            if 'save_button' in request.POST:
                analysis.name = form.cleaned_data['name']
                analysis.video_id = video_id
                analysis.delay = delay
                analysis.metricsgroups = metricsgroups
                analysis.save()
        else:
            video_id = id
            delay = 0
    elif mayedit:
        form = VideoAnalysisCreateForm(
            initial = {
                'name':analysis.name,
                'delay': analysis.delay,
                'url': analysis.video_id,
            }
        )
        metricsform = VideoAnalysisMetricsForm(initial={'groups':analysis.metricsgroups},
                                               mode=mode)
        metricsgroups = analysis.metricsgroups
        video_id = analysis.video_id
    else:
        form = None
        metricsform = None
        metricsgroups = analysis.metricsgroups

    data, metrics, maxtime = dataprep.get_video_data(w,groups=metricsgroups,mode=mode)
    hascoordinates = pd.Series(data['latitude']).std() > 0
    # create map
    if hascoordinates:
        mapscript, mapdiv = leaflet_chart_video(data['latitude'],data['longitude'],
                                                w.name)
    else:
        mapscript, mapdiv = interactive_chart_video(data)
        data['longitude'] = data['spm']
        data['latitude'] = list(range(len(data['spm'])))


    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,encoder.encode_hex(w.id)),
                'name': w.name
                },
            {
                'url':reverse('workout_video_view_mini',kwargs={'id':encoder.encode_hex(analysis.id)}),
                'name': 'Video Analysis'
                }

            ]


    return render(request,
                  'embedded_video_mini.html',
                  {
                      'workout':w,
                      'rower':rower,
                      'data': json.dumps(data,default=default),
                      'mapscript': mapscript,
                      'mapdiv': mapdiv,
                      'video_id': analysis.video_id,
                      'form':form,
                      'breadcrumbs':breadcrumbs,
                      'analysis':analysis,
                      'maxtime':maxtime,
                      'metrics':metrics,
                      'locked': True,
                      'metricsform':metricsform,
                      'metricsgroups': metricsgroups,
                      'siteurl': settings.SITE_URL,
                      })


# Show a video compared with data
def workout_video_view(request,id=''):
    try:
        id = encoder.decode_hex(id)
        analysis = VideoAnalysis.objects.get(id=id)
    except VideoAnalysis.DoesNotExist:
        raise Http404("Video Analysis does not exist")

    w = analysis.workout
    delay = analysis.delay

    if w.workouttype in mytypes.otwtypes:
        mode = 'water'
    else:
        mode = 'erg'

    if request.user.is_authenticated:
        mayedit = is_promember(request.user) and is_workout_user(request.user,w)
        rower = request.user.rower
    else:
        mayedit = False
        rower = None

    # get video ID and offset
    if mayedit and request.method == 'POST':
        form = VideoAnalysisCreateForm(request.POST)
        metricsform = VideoAnalysisMetricsForm(request.POST,mode=mode)
        if form.is_valid() and metricsform.is_valid():
            video_id = form.cleaned_data['url']
            try:
                video_id = get_video_id(form.cleaned_data['url'])
            except (TypeError,ValueError):
                pass
            delay = form.cleaned_data['delay']
            metricsgroups = metricsform.cleaned_data['groups']
            if 'save_button' in request.POST:
                analysis.name = form.cleaned_data['name']
                analysis.video_id = video_id
                analysis.delay = delay
                analysis.metricsgroups = metricsgroups
                analysis.save()
        else:
            video_id = id
            delay = 0
    elif mayedit:
        form = VideoAnalysisCreateForm(
            initial = {
                'name':analysis.name,
                'delay': analysis.delay,
                'url': analysis.video_id,
            }
        )
        metricsform = VideoAnalysisMetricsForm(initial={'groups':analysis.metricsgroups},
                                               mode=mode)
        metricsgroups = analysis.metricsgroups
        video_id = analysis.video_id
    else:
        form = None
        metricsform = None
        metricsgroups = analysis.metricsgroups

    data, metrics, maxtime = dataprep.get_video_data(w,groups=metricsgroups,mode=mode)
    hascoordinates = pd.Series(data['latitude']).std() > 0
    # create map
    if hascoordinates:
        mapscript, mapdiv = leaflet_chart_video(data['latitude'],data['longitude'],
                                                w.name)
    else:
        mapscript, mapdiv = interactive_chart_video(data)
        data['longitude'] = data['spm']
        data['latitude'] = list(range(len(data['spm'])))


    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,encoder.encode_hex(w.id)),
                'name': w.name
                },
            {
                'url':reverse('workout_video_view',kwargs={'id':encoder.encode_hex(analysis.id)}),
                'name': 'Video Analysis'
                }

            ]


    return render(request,
                  'embedded_video.html',
                  {
                      'workout':w,
                      'rower':rower,
                      'data': json.dumps(data,default=default),
                      'mapscript': mapscript,
                      'mapdiv': mapdiv,
                      'video_id': analysis.video_id,
                      'form':form,
                      'breadcrumbs':breadcrumbs,
                      'analysis':analysis,
                      'maxtime':maxtime,
                      'metrics':metrics,
                      'locked': True,
                      'metricsform':metricsform,
                      'metricsgroups': metricsgroups,
                      'siteurl': settings.SITE_URL,
                      })


# Create a video compared with data
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans/",
                  message="This functionality requires a Pro plan or higher",
                  redirect_field_name=None)
def workout_video_create_view(request,id=0):
    # get workout
    w = get_workout_by_opaqueid(request,id)
    if w.workouttype in mytypes.otwtypes:
        mode = 'water'
    else:
        mode = 'erg'

    # get video ID and offset
    if request.method == 'POST':
        form = VideoAnalysisCreateForm(request.POST)
        metricsform = VideoAnalysisMetricsForm(request.POST,mode=mode)
        if form.is_valid() and metricsform.is_valid():
            url = form.cleaned_data['url']
            delay = form.cleaned_data['delay']
            metricsgroups = metricsform.cleaned_data['groups']
            video_id = get_video_id(url)
            if 'save_button' in request.POST:
                analysis = VideoAnalysis(
                    workout=w,
                    name=form.cleaned_data['name'],
                    video_id = video_id,
                    delay=delay,
                    metricsgroups=metricsgroups
                )
                try:
                    analysis.save()
                    url = reverse('workout_video_view',
                                  kwargs={'id':encoder.encode_hex(analysis.id)})
                    return HttpResponseRedirect(url)
                except IntegrityError:
                    messages.error(request,'You cannot save two video analysis with the same YouTube video and Workout. Redirecting to your existing analysis')
                    analysis = VideoAnalysis.objects.filter(workout=w,video_id=video_id)
                    if analysis:
                        url = reverse('workout_video_view',
                                      kwargs={'id':encoder.encode_hex(analysis[0].id)})
                    else:
                        url = reverse('workout_video_create_view',
                                      kwargs={'id':encoder.encode_hex(w.id)})
                    return HttpResponseRedirect(url)
        else:
            video_id = None
            delay = 0
            metricsgroups = ['basic']
    else:
        form = VideoAnalysisCreateForm()
        metricsform = VideoAnalysisMetricsForm(initial={'groups':['basic']},mode=mode)
        video_id = None
        delay = 0
        metricsgroups = ['basic']

    # get data
    data, metrics, maxtime = dataprep.get_video_data(w,groups=metricsgroups,mode=mode)
    hascoordinates = pd.Series(data['latitude']).std() > 0

    # create map
    if hascoordinates:
        mapscript, mapdiv = leaflet_chart_video(data['latitude'],data['longitude'],
                                                w.name)
    else:
        mapscript, mapdiv = interactive_chart_video(data)
        data['longitude'] = data['spm']
        data['latitude'] = list(range(len(data['spm'])))

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,encoder.encode_hex(w.id)),
                'name': w.name
                },
            {
                'url':reverse('workout_video_create_view',kwargs={'id':encoder.encode_hex(w.id)}),
                'name': 'Video Analysis'
                }

            ]

    analysis = {'delay':delay}

    template = 'embedded_video.html'


    return render(request,
                  template,
                  {
                      'workout':w,
                      'rower':request.user.rower,
                      'data': json.dumps(data,default=default),
                      'mapscript': mapscript,
                      'mapdiv': mapdiv,
                      'video_id': video_id,
                      'form':form,
                      'metricsform':metricsform,
                      'analysis':analysis,
                      'breadcrumbs':breadcrumbs,
                      'maxtime':maxtime,
                      'metrics':metrics,
                      'metricsgroups': metricsgroups,
                      'locked': False,
                      'siteurl': settings.SITE_URL,
                      })

# Show the EMpower Oarlock generated Stroke Profile
@user_passes_test(ispromember,login_url="/rowers/paidplans/",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_forcecurve_view(request,id=0,workstrokesonly=False):
    row = get_workoutuser(id, request)

    promember=0
    mayedit=0

    r = getrequestrower(request)
    promember = 1

    if r == row.user:
        mayedit = 1

    if request.method == 'POST':
        form = ForceCurveOptionsForm(request.POST)
        if form.is_valid():
            includereststrokes = form.cleaned_data['includereststrokes']
            plottype = form.cleaned_data['plottype']
            workstrokesonly = not includereststrokes
        else:
            workstrokesonly = True
            plottype = 'line'
    else:
        form = ForceCurveOptionsForm()
        plottype = 'line'

    script,div,js_resources,css_resources = interactive_forcecurve(
        [row],
        workstrokesonly=workstrokesonly,
        plottype=plottype,
    )

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': row.name
                },
            {
                'url':reverse('workout_forcecurve_view',kwargs={'id':id}),
                'name': 'Empower Force Curve'
                }

            ]

    r = getrower(request.user)

    return render(request,
                  'forcecurve_single.html',
                  {
                      'the_script':script,
                      'rower':r,
                      'form':form,
                      'workout':row,
                      'breadcrumbs':breadcrumbs,
                      'active':'nav-workouts',
                      'the_div':div,
                      'js_res': js_resources,
                      'css_res':css_resources,
                      'id':id,
                      'mayedit':mayedit,
                      'teams':get_my_teams(request.user),
                  })

# Switch from GPS to Impeller (only for SpeedCoach 2, if impeller data)
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def otw_use_impeller(request,id=0):
    w = get_workoutuser(id, request)


    row = rdata(w.csvfilename)
    success = row.use_impellerdata()
    if success:
        row.write_csv(w.csvfilename)
        dataprep.update_strokedata(w.id,row.df)
        w.impeller = True
        w.save()
        messages.info(request,'The distance and speed data are now based on Impeller data')
    else:
        messages.error(request,'No impeller data found')

    url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)})

    return HttpResponseRedirect(url)


# Switch from Impeller to GPS (only for SpeedCoach 2, if impeller data)
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def otw_use_gps(request,id=0):
    w = get_workoutuser(id, request)


    row = rdata(w.csvfilename)
    success = row.use_gpsdata()
    if success:
        row.write_csv(w.csvfilename)
        dataprep.update_strokedata(w.id,row.df)
        w.impeller = False
        w.save()
        messages.info(request,'The distance and speed data are now based on GPS data')
    else:
        messages.error(request,'No GPS data found')

    url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)})

    return HttpResponseRedirect(url)



# Show Stroke power histogram for a workout
@login_required()
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_histo_view(request,id=0):
    w = get_workoutuser(id, request)
    r = getrequestrower(request)
    promember = 1

    mayedit=0
    if w.user == r:
        mayedit = 1

    res = interactive_histoall([w],'power',False)
    script = res[0]
    div = res[1]

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': w.name
                },
            {
                'url':reverse('workout_histo_view',kwargs={'id':id}),
                'name': 'Histogram'
                }

            ]


    return render(request,
                  'histo_single.html',
                  {'interactiveplot':script,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   'workout':w,
                   'rower':r,
                   'the_div':div,
                   'id':id,
                   'mayedit':mayedit,
                   'teams':get_my_teams(request.user),
                   })




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

    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
        'url':reverse('addmanual_view'),
            'name': 'Add Manual Entry'
                },
    ]

    if request.method == 'POST':
        # Form was submitted
        form = WorkoutForm(request.POST)
        metricsform = MetricsForm(request.POST)
        if form.is_valid() and metricsform.is_valid():
            # Get values from form
            name = form.cleaned_data['name']
            if name == '':
                name = 'Manual Entry'
            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']
            adaptiveclass = form.cleaned_data['adaptiveclass']
            distance = form.cleaned_data['distance']
            notes = form.cleaned_data['notes']
            thetimezone = form.cleaned_data['timezone']
            private = form.cleaned_data['private']
            avghr = metricsform.cleaned_data['avghr']
            avgpwr = metricsform.cleaned_data['avgpwr']
            avgspm = metricsform.cleaned_data['avgspm']
            try:
                ps = form.cleaned_data['plannedsession']
            except KeyError:
                ps = None

            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

            try:
                duplicate = form.cleaned_data['duplicate']
            except KeyError:
                duplicate = 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,
                                                duration,startdatetime,
                                                weightcategory=weightcategory,
                                                adaptiveclass=adaptiveclass,
                                                avghr=avghr,
                                                rankingpiece=rankingpiece,
                                                avgpwr=avgpwr,
                                                duplicate=duplicate,
                                                avgspm=avgspm,
                                                title = name,
                                                notes=notes,
                                                workouttype=workouttype)



            if message:
                messages.error(request,message)

            if id:
                w = Workout.objects.get(id=id)
                w.rankingpiece = rankingpiece
                w.privacy = privacy
                w.weightcategory = weightcategory
                w.adaptiveclass = adaptiveclass
                w.notes = notes
                w.plannedsession = ps
                w.name = name
                w.workouttype = workouttype
                w.boattype = boattype
                w.save()
                if ps:
                    add_workouts_plannedsession([w],ps,w.user)

                messages.info(request,'New workout created')

                iform = ImageForm(request.POST,request.FILES)
                if iform.is_valid():
                    f = iform.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)

                        i = GraphImage(workout=w,
                                       creationdatetime=timezone.now(),
                                       filename = path_and_filename,
                                       width=width,height=height)
                        i.save()

                if raceid != 0:
                    try:
                        race = VirtualRace.objects.get(id=raceid)
                    except VirtualRace.DoesNotExist:
                        messages.error(request,"Race does not exist")
                        url = reverse('workout_edit_view',
                                      kwargs = {'id':encoder.encode_hex(id)})
                        return HttpResponseRedirect(url)

                    can_submit = race_can_submit(r,race) or race_can_resubmit(r,race)
                    can_submit = can_submit and race.sessiontype == 'indoorrace'
                    if not can_submit:
                        messages.error(request,'You cannot submit a result for this race')
                    if can_submit:
                        records = IndoorVirtualRaceResult.objects.filter(race=race,userid=r.id)
                        if not records:
                            messages.error(request,'You have to register for the race first')
                            url = reverse('virtualevent_view',kwargs = {'id':race.id})
                            return HttpResponseRedirect(url)

                        recordid = records[0].id

                        result, comments, errors, jobid = add_workout_indoorrace(
                            [w],race,r,recordid=recordid
                        )
                        for c in comments:
                            messages.info(request,c)
                        for er in errors:
                            messages.error(request,er)

                        if result:
                            otherrecords = IndoorVirtualRaceResult.objects.filter(
                                race = race
                            ).exclude(userid=r.id)
                            for otherrecord in otherrecords:
                                try:
                                    otheruser = Rower.objects.get(id=otherrecord.userid)
                                    othername = otheruser.user.first_name+' '+otheruser.user.last_name
                                    registeredname = r.user.first_name+' '+r.user.last_name
                                    if otherrecord.emailnotifications:
                                        job = myqueue(
                                        queue,
                                        handle_sendemail_racesubmission,
                                        otheruser.user.email, othername,
                                        registeredname,
                                        race.name,
                                        race.id
                                        )
                                except Rower.DoesNotExist:
                                    pass

                    url = reverse('virtualevent_view',kwargs = {'id':race.id})
                    return HttpResponseRedirect(url)

                url = reverse(
                    'workout_edit_view',
                    kwargs={'id':encoder.encode_hex(id)}
                              )
                return HttpResponseRedirect(url)
        else:
            iform = ImageForm()
            return render(request,'manualadd.html',
                          {'form':form,
                           'iform':iform,
                           'metricsform':metricsform,
                           'breadcrumbs':breadcrumbs,
                           'active':'nav-workouts',
                           })

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

    }
    form = WorkoutForm(initial=initial)
    iform = ImageForm()
    metricsform = MetricsForm()

    return render(request,'manualadd.html',
                  {'form':form,
                   'iform':iform,
                   'metricsform':metricsform,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   })

@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)
    if not ms:
        url = reverse('workouts_view')
        return HttpResponseRedirect(url)

    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")


@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
def workout_update_cp_view(request,id=0):
    row = get_workoutuser(id, request)

    row.rankingpiece = True
    row.save()

    r = getrower(request.user)

    dataprep.runcpupdate(r)

    if row.workouttype in mytypes.otwtypes:
        url = reverse('otwrankings_view')
    else:
        url = reverse('oterankings_view')

    return HttpResponseRedirect(url)


# Reload the workout and calculate the summary from the stroke data (lapIDx)
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_recalcsummary_view(request,id=0):
    row = get_workoutuser(id, request)

    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':id,
                  })
    else:
        message = "Something went wrong. Could not update summary"
        messages.error(request,message)
        url = reverse('workout_edit_view',
                      kwargs = {
                          'id':id,
                          })

    return HttpResponseRedirect(url)


# Joining workout
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
def workouts_join_view(request,userid=0):
    promember=0

    r = getrequestrower(request,userid=userid)
    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']
            killparents = paramform.cleaned_data['killparents']

            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,
                                                killparents=killparents)

            if message:
                messages.error(request,message)

            url = reverse(r.defaultlandingpage,
                          kwargs = {
                            'id':encoder.encode_hex(id),
                          })

            return HttpResponseRedirect(url)

        else:
            return HttpResponse("form is not valid")

    else:
        url = reverse('workouts_join_select')
        return HttpResponseRedirect(url)

defaultoptions = {
    'includereststrokes': False,
    'workouttypes':['rower','dynamic','slides'],
    'waterboattype': mytypes.waterboattype,
    'rankingonly': False,
    'function':'boxplot'
}

@user_passes_test(ispromember, login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher",
                  redirect_field_name=None)
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
def video_selectworkout(request,userid=0,teamid=0):
    r = getrequestrower(request, userid=userid)
    user = r.user
    userid = user.id
    workouts = Workout.objects.filter(user=r).order_by('-date')

    try:
        theteam = Team.objects.get(id=teamid)
    except Team.DoesNotExist:
        theteam = None


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

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

    try:
        modalities = options['modalities']
        modality = modalities[0]
    except KeyError:
        modalities = [m[0] for m in mytypes.workouttypes_ordered.items()]
        modality = 'all'



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

    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))
            )
        searchform = SearchForm(initial={'q':query})
    else:
        searchform = SearchForm()


    if 'startdate' in request.session:
        startdate = iso8601.parse_date(request.session['startdate'])
    else:
        startdate=timezone.now()-datetime.timedelta(days=42)

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


    workouts = workouts.filter(date__gte=startdate,date__lte=enddate)

    waterboattype = mytypes.waterboattype

    if request.method == 'POST':
        thediv = get_call()
        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

        form = WorkoutSingleSelectForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            selectedworkout = cd['workout']
            url = reverse('workout_video_create_view',
                          kwargs={'id':encoder.encode_hex(selectedworkout.id)})
            return HttpResponseRedirect(url)
        else:
            id = 0
    else:
        form = WorkoutSingleSelectForm(workouts=workouts)
        thediv = ''
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })



    negtypes = []
    for b in mytypes.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))

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

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



    if theteam is not None and (theteam.viewing == 'allmembers' or theteam.manager == request.user):
        workouts = Workout.objects.filter(team=theteam,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities,
        )
    elif theteam is not None and theteam.viewing == 'coachonly':
        workouts = Workout.objects.filter(team=theteam,user=r,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities,
        )
    else:
        workouts = Workout.objects.filter(user=r,
                                          startdatetime__gte=startdate,
                                          startdatetime__lte=enddate,
                                          workouttype__in=modalities,
        )

    workouts = workouts.order_by(
            "-date", "-starttime"
        ).exclude(boattype__in=negtypes)


    if rankingonly:
        workouts = workouts.exclude(rankingpiece=False)




    optionsform = AnalysisOptionsForm(initial={
        'modality':modality,
        'waterboattype':waterboattype,
        'rankingonly':rankingonly,
        })



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


    breadcrumbs = [
        {
            'url':'/rowers/analysis',
            'name':'Analysis'
        },
        {
            'url':reverse('analysis_new',kwargs={'userid':userid}),
            'name': 'Analysis Select'
        },
    ]
    return render(request, 'video_selectworkout.html',
                  {'workouts': workouts,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'rower':r,
                   'breadcrumbs':breadcrumbs,
                   'theuser':user,
                   'the_div':thediv,
                   'form':form,
                   'active':'nav-analysis',
                   'searchform':searchform,
                   'teams':get_my_teams(request.user),
                   })


@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
def workouts_join_select(request,
                         startdatestring="",
                         enddatestring="",
                         message='',
                         successmessage='',
                         userid=0,
                         startdate=timezone.now()-datetime.timedelta(days=30),
                         enddate=timezone.now()+datetime.timedelta(days=1),
                         teamid=0):



    r = getrequestrower(request,userid=userid)

    if 'waterboattype' in request.session:
        waterboattype = request.session['waterboattype']
    else:
        waterboattype = mytypes.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 mytypes.workouttypes]
        modality = 'all'

    if request.method == 'POST':
        dateform = DateRangeForm(request.POST)
        modalityform = TrendFlexModalForm(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
        if modalityform.is_valid():
            modality = modalityform.cleaned_data['modality']
            waterboattype = modalityform.cleaned_data['waterboattype']
            if modality == 'all':
                modalities = [m[0] for m in mytypes.workouttypes]
            else:
                modalities = [modality]

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


            request.session['modalities'] = modalities
            request.session['waterboattype'] = waterboattype
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })



    negtypes = []
    for b in mytypes.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 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))
            )
        searchform = SearchForm(initial={'q':query})
    else:
        searchform = SearchForm()

    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,
                   'searchform':searchform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'active':'nav-workouts',
                   'team':theteam,
                   'form':form,
                   'joinparamform':joinparamform,
                   'modalityform':modalityform,
                   'teams':get_my_teams(request.user),
                   })

# Team comparison
@user_passes_test(ispromember,login_url='/rowers/paidplans/',
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
def team_comparison_select(request,
                           startdatestring="",
                           enddatestring="",
                           message='',
                           successmessage='',
                           userid=0,
                           startdate=timezone.now()-datetime.timedelta(days=30),
                           enddate=timezone.now(),
                           id=0,
                           teamid=0):

    r = getrequestrower(request,userid=userid)
    requestrower = getrower(request.user)


    request.session.pop('ps',None)

    if 'waterboattype' in request.session:
        waterboattype = request.session['waterboattype']
    else:
        waterboattype = mytypes.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 mytypes.workouttypes]
        modality = 'all'

    if request.method == '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

        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 mytypes.workouttypes]
            else:
                modalities = [modality]

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


            if 'rankingonly' in modalityform.cleaned_data:
                rankingonly = modalityform.cleaned_data['rankingonly']
            else:
                rankingonly = False

            request.session['modalities'] = modalities
            request.session['waterboattype'] = waterboattype
    else:
        dateform = DateRangeForm(initial={
            'startdate':startdate,
            'enddate':enddate,
            })
        modalityform = TrendFlexModalForm(initial={
            'modality':modality,
            'waterboattype':waterboattype,
            'rankingonly':rankingonly,
        })




    negtypes = []
    for b in mytypes.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 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)

    if rankingonly:
        workouts = workouts.exclude(rankingpiece=False)

    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))
            )
        searchform = SearchForm(initial={'q':query})
    else:
        searchform = SearchForm()

    if id:
        firstworkout = get_workout(id)
        if not is_workout_team(request.user,firstworkout):

            raise PermissionDenied("You are not allowed to use this workout")

        firstworkoutquery = Workout.objects.filter(id=encoder.decode_hex(id))
        workouts = firstworkoutquery | workouts
    else:
        firstworkout = None

    form = WorkoutMultipleCompareForm()
    form.fields["workouts"].queryset = workouts
    if id:
        form.fields["workouts"].initial = [firstworkout]



    if theteam:
        theid = theteam.id
    else:
        theid = 0

    chartform = ChartParamChoiceForm(initial={'teamid':0})

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

    if id:
        breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
            },
            {
                'url':get_workout_default_page(request,id),
                'name': firstworkout.name
                },
            {
                'url':reverse('team_comparison_select',kwargs={'id':id,'teamid':teamid}),
                'name':'Compare Select'
                },
            ]
    else:
        breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
            },
            {
                'url':reverse('team_comparison_select',kwargs={'teamid':teamid}),
                'name': 'Compare Select'
            },

        ]

    return render(request, 'team_compare_select.html',
                  {'workouts': workouts,
                   'workout':firstworkout,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'team':theteam,
                   'searchform':searchform,
                   'form':form,
                   'rower':r,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   'chartform':chartform,
                   'modalityform':modalityform,
                   'teams':get_my_teams(request.user),
                   })

def virtualevent_mapcompare_view(request,id=0):
    results = []

    r = None
    if not request.user.is_anonymous:
        r = getrower(request.user)

    try:
        race = VirtualRace.objects.get(id=id)
    except VirtualRace.DoesNotExist:
        raise Http404("Virtual Challenge does not exist")

    if race.sessiontype != 'race':
        url = reverse(virtualevent_view,kwargs={'id':id})
        messages.error(request,"This challenge doesn't have map data")
        return HttpResponseRedirect(request)

    results = VirtualRaceResult.objects.filter(
        race=race,
        workoutid__isnull=False,
        coursecompleted=True,
    ).order_by("distance","duration")

    workoutids = [result.workoutid for result in results]

    startenddict = {}
    if race.sessiontype == 'race':
        for result in results:
            startenddict[result.workoutid] = (result.startsecond,result.endsecond)

    if len(workoutids) == 0:
        url = reverse('virtualevent_view',
                      kwargs={
                          'id':race.id,
                      })

        messages.info(request,'There are no results to display')

        return HttpResponseRedirect(url)

    workouts = []
    for id in workoutids:
        try:
            workouts.append(Workout.objects.get(id=id))
        except Workout.DoesNotExist:
            pass

    labeldict = {
        int(w.id): w.__str__() for w in workouts
        }

    script,div =  leaflet_chart_compare(race.course,workoutids,
                                        labeldict=labeldict,
                                        startenddict=startenddict)

    breadcrumbs = [
        {
            'url': reverse('virtualevents_view'),
            'name': 'Racing'
        },
        {
            'url':reverse('virtualevent_view',
                          kwargs={
                              'id':race.id,
                          }
            ),
            'name': race.name
        },
        {
            'url':reverse('virtualevent_mapcompare_view',
                          kwargs={
                              'id':race.id,
                          }
            ),
            'name': 'Compare'
        }
    ]


    return render(request,'mapcompare.html',
                  {'mapscript':script,
                   'mapdiv':div,
                   'breadcrumbs':breadcrumbs,
                   'rower':r,
                   'race':race,
                   'results':results,
                   'active':'nav-racing',
                   'teamid':0,
                   'teams':[]
                   })

def virtualevent_compare_view(request,id=0):
    results = []

    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
    else:
        r = None

    try:
        race = VirtualRace.objects.get(id=id)
    except VirtualRace.DoesNotExist:
        raise Http404("Virtual Challenge does not exist")

    if race.sessiontype == 'race':
        script,div = course_map(race.course)
        resultobj = VirtualRaceResult
    else:
        script = ''
        div = ''
        resultobj = IndoorVirtualRaceResult

    results = resultobj.objects.filter(
        race=race,
        workoutid__isnull=False,
        coursecompleted=True,
    ).order_by("duration","-distance")

    workoutids = [result.workoutid for result in results]

    startenddict = {}
    if race.sessiontype == 'race':
        for result in results:
            startenddict[result.workoutid] = (result.startsecond,result.endsecond)





    if len(workoutids) == 0:
        url = reverse('virtualevent_view',
                      kwargs={
                          'id':race.id,
                      })

        messages.info(request,'There are no results to display')

        return HttpResponseRedirect(url)


    if request.method == 'GET':
        xparam = 'time'
        if race.sessionmode == 'distance':
            xparam = 'cumdist'


        yparam = 'pace'
        plottype = 'line'



        request.session['ids'] = workoutids
        request.session['plottype'] = plottype
        request.session['xparam'] = xparam
        request.session['yparam'] = yparam


        workouts = []
        for id in workoutids:
            try:
                workouts.append(Workout.objects.get(id=id))
            except Workout.DoesNotExist:
                pass


        labeldict = {
            int(w.id): w.__str__() for w in workouts
            }



        chartform = ChartParamChoiceForm(
            initial = {
                'xparam':xparam,
                'yparam':yparam,
                'plottype':plottype,
                'teamid':0
                }
            )
    elif request.method == 'POST':
        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']
            try:
                workoutids = request.session['ids']
            except KeyError:
                pass

            request.session['ids'] = workoutids
            workouts = []
            for id in workoutids:
                try:
                    workouts.append(Workout.objects.get(
                        id=id))
                except Workout.DoesNotExist:
                    pass

            labeldict = {
                int(w.id): w.__str__() for w in workouts
                }
    else:
        raise HttpResponse('Only GET and POST allowed',status=405)


    res = interactive_multiple_compare_chart(workoutids,xparam,yparam,
                                             promember=promember,
                                             plottype=plottype,
                                             labeldict=labeldict,startenddict=startenddict)
    script = res[0]
    div = res[1]
    errormessage = res[3]
    if errormessage != '':
        messages.error(request,errormessage)

    breadcrumbs = [
        {
            'url': reverse('virtualevents_view'),
            'name': 'Racing'
        },
        {
            'url':reverse('virtualevent_view',
                          kwargs={
                              'id':race.id,
                          }
            ),
            'name': race.name
        },
        {
            'url':reverse('virtualevent_compare_view',
                          kwargs={
                              'id':race.id,
                          }
            ),
            'name': 'Compare'
        }
    ]


    return render(request,'multicompare.html',
                  {'interactiveplot':script,
                   'the_div':div,
                   'breadcrumbs':breadcrumbs,
                   'rower':r,
                   'race':race,
                   'results':results,
                   'active':'nav-racing',
                   'promember':promember,
                   'teamid':0,
                   'chartform':chartform,
                   'teams':[]
                   })


@permission_required('plannedsession.view_session',
                     fn=get_session_by_pk,raise_exception=True)
def plannedsession_compare_view(request,id=0,userid=0):
    r = getrequestrower(request,userid=userid)

    try:
        ps = PlannedSession.objects.get(id=id)
    except PlannedSession.DoesNotExist:
        raise Http404("Planned session does not exist")


    workouts = Workout.objects.filter(plannedsession=ps)

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

    labeldict = {
        int(w.id): w.__str__() for w in workouts
        }

    xparam = 'time'
    yparam = 'hr'
    plottype = 'line'

    request.session['ids'] = ids
    request.session['xparam'] = xparam
    request.session['yparam'] = yparam
    request.session['plottype'] = plottype
    request.session['ps'] = ps.id

    if ids:
        url = reverse('multi_compare_view',
                      kwargs={'userid':userid,'id':encoder.encode_hex(ids[0])})
    else:
        url = reverse('plannedsession_view',kwargs={'id':ps.id})

    return HttpResponseRedirect(url)

# Team comparison
@login_required()
def multi_compare_view(request,id=0,userid=0):
    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.__str__() for w in workouts
                }

        else:
            return HttpResponse("Form is not valid")
    elif 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 = []
            for id in ids:
                try:
                    workouts.append(Workout.objects.get(id=id))
                except Workout.DoesNotExist:
                    pass

            labeldict = {
                int(w.id): w.__str__() for w in workouts
                }
    elif 'ids' in request.session and 'plottype' in request.session:
        xparam = request.session['xparam']
        yparam = request.session['yparam']
        plottype = request.session['plottype']
        teamid = 0
        ids = request.session['ids']
        workouts = []
        for id in ids:
            try:
                workouts.append(Workout.objects.get(id=id))
            except Workout.DoesNotExist:
                pass

        labeldict = {
            int(w.id): w.__str__() for w in workouts
            }
        chartform = ChartParamChoiceForm(
            initial = {
                'xparam':xparam,
                'yparam':yparam,
                'plottype':plottype,
                'teamid':teamid
                }
            )

    else:
        url = reverse('team_comparison_select',
                      kwargs={
                          'id':id,
                          'teamid':0})
        return HttpResponseRedirect(url)


    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)

    r = getrower(request.user)

    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url':reverse('team_comparison_select',kwargs={'teamid':teamid}),
            'name': 'Compare Select'
        },
        {
            'url':reverse('multi_compare_view'),
            'name': 'Comparison Chart'
        }
    ]

    if 'ps' in request.session:
        ps = PlannedSession.objects.get(id=int(request.session['ps']))
        breadcrumbs = [
            {
                'url': reverse('plannedsessions_view',
                               kwargs={'userid':userid}),
                'name': 'Sessions'
            },
            {
            'url':reverse('plannedsession_view',
                          kwargs={
                              'userid':userid,
                              'id':ps.id,
                          }
            ),
            'name': ps.id
            },
            {
            'url':reverse('plannedsession_compare_view',
                          kwargs={
                              'userid':userid,
                              'id':ps.id,
                          }
            ),
            'name': 'Compare'
            }
        ]


    return render(request,'multicompare.html',
                  {'interactiveplot':script,
                   'the_div':div,
                   'breadcrumbs':breadcrumbs,
                   'rower':r,
                   'active':'nav-workouts',
                   'promember':promember,
                   'teamid':teamid,
                   'chartform':chartform,
                   'teams':get_my_teams(request.user),
                  })


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

    startdate,enddate = get_dates_timeperiod(request,defaulttimeperiod='lastyear')
    request.session['referer'] = absolute(request)['PATH']
    r = getrequestrower(request,rowerid=rowerid,userid=userid)

    # check if access is allowed


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

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

    usertimezone = pytz.timezone(r.defaulttimezone)
    startdate = datetime.datetime.combine(startdate,datetime.time()).astimezone(usertimezone)
    enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)).astimezone(usertimezone)
    #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 enddate > timezone.now():
            activity_enddate = timezone.now()
            activity_enddate = activity_enddate.replace(hour=23,minute=59,second=59).astimezone(usertimezone)
            activity_startdate = activity_enddate-datetime.timedelta(days=15)
            activity_startdate = activity_startdate.replace(hour=0,minute=0,second=0)
        else:
            activity_enddate = enddate
    except ValueError:
        activity_enddate = enddate

    g_startdate = activity_startdate
    g_enddate = activity_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,
                privacy='visible').order_by("-date","-starttime")
            g_workouts = Workout.objects.filter(
                team=theteam,
                startdatetime__gte=activity_startdate,
                startdatetime__lte=activity_enddate,
                duplicate=False,
                privacy='visible').order_by("-date", "-starttime")
        elif theteam.viewing == 'coachonly':
            workouts = Workout.objects.filter(
                team=theteam,user=r,
                startdatetime__gte=startdate,
                startdatetime__lte=enddate,
                privacy='visible').order_by("-startdatetime")
            g_workouts = Workout.objects.filter(
                team=theteam,user=r,
                startdatetime__gte=activity_startdate,
                startdatetime__lte=activity_enddate,
                duplicate=False,
                privacy='visible').order_by("-startdatetime")


    elif request.user != r.user:
        theteam = None
        workouts = Workout.objects.filter(
            user=r,
            startdatetime__gte=startdate,
            startdatetime__lte=enddate,
            privacy='visible').order_by("-date", "-starttime")
        g_workouts = Workout.objects.filter(
            user=r,
            startdatetime__gte=activity_startdate,
            startdatetime__lte=activity_enddate,
            duplicate=False,
            privacy='visible').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,
            duplicate=False,
            startdatetime__gte=activity_startdate,
            startdatetime__lte=activity_enddate).order_by("-startdatetime")

    if g_workouts.count() == 0:
        g_workouts = Workout.objects.filter(
            user=r,
            startdatetime__gte=timezone.now()-timedelta(days=15)).order_by("-startdatetime")
        g_enddate = timezone.now()
        g_startdate = (timezone.now()-timedelta(days=15))


    if rankingonly:
        workouts = workouts.exclude(rankingpiece=False)

    workoutsnohr = workouts.exclude(averagehr__isnull=False)
    for w in workoutsnohr:
        res = dataprep.workout_trimp(w)

    # ids = [w.id for w in workouts]
    # df = dataprep.getsmallrowdata_db(['time','power'],ids=ids)
    # polarization = dataprep.polarization_index(df,r)


    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))
            )
        searchform = SearchForm(initial={'q':query})
    else:
        searchform = SearchForm()

    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,
                                           g_startdate,
                                           g_enddate,
                                           stack=stack)

    totalmeters,totalhours, totalminutes,total_seconds = get_totals(g_workouts)
    totalminutes = '{totalminutes:02d}'.format(totalminutes=totalminutes)


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

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
        ]
    timeperiod = startdate.strftime('%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
    return render(request, 'list_workouts.html',
                  {'workouts': workouts,
                   'active': 'nav-workouts',
                   'rower':r,
                   'searchform':searchform,
                   'breadcrumbs':breadcrumbs,
                   '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,
                   'timeperiod':timeperiod,
                   'totalmeters':totalmeters,
                   'totalminutes':totalminutes,
                   'totalhours':totalhours,
                   })




# List of workouts to compare a selected workout to
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_fusion_list(request,id=0,
                            startdatestring="",enddatestring="",
                            startdate=timezone.now()-datetime.timedelta(days=365),
                            enddate=timezone.now()):

    r = getrequestrower(request)

    u = r.user
    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

    if id:
        theid = encoder.decode_hex(id)
        w = get_workoutuser(id, request)
        r = w.user

    workouts = Workout.objects.filter(user=r,
                                      startdatetime__gte=startdate,
                                      startdatetime__lte=enddate).order_by("-date", "-starttime").exclude(id=theid)

    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))
            )
        searchform = SearchForm(initial={'q':query})
    else:
        searchform = SearchForm()

    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_workoutuser(id, request)


    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url':get_workout_default_page(request,encoder.encode_hex(row.id)),
            'name': row.name
        },
        {
            'url':reverse('workout_fusion_list',kwargs={'id':id}),
            'name': 'Sensor Fusion'
        }

    ]

    return render(request, 'fusion_list.html',
                  {'id':id,
                   'workout':row,
                   'rower':r,
                   'searchform':searchform,
                   'active':'nav-workouts',
                   'breadcrumbs':breadcrumbs,
                   'workouts': workouts,
                   'last_name':u.last_name,
                   'first_name':u.first_name,
                   'dateform':dateform,
                   'startdate':startdate,
                   'enddate':enddate,
                   'teams':get_my_teams(request.user),
                  })

# Basic view of workout
@permission_required('workout.view_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_view(request,id=0,raceresult=0):
    request.session['referer'] = absolute(request)['PATH']

    if not request.user.is_anonymous:
        rower = getrower(request.user)
    else:
        rower = None

    # get row
    row = get_workout_by_opaqueid(request,id)
    f1 = row.csvfilename
    rowdata = rdata(f1)
    summary = row.summary

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

    aantalcomments = len(comments)


    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

    # get raceresult
    intervaldata = {}
    if raceresult != 0:
        try:
            result = VirtualRaceResult.objects.get(id=raceresult)
            startsecond = result.startsecond
            endsecond = result.endsecond
            duration = row.duration
            durationsecs = duration.hour*3600+duration.minute*60+duration.second
            itime = [startsecond,endsecond-startsecond]
            itype = [3,4]
            intervaldata['itime'] = itime
            intervaldata['itype'] = itype

            rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',0.1,mode='larger',
                                          debug=False,smoothwindow=15.,
                                          activewindow = [startsecond,endsecond])
            summary = rowdata.allstats()
        except VirtualRaceResult.DoesNotExist:
            pass
    # create interactive plot
    res = interactive_chart(encoder.decode_hex(id),intervaldata=intervaldata)
    script = res[0]
    div = res[1]

    # create map
    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 = ""

    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url':reverse('workout_view',kwargs={'id':id}),
            'name': row.name,
        }

    ]

    u = row.user.user

    recordsindoor = IndoorVirtualRaceResult.objects.filter(workoutid= row.id)
    records = VirtualRaceResult.objects.filter(workoutid= row.id)

    return render(request, 'workout_view.html',
                  {'workout':row,
                   'rower':rower,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   'graphs':g,
                   'last_name':u.last_name,
                   'records':records,
                   'summary':summary,
                   'recordsindoor':recordsindoor,
                   'first_name':u.first_name,
                   'interactiveplot':script,
                   'aantalcomments':aantalcomments,
                   'mapscript':mapscript,
                   'mapdiv':mapdiv,
                   'teams':get_my_teams(request.user),
                   'the_div':div})


# Resets stroke data to raw data (pace)
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
def workout_undo_smoothenpace_view(
        request,id=0,message="",successmessage=""
):
    row = get_workoutuser(id, request)
    r = getrower(request.user)

    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(encoder.decode_hex(id),row.df)

    url = reverse(r.defaultlandingpage,
                  kwargs = {
                      'id':id,
                      }
                  )


    return HttpResponseRedirect(url)


# Data smoothing of pace data
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
def workout_smoothenpace_view(request,id=0,message="",successmessage=""):
    row = get_workoutuser(id, request)

    previousurl = request.META.get('HTTP_REFERER')

    r = getrower(request.user)


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

    try:
        pace = row.df[' Stroke500mPace (sec/500m)'].values
        velo = 500./pace
    except KeyError:
        messages.error(request,'Unable to find the data')
        if previousurl:
            url = previousurl
        else:
            url = reverse(r.defaultlandingpage,
                          kwargs = {
                              'id':id,
                          }
            )

        return HttpResponseRedirect(url)

    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(encoder.decode_hex(id),row.df)

    messages.info(request,'A smoothening filter was applied to your pace data')

    if previousurl:
        url = previousurl
    else:
        url = reverse(r.defaultlandingpage,
                      kwargs = {
                          'id':id,
                      }
        )

    return HttpResponseRedirect(url)

# Process CrewNerd Summary CSV and update summary
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
    row = get_workoutuser(id, request)
    r = getrower(request.user)
    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': row.name
                },
            {
                'url':reverse('workout_crewnerd_summary_view',kwargs={'id':id}),
                'name': 'CrewNerd Summary'
                }

            ]

    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':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':id,
                                  })
                return HttpResponseRedirect(url)
        else:
            return render(request,
                          "cn_form.html",
                          {'form':form,
                           'active':'nav-workouts',
                           'rower':r,
                           'workout':row,
                           'breadcrumbs':breadcrumbs,
                           'teams':get_my_teams(request.user),
                           'id':row.id})
    else:
        form = CNsummaryForm()

        return render(request,
                      "cn_form.html",
                      {'form':form,
                       'active':'nav-workouts',
                       'rower':r,
                       'workout':row,
                       'breadcrumbs':breadcrumbs,
                       'teams':get_my_teams(request.user),
                       'id':row.id})

# Get weather for given location and date/time
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
def workout_downloadwind_view(request,id=0,
                              airportcode=None,
                              message="",successmessage=""):
    row = get_workoutuser(id, request)

    f1 = row.csvfilename

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

    try:
        bearing = rowdata.df.loc[:,'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.loc[:,'TimeStamp (sec)'].iloc[0])
        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]
        if message is not None:
            try:
                row.notes += "\n"+message
            except TypeError:
                if message is not None and row.notes is not None:
                    row.notes += message

        row.save()
        rowdata.add_wind(windspeed,windbearing)
        rowdata.write_csv(f1,gzip=True)

        messages.info(request,message)

        kwargs = {
            'id':id}

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



    return response

# Get weather for given location and date/time
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",redirect_field_name=None)
def workout_downloadmetar_view(request,id=0,
                              airportcode=None,
                              message="",successmessage=""):
    row = get_workoutuser(id, request)

    f1 = row.csvfilename


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

    try:
        bearing = rowdata.df.loc[:,'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.loc[:,'TimeStamp (sec)'].iloc[0])
        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]
        try:
            row.notes += "\n"+message
        except TypeError:
            if message is not None:
                try:
                    row.notes += message
                except TypeError:
                    pass

        row.save()
        rowdata.add_wind(windspeed,windbearing)
        rowdata.write_csv(f1,gzip=True)
        messages.info(request,message)

        kwargs = {
                  'id':id}

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



    return response


# Show form to update wind data
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",redirect_field_name=None)
def workout_wind_view(request,id=0,message="",successmessage=""):
    row = get_workoutuser(id, request)
    r = getrower(request.user)
    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': row.name
                },
            {
                'url':reverse('workout_wind_view',kwargs={'id':id}),
                'name': 'Wind'
                }

            ]


    # 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.loc[:,' latitude']
    except KeyError:
        hascoordinates = 0

    if hascoordinates and not latitude.std():
        hascoordinates = 0

    try:
        bearing = rowdata.df.loc[:,'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':id
            }
            url = reverse('workout_wind_view',kwargs=kwargs)
            response = HttpResponseRedirect(url)

    else:
        form = UpdateWindForm()

    # create interactive plot
    res = interactive_windchart(encoder.decode_hex(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,
                   'rower':r,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   '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)
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",redirect_field_name=None)
def workout_stream_view(request,id=0,message="",successmessage=""):
    row = get_workoutuser(id, request)
    r = getrower(request.user)




    # create interactive plot
    f1 = row.csvfilename
    u = row.user.user
    r = getrower(u)

    rowdata = rdata(f1)
    if rowdata == 0:
        messages.info(request,"Error: CSV data file not found")
        url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(row.id)})
        return HttpResponseRedirect(url)

    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':id}
            url = reverse('workout_wind_view',kwargs=kwargs)
            response = HttpResponseRedirect(url)

    else:
        form = UpdateStreamForm()

    # create interactive plot
    res = interactive_streamchart(encoder.decode_hex(id),promember=1)
    script = res[0]
    div = res[1]

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': row.name
                },
            {
                'url':reverse('workout_stream_view',kwargs={'id':id}),
                'name': 'Stream'
                }

            ]

    messages.info(request,successmessage)
    messages.error(request,message)
    return render(request,
                  'streamedit.html',
                  {'workout':row,
                   'rower':r,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   '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
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember, login_url="/rowers/paidplans",redirect_field_name=None)
def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
    w = get_workoutuser(id, request)
    r = getrower(request.user)

    mayedit = 1




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

        if form.is_valid():
            #quick_calc = form.cleaned_data['quick_calc']
            #go_service = form.cleaned_data['go_service']
            boattype = form.cleaned_data['boattype']
            weightvalue = form.cleaned_data['weightvalue']
            w.boattype = boattype
            w.weightvalue = weightvalue
            w.save()


            # load row data & create power/wind/bearing columns if not set
            f1 = w.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 = w.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,encoder.decode_hex(id),
                          ps=[r.p0,r.p1,r.p2,r.p3],
                          ratio=r.cpratio,
                    #      quick_calc = quick_calc,
                    #      go_service=go_service,
                          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':id}

            try:
                url = request.session['referer']
            except KeyError:
                url = reverse('workout_edit_view',kwargs=kwargs)

            response = HttpResponseRedirect(url)
            return response

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

    else:
        form = AdvancedWorkoutForm(instance=w)

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': w.name
                },
            {
                'url':reverse('workout_otwsetpower_view',kwargs={'id':id}),
                'name': 'OTW Power'
                }

            ]


    messages.error(request,message)
    messages.info(request,successmessage)
    return render(request,
                  'otwsetpower.html',
                  {'workout':w,
                   'rower':w,
                   'mayedit':mayedit,
                   'active':'nav-workouts',
                   'breadcrumbs':breadcrumbs,
                   'teams':get_my_teams(request.user),
                   'form':form,
                   })

@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def instroke_view(request,id=0):
    w = get_workoutuser(id, request)
    r = getrower(request.user)
    mayedit = 1

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': w.name
                },
            {
                'url':reverse('instroke_view',kwargs={'id':id}),
                'name': 'In-Stroke Metrics'
                }

            ]

#    form = WorkoutForm(instance=row)
    g = GraphImage.objects.filter(workout=w).order_by("-creationdatetime")
    # check if user is owner of this workout



    rowdata = rrdata(csvfile=w.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':w,
                   'rower':r,
                   'active':'nav-workouts',
                   'breadcrumbs':breadcrumbs,
                   'mayedit':mayedit,
                   'teams':get_my_teams(request.user),
                   'instrokemetrics':instrokemetrics,
                   })


# generate instroke chart
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def instroke_chart(request,id=0,metric=''):
    w = get_workoutuser(id, request)



    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 imgs.count() < 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)


# data explorer
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_data_view(request, id=0):

    r = getrower(request.user)
    w = get_workoutuser(id, request)


    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': w.name
                },
            {
                'url':reverse('workout_data_view',kwargs={'id':id}),
                'name': 'Data Explorer'
                }

            ]


    datadf,row = dataprep.getrowdata_db(id=encoder.decode_hex(id))

    try:
        datadf.sort_values(['ftime'],inplace=True)
    except KeyError:
        pass

    columns = datadf.columns.values

    to_be_dropped = [
        'id','time','hr_an','hr_at','hr_bottom','hr_max',
        'hr_tr','hr_ut1','hr_ut2','x_right',
    ]

    to_be_dropped = [c for c in to_be_dropped if c in columns]

    datadf.drop(labels=to_be_dropped,inplace=True,axis=1)


    cols = ['ftime','cumdist','fpace','spm',
            'hr','power','driveenergy','drivelength','averageforce',
            'peakforce','distance','drivespeed','workoutstate',
            'catch','finish','peakforceangle','wash','slip','rhythm',
            'effectiveangle','totalangle','distanceperstroke','velo']

    cols = [c for c in cols if c in datadf.columns]

    tcols = ['ftime','cumdist','fpace','spm','hr','power']

    datadf = datadf[cols]
    try:
        datadf.loc[:,'hr'] = datadf['hr'].astype('int')
        datadf.loc[:,'power'] = datadf['power'].astype('int')
        datadf.loc[:,'distance'] = datadf['distance'].astype('int')
        datadf.loc[:,'spm'] = 10*datadf['spm'].astype('int')/10.
    except KeyError:
        pass

    if request.method == 'POST':
        form = DataFrameColumnsForm(request.POST)
        if form.is_valid():
            tcols = form.cleaned_data['cols']

    else:
        form = DataFrameColumnsForm(initial = {'cols':tcols})

    try:
        datadf = datadf[tcols]
    except KeyError:
        # tcols = list(set(datadf.columns(tolist)+tcols))
        try:
            datadf = datadf[tcols]
            datadf = datadf.fillna(value=0)
        except KeyError:
            pass

    for col in cols:
        try:
            if datadf[col].mean() == 0 and datadf[col].std() == 0:
                datadf.drop(labels=[col],axis=1,inplace=True)
        except (TypeError,KeyError):
            pass

    #    pd.set_option('display.width', 1000)
    #pd.set_option('colheader_justify', 'left')

    htmltable = datadf.to_html(
        bold_rows=True,
        show_dimensions=True,border=1,
        classes=['pandastable'],justify='justify'
    )

    return render(request,
                  'workout_data.html',
                  {
                      'htmltable': htmltable,
                      'form':form,
                      'teams':get_my_teams(request.user),
                      'workout': w,
                      'breadcrumbs': breadcrumbs,

                      }
                  )


# Stats page
@permission_required('workout.view_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_stats_view(request,id=0,message="",successmessage=""):

    r = getrower(request.user)
    w = get_workout(id)

    mayedit = 0
    if request.user == w.user.user:
        mayedit=1
    if is_workout_user(request.user,w):
        mayedit=1

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': w.name
                },
            {
                'url':reverse('workout_stats_view',kwargs={'id':id}),
                'name': 'Stats'
                }

            ]

    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=encoder.decode_hex(id))


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


    if datadf.empty:
        datadf,row = dataprep.getrowdata_db(id=encoder.decode_hex(id))
        datadf = dataprep.clean_df_stats(datadf,workstrokesonly=False,
                                         ignoreadvanced=True)
        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')
    try:
        fielddict.pop('pace')
    except KeyError:
        pass

    for field,verbosename in fielddict.items():
        try:
            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
        except KeyError:
            pass

    # Create a dict with correlation values
    cor = datadf.corr(method='spearman')
    cor.fillna(value=0,inplace=True)
    cordict = {}
    for field1,verbosename1 in fielddict.items():
        thedict = {}
        for field2,verbosename2 in fielddict.items():
            try:
                thedict[verbosename2] = cor.loc[field1,field2]
            except KeyError:
                thedict[verbosename2] = 0

            cordict[verbosename1] = 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':w,
                      'rower':r,
                      'mayedit':mayedit,
                      'breadcrumbs':breadcrumbs,
                      'active':'nav-workouts',
                      'workstrokesonly':workstrokesonly,
                      'cordict':cordict,
                      'otherstats':otherstats,
                  })



# 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_config2_view(request,userid=0):
    request.session['referer'] = absolute(request)['PATH']
    request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
    try:
        workoutid = request.session['lastworkout']
    except KeyError:
        workoutid = 0


    r = getrequestrower(request,userid=userid,notpermanent=True)

    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':r,
                      'leftpanel_formset':leftpanel_formset,
                      'middlepanel_formset':middlepanel_formset,
                      'workoutid': workoutid,
                      })



# Workflow View
@login_required()
@permission_required('workout.view_workout',fn=get_workout_by_opaqueid,raise_exception=True)
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_by_opaqueid(request,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)

    favorites,maxfav = getfavorites(r,row)

    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


    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': row.name
                },
            {
                'url':reverse('workout_workflow_view',kwargs={'id':id}),
                'name': 'View'
                }

            ]

    return render(request,
                  'workflow.html',
                  {
                      'middleTemplates':middleTemplates,
                      'leftTemplates':leftTemplates,
                      'active':'nav-workouts',
                      'breadcrumbs':breadcrumbs,
                      'charts':charts,
                      'workout':row,
                      'mapscript':mapscript,
                      'mapdiv':mapdiv,
                      'statcharts':statcharts,
                      'rower':r,
                      'aantalcomments':aantalcomments,
                  })

# The famous flex chart
@login_required()
@permission_required('workout.view_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_flexchart3_view(request,*args,**kwargs):

    try:
        id = kwargs['id']
    except KeyError:
        raise Http404("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)
    r = getrequestrower(request)

    promember=0
    mayedit=0
    if not request.user.is_anonymous:
        result = ispromember(request.user)
        if result:
            promember=1
        if request.user == row.user.user:
            mayedit=1
        if is_workout_user(request.user,row):
            mayedit=1

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

    favorites,maxfav = getfavorites(r,row)

    # 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 'xaxis' in request.POST:
        flexoptionsform = FlexOptionsForm(request.POST)
        if flexoptionsform.is_valid():
            cd = flexoptionsform.cleaned_data
            includereststrokes = cd['includereststrokes']
            plottype = cd['plottype']

            workstrokesonly = not includereststrokes

        flexaxesform = FlexAxesForm(request,request.POST)

        if flexaxesform.is_valid():
            cd = flexaxesform.cleaned_data
            xparam = cd['xaxis']
            yparam1 = cd['yaxis1']
            yparam2 = cd['yaxis2']
        else:
            pass


    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(
            encoder.decode_hex(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(
            encoder.decode_hex(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 mytypes.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,TypeError):
        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}
    extrametrics = additionalmetrics

    initial = {
        'xaxis':xparam,
        'yaxis1':yparam1,
        'yaxis2':yparam2,
    }
    flexaxesform = FlexAxesForm(request,initial=initial,
                                extrametrics=extrametrics)

    initial = {
        'includereststrokes': not workstrokesonly,
        'plottype':plottype
        }

    flexoptionsform = FlexOptionsForm(initial=initial)

    row = Workout.objects.get(id=encoder.decode_hex(id))

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': row.name
                },
            {
                'url':reverse('workout_flexchart3_view',kwargs=kwargs),
                'name': 'Flex Chart'
                }

            ]


    return render(request,
                  'flexchart3otw.html',
                  {'the_script':script,
                   'the_div':div,
                   'breadcrumbs':breadcrumbs,
                   'rower':r,
                   'active':'nav-workouts',
                   'workout':row,
                   'chartform':flexaxesform,
                   'optionsform':flexoptionsform,
                   'js_res': js_resources,
                   'css_res':css_resources,
                   'teams':get_my_teams(request.user),
                   'id':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 wind corrected pace for OTW outings
def workout_otwpowerplot_view(request,id=0,message="",successmessage=""):
    w = get_workout(id)
    r = getrower(request.user)

    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url':get_workout_default_page(request,id),
            'name': w.name
        },
        {
            'url':reverse('workout_otwpowerplot_view',kwargs={'id':id}),
            'name': 'Interactive OTW Power Plot'
        }

    ]

    # check if user is owner of this workout


    # create interactive plot
    f1 = w.csvfilename
    u = w.user.user
    # r = getrower(u)

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

    # create interactive plot
    res = interactive_otw_advanced_pace_chart(encoder.decode_hex(id),promember=promember)
    script = res[0]
    div = res[1]

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

    return render(request,
                  'otwinteractive.html',
                  {'workout':w,
                   'rower':r,
                   'active':'nav-workouts',
                   'breadcrumbs':breadcrumbs,
                   'teams':get_my_teams(request.user),
                   'interactiveplot':script,
                   'the_div':div,
                   'mayedit':mayedit})


#
@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)
            try:
                if isinstance(comment,unicode):
                    comment = comment.encode('utf8')
                elif isinstance(comment, str):
                    comment = comment.decode('utf8')
            except:
                pass


            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

    rower = getrower(request.user)

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': w.name
                },
            {
                'url':reverse('workout_comment_view',kwargs={'id':id}),
                'name': 'Comments'
                }

            ]


    return render(request,
                  'workout_comments.html',
                  {'workout':w,
                   'rower':rower,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   'teams':get_my_teams(request.user),
                   'graphs':g,
                   'comments':comments,
                   'form':form,
                  })



# The basic edit page
@login_required()
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
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_workoutuser(id,request)

    if request.user.rower.rowerplan == 'basic' and 'speedcoach2' in row.workoutsource:
        data = getsmallrowdata_db(['wash'],ids=[encoder.decode_hex(id)])
        try:
            if data['wash'].std() != 0:
                url = reverse('paidplans_view')
                messages.info(
                    request,
                    'Some Empower Oarlock data are only available to users with a <a href="{u}">paid plan</a>'.format(u=url)
                )
        except:
            pass

    form = WorkoutForm(instance=row)

    if request.method == 'POST':
        # Form was submitted
        form = WorkoutForm(request.POST,instance=row)
        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']
            adaptiveclass = form.cleaned_data['adaptiveclass']
            duration = form.cleaned_data['duration']
            distance = form.cleaned_data['distance']
            private = form.cleaned_data['private']
            notes = form.cleaned_data['notes']
            newdragfactor = form.cleaned_data['dragfactor']
            thetimezone = form.cleaned_data['timezone']

            try:
                ps = form.cleaned_data['plannedsession']
            except KeyError:
                ps = None

            try:
                boattype  = request.POST['boattype']
            except KeyError:
                boattype = Workout.objects.get(id=encoder.decode_hex(id)).boattype
            try:
                privacy = request.POST['privacy']
            except KeyError:
                privacy = Workout.objects.get(id=row.id).privacy
            try:
                rankingpiece = form.cleaned_data['rankingpiece']
            except KeyError:
                rankingpiece =- Workout.objects.get(id=row.id).rankingpiece

            try:
                duplicate = form.cleaned_data['duplicate']
            except KeyError:
                duplicate = Workout.objects.get(id=row.id).duplicate

            if private:
                privacy = 'private'
            else:
                privacy = 'visible'

            try:
                startdatetime = datetime.datetime.combine(
                    date,starttime
                )
            except TypeError:
                startdatetime = datetime.datetime.combine(
                    date,datetime.datetime.min.time()
                    )

            try:
                startdatetime = pytz.timezone(thetimezone).localize(
                    startdatetime
                )
            except UnknownTimeZoneError:
                pass

            try:
                # aware object can be in any timezone
                out = startdatetime.astimezone(pytz.utc)
            except (ValueError, TypeError):
                startdatetime = timezone.make_aware(startdatetime)

            try:
                startdatetime = startdatetime.astimezone(pytz.timezone(thetimezone))
            except UnknownTimeZoneError:
                thetimezone = 'UTC'

            timechanged = (startdatetime != row.startdatetime)

            row.name  = name
            row.date = date
            row.starttime = starttime
            row.startdatetime = startdatetime
            row.workouttype = workouttype
            row.weightcategory = weightcategory
            row.adaptiveclass = adaptiveclass
            row.notes = notes
            row.duration = duration
            row.distance = distance
            row.boattype = boattype
            row.duplicate = duplicate
            row.privacy = privacy
            row.rankingpiece = rankingpiece
            row.timezone = thetimezone
            row.plannedsession = ps

            dragchanged = False
            if newdragfactor != row.dragfactor:
                row.dragfactor = newdragfactor
                dragchanged = True

            try:
                row.save()
            except IntegrityError:
                pass

            if ps:
                add_workouts_plannedsession([row],ps,row.user)

            # change data in csv file
            datachanged = (dragchanged or timechanged)
            if datachanged:
                r = rdata(row.csvfilename)
                if dragchanged:
                    try:
                        r.change_drag(newdragfactor)
                    except AttributeError:
                        pass

                if r == 0:
                    return HttpResponse("Error: CSV Data File Not Found")
                r.rowdatetime = startdatetime
                r.write_csv(row.csvfilename,gzip=True)
                dataprep.update_strokedata(encoder.decode_hex(id),r.df)

            successmessage = "Changes saved"

            if rankingpiece:
                dataprep.runcpupdate(row.user,type=row.workouttype)

            messages.info(request,successmessage)
    else:
        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

    videos = VideoAnalysis.objects.filter(workout=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']
            longitude = rowdata.df[' longitude']
            if not latitude.std():
                hascoordinates = 0
            if not longitude.std():
                hascoordinates = 0
        except (KeyError,AttributeError):
            hascoordinates = 0

    else:
        hascoordinates = 0


    mapscript = ""
    mapdiv = ""

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

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,encoder.encode_hex(row.id)),
                'name': row.name
                },
            {
                'url':reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(row.id)}),
                'name': 'Edit'
                }

            ]

    if row.workouttype in mytypes.otetypes:
        indoorraces = get_indoorraces(row)
    else:
        indoorraces = []


    r = row.user
    # render page
    return render(request, 'workout_form.html',
                  {'form':form,
                   'workout':row,
                   'teams':get_my_teams(request.user),
                   'graphs':g,
                   'videos':videos,
                   'breadcrumbs':breadcrumbs,
                   'rower':r,
                   'indoorraces':indoorraces,
                   'active':'nav-workouts',
                   'mapscript':mapscript,
                   'mapdiv':mapdiv,
                   'rower':r,
                  })




@login_required()
def workout_map_view(request,id=0):
    request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
    request.session['referer'] = absolute(request)['PATH']

    w = get_workout(id)

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': w.name
                },
            {
                'url':reverse('workout_map_view',kwargs={'id':id}),
                'name': 'Map'
                }

            ]


    # create interactive plot
    f1 = w.csvfilename
    u = w.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'],
                                         w.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 == w.user.user:
            mayedit=1

    return render(request, 'map_view.html',
                  {'mapscript':mapscript,
                   'workout':w,
                   'rower':r,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   'mapdiv':mapdiv,
                   'mayedit':mayedit,
                   })




# Image upload
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_uploadimage_view(request,id):
    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    r = getrower(request.user)

    w = get_workoutuser(id, request)

    breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,id),
                'name': w.name
                },
            {
                'url':reverse('workout_uploadimage_view',kwargs={'id':id}),
                'name': 'Upload Image'
                }

            ]



    images = GraphImage.objects.filter(workout=w)


    if images.count() >= 6:
        message = "You have reached the maximum number of static images for this workout"
        messages.error(request,message)
        url = reverse(r.defaultlandingpage,
                      kwargs = {
                          'id':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,
                           'rower':r,
                           'active':'nav-workouts',
                           'breadcrumbs':breadcrumbs,
                           'teams':get_my_teams(request.user),
                           'workout': w,
                           })
        else:
            return {'result':0}



# Generic chart creation
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_add_chart_view(request,id,plotnr=1):

    w = get_workoutuser(id, request)
    r = getrower(request.user)

    plotnr = int(plotnr)


    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')]


    url = reverse(r.defaultlandingpage,kwargs={'id':encoder.encode_hex(w.id)})

    return HttpResponseRedirect(url)





@login_required
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_toggle_ranking(request,id=0):
    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    row = get_workout_by_opaqueid(request,id)

    row.rankingpiece = not row.rankingpiece
    row.save()

    if is_ajax:
        response = JSONResponse({'result':row.rankingpiece},
                                content_type='application/json')

        return response
    else:
        url = reverse('workouts_view')
        response = HttpResponseRedirect(url)

    return response

# simple POST API for files on local (e.g. in mailbox)
@csrf_exempt
def workout_upload_api(request):
    stravaid = ''
    if request.method != 'POST':
        message = {'status':'false','message':'this view cannot be accessed through GET'}
        return JSONResponse(status=403,data=message)


    # test if JSON
    try:
        json_data = json.loads(request.body)
        secret = json_data['secret']
        post_data = json_data
    except (KeyError,JSONDecodeError):
        q = request.POST
        post_data = {k: q.getlist(k) if len(q.getlist(k))>1 else v for k, v in q.items()}

    # only allow local host
    hostt = request.get_host().split(':')
    if hostt[0] not in ['localhost','127.0.0.1','dev.rowsandall.com','rowsandall.com']:
        message = {'status':'false','message':'permission denied for host '+hostt[0]}
        return JSONResponse(status=403,data=message)

    # check credentials here
    try:
        secret = post_data['secret']
    except KeyError:
        message = {'status': 'false', 'message':'missing credentials'}
        return JSONResponse(status=400,data=message)
    if secret != settings.UPLOAD_SERVICE_SECRET:
        message = {'status':'false','message':'invalid credentials'}
        return JSONResponse(status=403,data=message)

    form = DocumentsForm(post_data)
    optionsform = TeamUploadOptionsForm(post_data)
    rowerform = TeamInviteForm(post_data)
    rowerform.fields.pop('email')
    try:
        fstr = post_data['file']
        nn, ext = os.path.splitext(fstr)
        if ext== '.gz':
            nn, ext2 = os.path.splitext(nn)
            ext = ext2+ext
        f1 = uuid.uuid4().hex[:10]+'-'+time.strftime("%Y%m%d-%H%M%S")+ext
        f2 = 'media/'+f1
        copyfile(fstr,f2)
    except KeyError:
        message = {'status':'false','message':'no filename given'}
        return JSONResponse(status=400,data=message)
    except FileNotFoundError:
        message = {'status':'false','message':'could not find file'}
        return JSONResponse(status=400,data=message)

    try:
        stravaid = post_data['stravaid']
    except KeyError:
        stravaid = ''

    if form.is_valid():
        t = form.cleaned_data['title']
        boattype = form.cleaned_data['boattype']
        workouttype = form.cleaned_data['workouttype']
        if rowerform.is_valid():
            u = rowerform.cleaned_data['user']
            r = getrower(u)
        elif 'useremail' in post_data:
            us = User.objects.filter(email=post_data['useremail'])
            if len(us):
                u = us[0]
                r = getrower(u)
            else:
                message = {'status':'false','message':'could not find user'}
                return JSONResponse(status=400,data=message)
        else:
            message = {'status':'false','message':'invalid user'}
            return JSONResponse(status=400,data=message)

        notes = form.cleaned_data['notes']
        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']
        else:
            message = optionsform.errors
            return JSONResponse(status=400,data=message)


        id, message, f2 = dataprep.new_workout_from_file(
            r,f2,
            workouttype=workouttype,
            workoutsource=None,
            boattype=boattype,
            makeprivate=makeprivate,
            title = t,
            notes=notes,
            uploadoptions=post_data,
        )

        if id == 0:
            if message is not None:
                message = {'status':'false','message':'unable to process file: '+message}
            else:
                message = {'status': 'false', 'message': 'unable to process file'}
            return JSONResponse(status=400,data=message)
        if id == -1:
            message = {'status': 'true', 'message':message}
            return JSONResponse(status=200,data=message)

        w = Workout.objects.get(id=id)

        if make_plot:
            res, jobid = uploads.make_plot(r,w,f1,f2,plottype,t)

        uploads.do_sync(w,post_data,quick=True)

    else: # form invalid
        if fstr:
            os.remove(fstr)
        message = form.errors
        return JSONResponse(status=400,data=message)

    message = {'status': 'true','id':w.id}
    statuscode = 200
    if fstr:
        try:
            os.remove(fstr)
        except FileNotFoundError:
            message = {'status': 'true', 'id':w.id,'message': 'Error deleting temporary file'}
            statuscode = 500

    if r.getemailnotifications and not r.emailbounced:
        link = settings.SITE_URL+reverse(
                r.defaultlandingpage,
            kwargs = {
                'id':encoder.encode_hex(w.id),
            }
        )
        email_sent = send_confirm(r.user, t, link, '')
    return JSONResponse(status=statuscode,data=message)


# 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',
                        },
                        raceid=0):

    is_ajax = False
    if request.is_ajax():
        is_ajax = True

    r = getrower(request.user)
    if r.rowerplan == 'freecoach':
        url = reverse('team_workout_upload_view')
        return HttpResponseRedirect(url)

    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url': reverse('workout_upload_view'),
            'name': 'Upload'
            }
        ]

    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:
        notes = docformoptions['notes']
    except KeyError:
        notes = ''

    try:
        workoutsource = uploadoptions['workoutsource']
    except KeyError:
        workoutsource = None

    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,request=request,raceid=raceid)

        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']

            race = None
            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']

                try:
                    race = optionsform.cleaned_data['submitrace']
                except KeyError:
                    race = None

                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,
                    workoutsource=workoutsource,
                    boattype=boattype,
                    makeprivate=makeprivate,
                    title = t,
                    notes=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)

                w = Workout.objects.get(id=id)

                url = reverse('workout_edit_view',
                              kwargs = {
                                  'id':encoder.encode_hex(w.id),
                              })

                if is_ajax:
                    response = {'result': 1,'url':url}
                else:
                    response = HttpResponseRedirect(url)


            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):
                try:
                    message,id = c2stuff.workout_c2_upload(request.user,w)
                except NoTokenError:
                    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):
                try:
                    message,id = stravastuff.workout_strava_upload(
                        request.user,w,
                    )
                except NoTokenError:
                    id = 0
                    message = "Please connect to Strava first"
                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)

            if (upload_to_st):
                try:
                    message,id = sporttracksstuff.workout_sporttracks_upload(
                        request.user,w
                    )
                except NoTokenError:
                    message = "Please connect to SportTracks first"
                    id = 0
                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)

            if (upload_to_rk):
                try:
                    message,id = runkeeperstuff.workout_runkeeper_upload(
                        request.user,w
                        )
                except NoTokenError:
                    message = "Please connect to Runkeeper first"
                    id = 0

                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)


            if (upload_to_ua):
                try:
                    message,id = underarmourstuff.workout_ua_upload(
                        request.user,w
                    )
                except NoTokenError:
                    message = "Please connect to MapMyFitness first"
                    id = 0

                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)


            if (upload_to_tp):
                try:
                    message,id = tpstuff.workout_tp_upload(
                        request.user,w
                        )
                except NoTokenError:
                    message = "Please connect to TrainingPeaks first"
                    id = 0

                if id>1:
                    messages.info(request,message)
                else:
                    messages.error(request,message)

            if race and race_can_submit(r,race):
                if race.sessiontype == 'indoorrace':
                    records = IndoorVirtualRaceResult.objects.filter(
                        race=race,
                        userid=r.id
                        )

                    if records:

                        result,comments,errors,jobid = add_workout_indoorrace(
                            [w],race,r,recordid=records[0].id
                            )

                        if result:
                            messages.info(
                                request,
                                "We have submitted your workout to the race")

                        for c in comments:
                            messages.info(request,c)
                        for er in errors:
                            messages.error(request,er)
                if race.sessiontype == 'race':
                    records = VirtualRaceResult.objects.filter(
                        race=race,userid=r.id
                    )


                    if records:
                        result,comments,errors,jobid = add_workout_race(
                            [w], race,r,recordid=records[0].id
                        )
                        if result:
                            messages.info(
                                request,
                                "We have submitted your workout to the race")

                        for c in comments:
                            messages.info(request,c)
                        for er in errors:
                            messages.error(request,er)


            if landingpage != 'workout_upload_view':
                url = reverse(landingpage,
                              kwargs = {
                                  'id':encoder.encode_hex(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:
            if r.c2_auto_export and ispromember(r.user):
                uploadoptions['upload_to_C2'] = True

            if r.strava_auto_export and ispromember(r.user):
                uploadoptions['upload_to_Strava'] = True

            if r.sporttracks_auto_export and ispromember(r.user):
                uploadoptions['upload_to_SportTracks'] = True

            if r.runkeeper_auto_export and ispromember(r.user):
                uploadoptions['upload_to_RunKeeper'] = True

            if r.trainingpeaks_auto_export and ispromember(r.user):
                uploadoptions['upload_to_TrainingPeaks'] = True

            if r.mapmyfitness_auto_export and ispromember(r.user):
                uploadoptions['upload_to_MapMyFitness'] = True

            form = DocumentsForm(initial=docformoptions)
            optionsform = UploadOptionsForm(initial=uploadoptions,
                                            request=request,raceid=raceid)
            return render(request, 'document_form.html',
                          {'form':form,
                           'active':'nav-workouts',
                           'breadcrumbs':breadcrumbs,
                           '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="/rowers/paidplans",redirect_field_name=None,
                  message="This functionality requires a Coach plan or higher")
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

    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url': reverse('team_workout_upload_view'),
            'name': 'Team Upload'
            }
        ]


    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')
        rowers = Rower.objects.filter(
            coachinggroups__in=[r.mycoachgroup]
        ).exclude(
            rowerplan='freecoach'
        ).distinct()
        if r.rowerplan == 'freecoach':
            rowers = rowers.exclude(rowerplan='basic')

        rowerform.fields['user'].queryset = User.objects.filter(rower__in=rowers).distinct()
        rowerform.fields['user'].required = True
        if form.is_valid() and rowerform.is_valid():
            f = request.FILES.get('file',False)
            if f:
                res = handle_uploaded_file(f)
            else:
                messages.error(request,'No file attached')
                response = render(request,
                                  'team_document_form.html',
                                  {'form':form,
                                   'teams':get_my_teams(request.user),
                                   'optionsform':optionsform,
                                   'rowerform':rowerform,
                                   })
                return response

            t = form.cleaned_data['title']
            offline = form.cleaned_data['offline']
            boattype = form.cleaned_data['boattype']
            workouttype = form.cleaned_data['workouttype']
            if rowerform.is_valid():
                u = rowerform.cleaned_data['user']
                r = getrower(u)
                if not can_add_workout_member(request.user,r):
                    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),
                              'active': 'nav-workouts',
                              'breadcrumbs':breadcrumbs,
                              'optionsform': optionsform,
                              'rowerform': rowerform,
                             })

        return response
    else:
        form = DocumentsForm()
        optionsform = TeamUploadOptionsForm(initial=uploadoptions)
        rowerform = TeamInviteForm()
        rowerform.fields.pop('email')

        rowers = Rower.objects.filter(
            coachinggroups__in=[r.mycoachgroup]
        ).exclude(
            rowerplan='freecoach'
        ).distinct()
        if r.rowerplan == 'freecoach':
            rowers = rowers.exclude(rowerplan='basic')

        rowerform.fields['user'].queryset = User.objects.filter(rower__in=rowers).distinct()


        return render(request, 'team_document_form.html',
                      {'form':form,
#                       'teams':get_my_teams(request.user),
                       'optionsform': optionsform,
                       'active': 'nav-workouts',
                       'breadcrumbs':breadcrumbs,
#                       'rower':r,
                       'rowerform':rowerform,
                      })





# A page with all the recent graphs (searchable on workout name)
@login_required()
def list_videos(request,userid=0):
    r = getrequestrower(request,userid=userid)
    workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
    query = request.GET.get('q')
    if query:
        query_list = query.split()
        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))
                )
            searchform = SearchForm(initial={'q':query})
    else:
        searchform = SearchForm()

    g = VideoAnalysis.objects.filter(workout__in=workouts).order_by("-workout__date")


    paginator = Paginator(g,8)
    page = request.GET.get('page')

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

    return render(request, 'list_videos.html',
                  {'analyses': g,
                   'searchform':searchform,
                   'active':'nav-analysis',
                   'rower':r,
                   'teams':get_my_teams(request.user),
                   })

@login_required()
def graphs_view(request,userid=0):
    request.session['referer'] = reverse('graphs_view')
    r = getrequestrower(request,userid=userid)
    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))
            )
        searchform = SearchForm(initial={'q':query})
    else:
        searchform = SearchForm()

    g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")


    paginator = Paginator(g,8)
    page = request.GET.get('page')

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

    return render(request, 'list_graphs.html',
                      {'graphs': g,
                       'searchform':searchform,
                       'active':'nav-workouts',
                       'teams':get_my_teams(request.user),
                       'rower':r,
                      })



# 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)

        breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(request,encoder.encode_hex(w.id)),
                'name': w.name
                },
            {
                'url':reverse('graph_show_view',kwargs={'id':id}),
                'name': 'Chart'
                }

            ]


        return render(request,'show_graph.html',
                      {'graph':g,
                       'teams':get_my_teams(request.user),
                       'workout':w,
                       'breadcrumbs':breadcrumbs,
                       'active':'nav-workouts',
                       '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
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_summary_restore_view(request,id,message="",successmessage=""):
    row = get_workout_by_opaqueid(request,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 mytypes.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(encoder.decode_hex(id),rowdata.df)
    intervalstats = rowdata.allstats()
    row.summary = intervalstats
    row.save()

    # create interactive plot
    try:
        res = interactive_chart(encoder.decode_hex(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':encoder.encode_hex(row.id),
                  }
    )
    return HttpResponseRedirect(url)

# Split a workout
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",
                  message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
                  redirect_field_name=None)
def workout_split_view(request,id=0):
    row = get_workout_by_opaqueid(request,id)

    r = row.user

    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url':get_workout_default_page(request,id),
            'name': row.name
        },
        {
            'url':reverse('workout_split_view',
                          kwargs={'id':id}),
            'name': 'Chart'
        }

    ]
    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
                )
                for message in mesgs:
                    messages.info(request,message)
            except IndexError:
                messages.error(request,"Something went wrong in Split")


            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
            try:
                if isinstance(rowname,unicode):
                    rowname = rowname.encode('utf8')
                elif isinstance(rowname, str):
                    rowname = rowname.decode('utf8')
            except:
                pass

            qdict = {'q':rowname}
            url+='?'+urllib.parse.urlencode(qdict)

            return HttpResponseRedirect(url)

    form = WorkoutSplitForm()

    # create interactive plot
    try:
        res = interactive_chart(encoder.decode_hex(id),promember=1)
        script = res[0]
        div = res[1]
    except ValueError:
        pass

    return render(request, 'splitworkout.html',
                  {'form':form,
                   'rower':r,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   'workout':row,
                   'thediv':script,
                   'thescript':div,
                  })


# Fuse two workouts
@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",redirect_field_name=None)
def workout_fusion_view(request,id1=0,id2=1):

    try:
        id1 = encoder.decode_hex(id1)
        id2 = encoder.decode_hex(id2)
    except:
        pass

    r = getrower(request.user)

    try:
        w1 = Workout.objects.get(id=id1)
        w2 = Workout.objects.get(id=id2)
        r = w1.user
        if (is_workout_user(request.user,w1)==False) or \
           (is_workout_user(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':encoder.encode_hex(idnew),
                          })

            return HttpResponseRedirect(url)
    else:
        form = FusionMetricChoiceForm(instance=w2)

    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url':get_workout_default_page(request,encoder.encode_hex(w1.id)),
            'name': encoder.encode_hex(w1.id)
        },
        {
            'url':reverse('workout_fusion_list',
                          kwargs={'id':encoder.encode_hex(id1)}),
            'name': 'Sensor Fusion'
        },
        {
            'url':reverse('workout_fusion_view',
                          kwargs={
                              'id1':encoder.encode_hex(id1),
                              'id2':encoder.encode_hex(id2)
                          }),
            'name': encoder.encode_hex(w2.id)
        }

    ]

    return render(request, 'fusion.html',
                  {'form':form,
                   'teams':get_my_teams(request.user),
                   'workout':w1,
                   'rower':r,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   'workout1':w1,
                   'workout2':w2,
                  })


# Edit the splits/summary
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_summary_edit_view(request,id,message="",successmessage=""
                              ):
    row =  get_workout_by_opaqueid(request,id)
    r = getrower(request.user)
    breadcrumbs = [
        {
            'url':'/rowers/list-workouts/',
            'name':'Workouts'
        },
        {
            'url':get_workout_default_page(request,encoder.encode_hex(row.id)),
            'name': row.name
        },
        {
            'url':reverse('workout_summary_edit_view',kwargs={'id':id}),
            'name': 'Edit Intervals'
        }

    ]

    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 mytypes.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)

    activeminutesmax = int(rowdata.duration/60.)
    activeminutesmin = 0
    maxminutes = activeminutesmax

    savebutton = 'nosavebutton'
    formvalues = {}
    form = SummaryStringForm()

    tss = row.rscore
    normp = row.normp
    normv = row.normv
    normw = row.normw
    try:
        normspm = rowdata.df[' Cadence (stokes/min)'].mean()
    except KeyError:
        normspm = 0

    if tss == -1:
        tss,normp = dataprep.workout_rscore(row)
        normv,normw = dataprep.workout_normv(row,pp=8.0)

    work = int(normw)
    power = int(normp)
    try:
        pace_secs = int(500./normv)
    except (OverflowError, ZeroDivisionError):
        pace_secs = 140.

    try:
        avpace = datetime.timedelta(seconds=int(500./normv))
    except (OverflowError, ZeroDivisionError):
        avpace = datetime.timedelta(seconds=130)

    data = {
        'power': int(normp),
        'pace': avpace,
        'selector': 'power',
        'work': int(normw),
        'spm': int(normspm),
        'activeminutesmin': 0,
        'activeminutesmax': activeminutesmax,
        }

    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:
                messages.error(request,'Parsing error')
            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']
        value_spm = request.POST['value_spm']
        activeminutesmin = request.POST['activeminutesmin']
        activeminutesmax = request.POST['activeminutesmax']
        try:
            activesecondsmin = 60.*float(activeminutesmin)
            activesecondsmax = 60.*float(activeminutesmax)
        except ValueError:
            activesecondsmin = 0
            activeminutesmin = 0
            activeminutesmax = maxminutes
            activesecondsmax = rowdata.duration

        if abs(rowdata.duration-activesecondsmax) < 60.:
            activesecondsmax = rowdata.duration
        if powerorpace == 'power':
            try:
                power = int(value_power)
            except ValueError:
                int(normp)
        elif powerorpace == 'pace':
            try:
                pace_secs = float(value_pace)
            except ValueError:
                try:
                    pace_secs = float(value_pace.replace(',','.'))
                except ValueError:
                    pace_secs  = int(500./normv)
        elif powerorpace == 'work':
            try:
                work = int(value_work)
            except ValueError:
                work = int(normw)
        elif powerorpace == 'spm':
            try:
                spm = int(value_spm)
            except ValueError:
                spm = int(normspm)

        if powerorpace == 'power' and power is not None:
            try:
                rowdata.updateinterval_metric(
                    ' Power (watts)',power,mode='larger',
                    debug=False,smoothwindow=15.,
                    activewindow=[activesecondsmin,activesecondsmax],
                    )
            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.,
                    activewindow=[activesecondsmin,activesecondsmax],
                    )
            except:
                messages.error(request,'Error updating pace')
        elif powerorpace == 'work':
            try:
                rowdata.updateinterval_metric(
                    'driveenergy',work,mode='larger',
                    debug=False,smoothwindow=15.,
                    activewindow=[activesecondsmin,activesecondsmax],
                    )
            except:
                messages.error(request,'Error updating Work per Stroke')
        elif powerorpace == 'spm':
            try:
                rowdata.updateinterval_metric(
                    ' Cadence (stokes/min)',spm,mode='larger',
                    debug=False,smoothwindow=2.,
                    activewindow=[activesecondsmin,activesecondsmax],)
            except:
                messages.error(request,'Error updating SPM')

        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(encoder.decode_hex(id),rowdata.df)

        messages.info(request,"Updated interval data saved")
        data = {
            'power': power,
            'pace': datetime.timedelta(seconds=int(pace_secs)),
            'work': work,
            'selector': powerorpace,
            'spm': int(normspm),
            'activeminutesmin': activeminutesmin,
            'activeminutesmax': activeminutesmax,
        }
        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(encoder.decode_hex(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),
            'spm': int(normspm),
            'activeminutesmin': 0,
            'activeminutesmax': activeminutesmax,
        })
        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']
            spm = cd['spm']
            activeminutesmin = cd['activeminutesmin']
            activeminutesmax = cd['activeminutesmax']
            activesecondsmin = 60.*activeminutesmin
            activesecondsmax = 60.*activeminutesmax
            if abs(rowdata.duration-activesecondsmax) < 60.:
                activesecondsmax = rowdata.duration
            try:
                pace_secs = pace.seconds+pace.microseconds/1.0e6
            except AttributeError:
                pace_secs = 120.

            if powerorpace == 'power' and power is not None:
                rowdata.updateinterval_metric(' Power (watts)',power,mode='larger',
                                                  debug=False,smoothwindow=15,
                                                  activewindow=[activesecondsmin,activesecondsmax],
                                                  )

            elif powerorpace == 'pace':
                try:
                    velo = 500./pace_secs
                    rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',velo,mode='larger',
                                                  debug=False,smoothwindow=15,
                                                  activewindow=[activesecondsmin,activesecondsmax],
                                                  )
                except:
                    messages.error(request,'Error updating pace')
            elif powerorpace == 'work':
                try:
                    rowdata.updateinterval_metric(
                        'driveenergy',work,mode='larger',
                        debug=False,smoothwindow=15.,
                        activewindow=[activesecondsmin,activesecondsmax],)
                except:
                    messages.error(request,'Error updating Work per Stroke')
            elif powerorpace == 'spm':
                try:
                    rowdata.updateinterval_metric(' Cadence (stokes/min)',spm,mode='larger',
                                                  debug=False,smoothwindow=2.,
                                                  activewindow=[activesecondsmin,activesecondsmax],
                                                  )
                except:
                    messages.error(request,'Error updating SPM')


            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,
                'value_spm': spm,
                'activeminutesmin': activeminutesmin,
                'activeminutesmax': activeminutesmax,
                }
            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 range(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
        try:
            row.notes += "\n"+s
        except TypeError:
            pass

        row.save()
        rowdata.write_csv(f1,gzip=True)
        dataprep.update_strokedata(encoder.decode_hex(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),
            'spm': int(normspm),
            'activeminutesmin': 0,
            'activeminutesmax': activeminutesmax,
        })


    # 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 range(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 range(nrintervals):
        try:
            initial['intervald_%s' % i] = idist[i]
            initial['intervalt_%s' % i] = get_time(itime[i])
            initial['type_%s' % i] = itype[i]
        except IndexError:
            pass


    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(encoder.decode_hex(id),promember=1,intervaldata=intervaldata)
        script = res[0]
        div = res[1]
    except ValueError:
        script = ''
        div = ''

    # render page

    return render(request, 'summary_edit.html',
                  {'form':form,
                   'activeminutesmax':activeminutesmax,
                   'activeminutesmin':activeminutesmin,
                   'maxminutes': maxminutes,
                   'detailform':detailform,
                   'powerupdateform':powerupdateform,
                   'workout':row,
                   'rower':r,
                   'breadcrumbs':breadcrumbs,
                   'active':'nav-workouts',
                   'teams':get_my_teams(request.user),
                   'intervalstats':intervalstats,
                   'nrintervals':nrintervals,
                   'interactiveplot':script,
                   'the_div':div,
                   'intervalstring':s,
                   'savebutton':savebutton,
                   'formvalues':formvalues,
                   })

class VideoDelete(DeleteView):
    login_required = True
    model = VideoAnalysis
    template_name = 'video_delete_confirm.html'

    # extra parameters
    def get_context_data(self, **kwargs):
        context = super(VideoDelete, self).get_context_data(**kwargs)

        breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(
                    self.request,
                    encoder.encode_hex(self.object.workout.id)),
                'name': self.object.workout.name
                },
            {
                'url':reverse('workout_video_view',kwargs={'id':encoder.encode_hex(self.object.id)}),
                'name': 'Video Analysis'
                },
            { 'url':reverse('video_delete',kwargs={'pk':str(self.object.pk)}),
              'name': 'Delete'
              }

            ]

        context['active'] = 'nav-workouts'
        context['rower'] = getrower(self.request.user)
        context['breadcrumbs'] = breadcrumbs

        return context


    def get_success_url(self):
        w = self.object.workout
        try:
            w = Workout.objects.get(id=w.id)
        except Workout.DoesNotExist:
            return reverse('workouts_view')

        return reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)})

    def get_object(self, *args, **kwargs):
        obj = super(VideoDelete, self).get_object(*args, **kwargs)
        if not is_coach_user(self.request.user,obj.workout.user):
            raise PermissionDenied('You are not allowed to delete this analysis')

        return obj

class GraphDelete(DeleteView):
    login_required = True
    model = GraphImage
    template_name = 'graphimage_delete_confirm.html'

    # extra parameters
    def get_context_data(self, **kwargs):
        context = super(GraphDelete, self).get_context_data(**kwargs)

        breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(
                    self.request,
                    encoder.encode_hex(self.object.workout.id)),
                'name': self.object.workout.name
                },
            {
                'url':reverse('graph_show_view',kwargs={'id':self.object.pk}),
                'name': 'Chart'
                },
            { 'url':reverse('graph_delete',kwargs={'pk':str(self.object.pk)}),
              'name': 'Delete'
              }

            ]

        context['active'] = 'nav-workouts'
        context['rower'] = getrower(self.request.user)
        context['breadcrumbs'] = breadcrumbs

        return context


    def get_success_url(self):
        w = self.object.workout
        try:
            w = Workout.objects.get(id=w.id)
        except Workout.DoesNotExist:
            return reverse('workouts_view')

        return reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)})

    def get_object(self, *args, **kwargs):
        obj = super(GraphDelete, self).get_object(*args, **kwargs)

        if not is_workout_user(self.request.user,obj.workout):
            raise PermissionDenied('You are not allowed to delete this chart')

        return obj

def workout_code_delete_view(request,id=0):
    pk = encoder.decode_hex(id)

    try:
        w = Workout.objects.get(pk=pk)
        url = reverse('workout_delete',kwargs={'pk':pk})
    except Workout.DoesNotExist:
        url = reverse('workout_delete',kwargs={'pk':id})

    return HttpResponseRedirect(url)

class WorkoutDelete(PermissionRequiredMixin,DeleteView):
    login_required = True
    model = Workout
    template_name = 'workout_delete_confirm.html'
    permission_required = 'workout.change_workout'

    # extra parameters
    def get_context_data(self, **kwargs):
        context = super(WorkoutDelete, self).get_context_data(**kwargs)

        breadcrumbs = [
            {
                'url':'/rowers/list-workouts/',
                'name':'Workouts'
                },
            {
                'url':get_workout_default_page(self.request,encoder.encode_hex(self.object.id)),
                'name': encoder.encode_hex(self.object.id)
                },
            { 'url':reverse('workout_delete',kwargs={'pk':str(self.object.pk)}),
              'name': 'Delete'
              }

            ]

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

        context['active'] = 'nav-workouts'
        context['rower'] = getrower(self.request.user)
        context['breadcrumbs'] = breadcrumbs
        context['workout'] = self.object
        context['mayedit'] = mayedit
        context['promember'] = promember

        return context


    def get_success_url(self):
        return reverse('workouts_view')

    def get_object(self, *args, **kwargs):
        workout_pk = self.kwargs['pk']
        try:
            obj = Workout.objects.get(pk=workout_pk)
        except (ValueError,Workout.DoesNotExist):
            workout_pk = encoder.decode_hex(workout_pk)
            try:
                obj = Workout.objects.get(pk=workout_pk)
            except Workout.DoesNotExist:
                raise Http404("One of the workouts doesn't exist")
                #        obj = super(WorkoutDelete, self).get_object(*args, **kwargs)


        return obj
