from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# for actions related to uploads
from django.conf import settings
from django.utils import timezone,translation
from rowers.tasks import (
    handle_sendemail_unrecognized,handle_sendemailnewcomment,
    handle_sendemailnewresponse, handle_updatedps,
    handle_makeplot,handle_otwsetpower,handle_sendemailtcx,
    handle_sendemailcsv
    )

from rowers.models import GraphImage

from rowers.rower_rules import ispromember

from PIL import Image

import numpy as np
import yaml
import argparse
import yamllint
from subprocess import call
import re
import sys
import time

from verbalexpressions import VerEx

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

from rowers.mytypes import workouttypes,boattypes,otwtypes,workoutsources, workouttypes_ordered

try:
    from cStringIO import StringIO
except:
    from io import StringIO


from rowers.utils import (
    geo_distance,serialize_list,deserialize_list,uniqify,
    str2bool,range_to_color_hex,absolute,myqueue,NoTokenError
    )

def cleanbody(body):
    try:
        body = body.decode('utf-8')
    except AttributeError:
        pass

    regex = r".*---\n([\s\S]*?)\.\.\..*"
    matches = re.finditer(regex,body)

    for m in matches:

        if m != None:
            body = m.group(0)

    return body


sources = [s for s,name in workoutsources]

def matchsource(line):
    results = []
    for s in sources:
        testert = '^source.*(%s)' % s
        tester = re.compile(testert)

        if tester.match(line.lower()):
            return tester.match(line.lower()).group(1)

# currently only matches one chart
def matchchart(line):
    results = []
    testert =  '^((chart)|(plot))'
    tester2t = testert+'(.*)(dist)'
    tester3t = testert+'(.*)(time)'
    tester4t = testert+'(.*)(pie)'

    tester = re.compile(testert)
    tester2 = re.compile(tester2t)
    tester3 = re.compile(tester3t)
    tester4 = re.compile(tester4t)

    if tester.match(line.lower()):
        if tester2.match(line.lower()):
            return 'distanceplot'
        if tester3.match(line.lower()):
            return 'timeplot'
        if tester3.match(line.lower()):
            return 'pieplot'

def matchuser(line):
    testert = '^(user)'
    tester = re.compile(testert)
    if tester.match(line.lower()):
        words = line.split()
        return words[1]

    return None

def matchrace(line):
    testert = '^(race)'
    tester = re.compile(testert)
    if tester.match(line.lower()):
        words = line.split()
        try:
            return int(words[1])
        except:
            return None

    return None

def matchsync(line):
    results = []
    tester = '((sync)|(synchronization)|(export))'
    tester2 = tester+'(.*)((c2)|(concept2)|(logbook))'
    tester3 = tester+'(.*)((tp)|(trainingpeaks))'
    tester4 = tester+'(.*)(strava)'
    tester5 = tester+'(.*)((st)|(sporttracks))'
    tester6 = tester+'(.*)((rk)|(runkeeper))'
    tester7 = tester+'(.*)((mapmyfitness)|(underarmour)|(ua))'

    tester = re.compile(tester)

    if tester.match(line.lower()):
        testers = [
            ('upload_to_C2',re.compile(tester2)),
            ('upload_totp',re.compile(tester3)),
            ('upload_to_Strava',re.compile(tester4)),
            ('upload_to_SportTracks',re.compile(tester5)),
            ('upload_to_RunKeeper',re.compile(tester6)),
            ('upload_to_MapMyFitness',re.compile(tester7)),
        ]
        for t in testers:
            if t[1].match(line.lower()):
                results.append(t[0])

    return results

def getstravaid(uploadoptions,body):
    stravaid = 0
    tester = re.compile('^(stravaid)(.*?)(\d+)')
    for line in body.splitlines():
        if tester.match(line.lower()):
            stravaid =  tester.match(line.lower()).group(3)

    uploadoptions['stravaid'] = int(stravaid)

    return uploadoptions

def gettypeoptions_body2(uploadoptions,body):
    tester = re.compile('^(workout)')
    testerb = re.compile('^(boat)')
    for line in body.splitlines():
        if tester.match(line.lower()):
            for typ,verb in workouttypes_ordered.items():
                str1 = '^(workout)(.*)({a})'.format(
                    a = typ.lower()
                    )
                testert = re.compile(str1)
                if testert.match(line.lower()):
                    uploadoptions['workouttype'] = typ
                    break
        if testerb.match(line.lower()):
            for typ,verb in boattypes:
                str1 = '^(boat)(.*)({a})'.format(
                    a = typ.replace('+','\+')
                    )
                testert = re.compile(str1)
                if testert.match(line.lower()):
                    uploadoptions['boattype'] = typ
                    break

    return uploadoptions

def getprivateoptions_body2(uploadoptions,body):
    tester = re.compile('^(priva)')
    for line in body.splitlines():
        if tester.match(line.lower()):
            v = True
            negs = ['false','False','None','no']
            for neg in negs:
                tstr = re.compile('^(.*)'+neg)

                if tstr.match(line.lower()):
                    v = False

            uploadoptions['makeprivate'] = v

    return uploadoptions

def getworkoutsources(uploadoptions,body):
    for line in body.splitlines():
        workoutsource = matchsource(line)
        if workoutsource:
            uploadoptions['workoutsource'] = workoutsource

    return uploadoptions

def getplotoptions_body2(uploadoptions,body):
    for line in body.splitlines():
        chart = matchchart(line)
        if chart:
            uploadoptions['make_plot'] = True
            uploadoptions['plottype'] = chart

    return uploadoptions

def getuseroptions_body2(uploadoptions,body):
    for line in body.splitlines():
        user = matchuser(line)
        if user:
            uploadoptions['username'] = user

    return uploadoptions

def getraceoptions_body2(uploadoptions,body):
    for line in body.splitlines():
        raceid = matchrace(line)
        if raceid:
            uploadoptions['raceid'] = raceid

    return uploadoptions

def getsyncoptions_body2(uploadoptions,body):
    result = []
    for line in body.splitlines():
        result = result+matchsync(line)

    result = list(set(result))

    for r in result:
        uploadoptions[r] = True

    return uploadoptions

def getsyncoptions(uploadoptions,values):
    try:
        value = values.lower()
        values = [values]
    except AttributeError:
        pass

    for v in values:
        try:
            v = v.lower()

            if v in ['c2','concept2','logbook']:
                uploadoptions['upload_to_C2'] = True
            if v in ['tp','trainingpeaks']:
                uploadoptions['upload_totp'] = True
            if v in ['strava']:
                uploadoptions['upload_to_Strava'] = True
            if v in ['st','sporttracks']:
                uploadoptions['upload_to_SportTracks'] = True
            if v in ['rk','runkeeper']:
                uploadoptions['upload_to_RunKeeper'] = True
            if v in ['ua','underarmour','mapmyfitness']:
                uploadoptions['upload_to_MapMyFitness'] = True
        except AttributeError:
            pass

    return uploadoptions

def getplotoptions(uploadoptions,value):
    try:
        v = value.lower()
        if v in ['pieplot','timeplot','distanceplot']:
            uploadoptions['make_plot'] = True
            uploadoptions['plottype'] = v
        elif 'pie' in v:
            uploadoptions['make_plot'] = True
            uploadoptions['plottype'] = 'pieplot'
        elif 'distance' in v:
            uploadoptions['make_plot'] = True
            uploadoptions['plottype'] = 'distanceplot'
        elif 'time' in v:
            uploadoptions['make_plot'] = True
            uploadoptions['plottype'] = 'timeplot'
    except TypeError:
        pass

    return uploadoptions


def gettype(uploadoptions,value,key):
    workouttype = 'rower'
    for typ,verb in workouttypes_ordered.items():
        if value == typ:
            workouttype = typ
            break
        if value == verb:
            workouttype = typ
            break

    uploadoptions[key] = workouttype

    return uploadoptions

def getboattype(uploadoptions,value,key):
    boattype = '1x'
    for type,verb in boattypes:
        if value == type:
            boattype = type
        if value == verb:
            boattype = type

    uploadoptions[key] = boattype

    return uploadoptions

def getuser(uploadoptions,value,key):
    uploadoptions['username'] = value

    return uploadoptions

def getrace(uploadoptions,value,key):
    try:
        raceid = int(value)
        uploadoptions['raceid'] = raceid
    except:
        pass

    return uploadoptions

def getsource(uploadoptions,value,key):
    workoutsource = 'unknown'
    for type,verb in workoutsources:
        if value == type:
            workoutsource = type
        if value == verb:
            workoutsource = type

    uploadoptions[key] = workoutsource

    return uploadoptions

def getboolean(uploadoptions,value,key):
    b = True
    if not value:
        b = False
    if value in [False,'false','False',None,'no']:
        b = False

    uploadoptions[key] = b

    return uploadoptions

def upload_options(body):
    uploadoptions = {
        'boattype':'1x',
        'workouttype': 'rower',
    }
    body = cleanbody(body)
    try:
        yml = (yaml.safe_load(body))
        if yml and 'fromuploadform' in yml:
            return yml
        try:
            for key, value in yml.iteritems():
                lowkey = key.lower()
                if lowkey == 'sync' or lowkey == 'synchronization' or lowkey == 'export':
                    uploadoptions = getsyncoptions(uploadoptions,value)
                if lowkey == 'chart' or lowkey == 'static' or lowkey == 'plot':
                    uploadoptions = getplotoptions(uploadoptions,value)
                if 'priva' in lowkey:
                    uploadoptions = getboolean(uploadoptions,value,'makeprivate')
                if 'workout' in lowkey:
                    uploadoptions = gettype(uploadoptions,value,'workouttype')
                if 'boat' in lowkey:
                    uploadoptions = getboattype(uploadoptions,value,'boattype')
                if 'source' in lowkey:
                    uploadoptions = getsource(uploadoptions,value,'workoutsource')
                if 'username' in lowkey:
                    uploadoptions = getuser(uploadoptions,value,'username')
                if 'raceid' in lowkey:
                    uploadoptions = getraceid(uploadoptions,value,'raceid')
        except AttributeError:
            #pass
            raise yaml.YAMLError
    except yaml.YAMLError as exc:
        try:
            uploadoptions = getplotoptions_body2(uploadoptions,body)
            uploadoptions = getsyncoptions_body2(uploadoptions,body)
            uploadoptions = getprivateoptions_body2(uploadoptions,body)
            uploadoptions = gettypeoptions_body2(uploadoptions,body)
            uploadoptions = getstravaid(uploadoptions,body)
            uploadoptions = getworkoutsources(uploadoptions,body)
            uploadoptions = getuseroptions_body2(uploadoptions,body)
            uploadoptions = getraceoptions_body2(uploadoptions,body)
        except IOError:
            pm = exc.problem_mark
            strpm = str(pm)
            pbm = "Your email has an issue on line {} at position {}. The error is: ".format(
                pm.line+1,
                pm.column+1,
            )+strpm
            return {'error':pbm}

    if uploadoptions == {}:
        uploadoptions['message'] = 'No parsing issue. No valid commands detected'

    return uploadoptions

def make_plot(r,w,f1,f2,plottype,title,imagename='',plotnr=0):
    if imagename == '':
        imagename = f1[:-4]+'.png'
    fullpathimagename = 'static/plots/'+imagename

    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 w.workouttype in otwtypes:
        ftp = ftp*(100.-r.otwslack)/100.

    hrpwrdata = {
        'hrmax':r.max,
        'hrut2':r.ut2,
        'hrut1':r.ut1,
        'hrat':r.at,
        'hrtr':r.tr,
        'hran':r.an,
        'ftp':ftp,
        'powerperc':serialize_list(powerperc),
        'powerzones':serialize_list(r.powerzones),
    }

    # make plot - asynchronous task
    plotnrs = {
        'timeplot':1,
        'distanceplot':2,
        'pieplot':3,
    }

    axis = r.staticgrids
    if axis == None:
        gridtrue = False
        axis = 'both'
    else:
        gridtrue = True

    if plotnr == 0:
        plotnr = plotnrs[plottype]

    if w.workouttype in otwtypes:
        plotnr = plotnr+3

    otwrange = [r.fastpaceotw.total_seconds(),r.slowpaceotw.total_seconds()]
    oterange = [r.fastpaceerg.total_seconds(),r.slowpaceerg.total_seconds()]


    job = myqueue(queuehigh,handle_makeplot,f1,f2,
                  title,hrpwrdata,
                  plotnr,imagename,gridtrue=gridtrue,axis=axis,
                  otwrange=otwrange,oterange=oterange)

    try:
        width,height = Image.open(fullpathimagename).size
    except:
        width = 1200
        height = 600

    imgs = GraphImage.objects.filter(workout=w)
    if len(imgs) < 7:
        i = GraphImage(workout=w,
                       creationdatetime=timezone.now(),
                       filename=fullpathimagename,
                       width=width,height=height)

        i.save()
    else:
        return 0,'You have reached the maximum number of static images for this workout. Delete an image first'

    return i.id,job.id

import rowers.c2stuff as c2stuff
import rowers.stravastuff as stravastuff
import rowers.sporttracksstuff as sporttracksstuff
import rowers.runkeeperstuff as runkeeperstuff
import rowers.underarmourstuff as underarmourstuff
import rowers.tpstuff as tpstuff

from rowers.rower_rules import is_promember

def set_workouttype(w,options):
    try:
        w.workouttype = options['workouttype']
        w.save()
    except KeyError:
        pass
    try:
        w.boattype = options['boattype']
        w.save()
    except KeyError:
        pass

    return 1

def set_workoutsource(w,options):
    try:
        w.workoutsource = options['workoutsource']
        w.save()
    except KeyError:
        pass

def make_private(w,options):
    if 'makeprivate' in options and options['makeprivate']:
        w.privacy = 'hidden'
        w.save()

        return 1

def do_sync(w,options, quick=False):
    try:
        upload_to_strava = options['upload_to_Strava']
    except KeyError:
        upload_to_strava = False

    try:
        if options['stravaid'] != 0 and options['stravaid'] != '':
            w.uploadedtostrava = options['stravaid']
            upload_to_strava = False
            w.save()
    except KeyError:
        pass


    if ('upload_to_C2' in options and options['upload_to_C2']) or (w.user.c2_auto_export and ispromember(w.user.user)):
        try:
            message,id = c2stuff.workout_c2_upload(w.user.user,w,asynchron=True)
        except NoTokenError:
            id = 0
            message = "Something went wrong with the Concept2 sync"
        except:
            pass

    if ('upload_to_Strava' in options and upload_to_strava) or (w.user.strava_auto_export and ispromember(w.user.user)):
        try:
            message,id = stravastuff.workout_strava_upload(
            w.user.user,w,quick=quick,asynchron=True,
            )
        except NoTokenError:
            id = 0
            message = "Please connect to Strava first"
        except:
            e = sys.exc_info()[0]
            t = time.localtime()
            timestamp = time.strftime('%b-%d-%Y_%H%M', t)
            with open('stravalog.log','a') as f:
                f.write('\n')
                f.write(timestamp)
                f.write(str(e))



    if ('upload_to_SportTracks' in options and options['upload_to_SportTracks']) or (w.user.sporttracks_auto_export and ispromember(w.user.user)):
        try:
            message,id = sporttracksstuff.workout_sporttracks_upload(
                w.user.user,w,asynchron=True,
            )
        except NoTokenError:
            message = "Please connect to SportTracks first"
            id = 0


    if ('upload_to_RunKeeper' in options and options['upload_to_RunKeeper']) or (w.user.runkeeper_auto_export and ispromember(w.user.user)):
        try:
            message,id = runkeeperstuff.workout_runkeeper_upload(
                w.user.user,w,asynchron=True,
            )
        except NoTokenError:
            message = "Please connect to Runkeeper first"
            id = 0

    if ('upload_to_MapMyFitness' in options and options['upload_to_MapMyFitness']) or (w.user.mapmyfitness_auto_export and ispromember(w.user.user)):
        try:
            message,id = underarmourstuff.workout_ua_upload(
                w.user.user,w
            )
        except NoTokenError:
            message = "Please connect to MapMyFitness first"
            id = 0


    if ('upload_to_TrainingPeaks' in options and options['upload_to_TrainingPeaks']) or (w.user.trainingpeaks_auto_export and ispromember(w.user.user)):
        try:
            message,id = tpstuff.workout_tp_upload(
                w.user.user,w
            )
        except NoTokenError:
            message = "Please connect to TrainingPeaks first"
            id = 0

    return 1
