from __future__ import unicode_literals

from django.db import models
from django.contrib.auth.models import User
from django import forms
from django.forms import ModelForm
from django.dispatch import receiver
from django.forms.widgets import SplitDateTimeWidget
from django.forms.formsets import BaseFormSet
from datetimewidget.widgets import DateTimeWidget
from django.core.validators import validate_email
import os
import twitter
import re

from django.conf import settings
from sqlalchemy import create_engine
import sqlalchemy as sa
from sqlite3 import OperationalError
from django.utils import timezone
import datetime
from django.core.exceptions import ValidationError
from rowers.rows import validate_file_extension

import types

from rowsandall_app.settings import (
    TWEET_ACCESS_TOKEN_KEY,
    TWEET_ACCESS_TOKEN_SECRET,
    TWEET_CONSUMER_KEY,
    TWEET_CONSUMER_SECRET,
    )

tweetapi = twitter.Api(consumer_key=TWEET_CONSUMER_KEY,
                       consumer_secret=TWEET_CONSUMER_SECRET,
                       access_token_key=TWEET_ACCESS_TOKEN_KEY,
                       access_token_secret=TWEET_ACCESS_TOKEN_SECRET)

user = settings.DATABASES['default']['USER']
password = settings.DATABASES['default']['PASSWORD']
database_name = settings.DATABASES['default']['NAME']
host = settings.DATABASES['default']['HOST']
port = settings.DATABASES['default']['PORT']

database_url = 'mysql://{user}:{password}@{host}:{port}/{database_name}'.format(
    user=user,
    password=password,
    database_name=database_name,
    host=host,
    port=port,
    )

if settings.DEBUG or user=='':	    
    database_url = 'sqlite:///db.sqlite3'

class UserFullnameChoiceField(forms.ModelChoiceField):
    def label_from_instance(self,obj):
        return obj.get_full_name()
    
# model for Power Zone names
class PowerZonesField(models.TextField):
#    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        self.token = kwargs.pop('token',',')
        super(PowerZonesField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        if not value: return
        if isinstance(value, list):
            return value
        # remove double quotes and brackets
        value = re.sub(r'u\"','',value)
        value = re.sub(r'u\'','',value)
        value = re.sub(r'\\','',value)
        value = re.sub(r'\"','',value)
        value = re.sub(r'\'','',value)
        value = re.sub(r'\[','',value)
        value = re.sub(r'\]','',value)
        value = re.sub(r'\[\[','[',value)
        value = re.sub(r'\]\]',']',value)
        value = re.sub(r'\ \ ',' ',value)
        value = re.sub(r', ',',',value)
        
        return value.split(self.token)

    def from_db_value(self,value, expression, connection, context):
        if value is None:
            return value
        if isinstance(value, list):
            return value
        return value.split(self.token)
    
    def get_db_prep_value(self, value, connection, prepared=False):
        if not value: return
        assert(isinstance(value, list) or isinstance(value, tuple))
        return self.token.join([unicode(s) for s in value])

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_deb_prep_value(value)

# For future Team functionality
class Team(models.Model):
    choices = (
        ('private','private'),
        ('open','open'),
        )

    viewchoices = (
        ('coachonly','Coach Only'),
        ('allmembers','All Members')
        )
    
    name = models.CharField(max_length=150,unique=True,verbose_name='Team Name')
    notes = models.CharField(blank=True,max_length=200,verbose_name='Team Purpose')
    manager = models.ForeignKey(User)
    private = models.CharField(max_length=30,choices=choices,default='open',
                               verbose_name='Team Type')

    viewing = models.CharField(max_length=30,choices=viewchoices,default='allmembers',verbose_name='Sharing Behavior')

    def __unicode__(self):
        return self.name

class TeamForm(ModelForm):
    class Meta:
        model = Team
        fields = ['name','notes','private','viewing']
	widgets = {
	    'notes': forms.Textarea,
	    }

class TeamInvite(models.Model):
    team = models.ForeignKey(Team)
    user = models.ForeignKey(User,null=True)
    issuedate = models.DateField(default=timezone.now)
    code = models.CharField(max_length=150,unique=True)
    email = models.CharField(max_length=150,null=True,blank=True)

class TeamInviteForm(ModelForm):
    user = UserFullnameChoiceField(queryset=User.objects.all(),required=False)
    class Meta:
        model = TeamInvite
        fields = ['user','email']

class TeamRequest(models.Model):
    team = models.ForeignKey(Team)
    user = models.ForeignKey(User,null=True)
    issuedate = models.DateField(default=timezone.now)
    code = models.CharField(max_length=150,unique=True)

    
# Extension of User with rowing specific data
class Rower(models.Model):
    weightcategories = (
	('hwt','heavy-weight'),
	('lwt','light-weight'),
	)
    user = models.OneToOneField(User)

    # Heart Rate Zone data
    max = models.IntegerField(default=192,verbose_name="Max Heart Rate")
    rest = models.IntegerField(default=48,verbose_name="Resting Heart Rate")
    ut2 = models.IntegerField(default=105,verbose_name="UT2 band lower HR")
    ut1 = models.IntegerField(default=146,verbose_name="UT1 band lower HR")
    at = models.IntegerField(default=160,verbose_name="AT band lower HR")
    tr = models.IntegerField(default=167,verbose_name="TR band lower HR")
    an = models.IntegerField(default=180,verbose_name="AN band lower HR")

    # Weight Category (for sync to C2)
    weightcategory = models.CharField(default="hwt",
				      max_length=30,
				      choices=weightcategories)

    # Power Zone Data
    ftp = models.IntegerField(default=226,verbose_name="Functional Threshold Power")

    p0 = models.FloatField(default=1.0,verbose_name="CP p1")
    p1 = models.FloatField(default=1.0,verbose_name="CP p2")
    p2 = models.FloatField(default=1.0,verbose_name="CP p3")
    p3 = models.FloatField(default=1.0,verbose_name="CP p4")
    cpratio = models.FloatField(default=1.0,verbose_name="CP fit ratio")
    
    otwslack = models.IntegerField(default=0,verbose_name="OTW Power slack")

    pw_ut2 = models.IntegerField(default=124,verbose_name="UT2 Power")
    pw_ut1 = models.IntegerField(default=171,verbose_name="UT1 Power")
    pw_at = models.IntegerField(default=203,verbose_name="AT Power")
    pw_tr = models.IntegerField(default=237,verbose_name="TR Power")
    pw_an = models.IntegerField(default=273,verbose_name="AN Power")
    
    powerzones = PowerZonesField(default=['Rest',
                                          'Pwr UT2',
                                          'Pwr UT1',
                                          'Pwr AT',
                                          'Pwr TR',
                                          'Pwr AN'])
    
    # Access tokens
    c2token = models.CharField(default='',max_length=200,blank=True,null=True)
    tokenexpirydate = models.DateTimeField(blank=True,null=True)
    c2refreshtoken = models.CharField(default='',max_length=200,blank=True,null=True)
    sporttrackstoken = models.CharField(default='',max_length=200,blank=True,null=True)
    sporttrackstokenexpirydate = models.DateTimeField(blank=True,null=True)
    sporttracksrefreshtoken = models.CharField(default='',max_length=200,
					       blank=True,null=True)
    underarmourtoken = models.CharField(default='',max_length=200,blank=True,null=True)
    underarmourtokenexpirydate = models.DateTimeField(blank=True,null=True)
    underarmourrefreshtoken = models.CharField(default='',max_length=200,
					       blank=True,null=True)
    tptoken = models.CharField(default='',max_length=1000,blank=True,null=True)
    tptokenexpirydate = models.DateTimeField(blank=True,null=True)
    tprefreshtoken = models.CharField(default='',max_length=1000,
					       blank=True,null=True)

    stravatoken = models.CharField(default='',max_length=200,blank=True,null=True)

    runkeepertoken = models.CharField(default='',max_length=200,
                                      blank=True,null=True)

#    runkeepertokenexpirydate = models.DateTimeField(blank=True,null=True)
#    runkeeperrefreshtoken = models.CharField(default='',max_length=200,
#                                             blank=True,null=True)
    
    # Plan
    plans = (
	('basic','basic'),
	('pro','pro'),
	('coach','coach')
	)

    privacychoices = (
        ('visible','Visible'),
        ('hidden','Hidden'),
        )

    getemailnotifications = models.BooleanField(default=False,
                                                verbose_name='Receive email notifications')

    rowerplan = models.CharField(default='basic',max_length=30,
				 choices=plans)

    planexpires = models.DateField(default=timezone.now)
    teamplanexpires = models.DateField(default=timezone.now)
    clubsize = models.IntegerField(default=0)
    
    
    # Friends/Team
    friends = models.ManyToManyField("self",blank=True)
    privacy  = models.CharField(default='visible',max_length=30,
                                choices=privacychoices)

    team = models.ManyToManyField(Team,blank=True)

    def __str__(self):
	return self.user.username

    def clean_email(self):
        return self.user.email.lower()

@receiver(models.signals.post_save,sender=Rower)
def auto_delete_teams_on_change(sender, instance, **kwargs):
    if instance.rowerplan != 'coach':
        teams = Team.objects.filter(manager=instance.user)
        for team in teams:
            team.delete()

from rowers.metrics import axlabels
favchartlabelsx = axlabels.copy()
favchartlabelsy1 = axlabels.copy()
favchartlabelsy2 = axlabels.copy()
favchartlabelsy1.pop('None')
parchoicesy1 = list(sorted(favchartlabelsy1.items(), key = lambda x:x[1]))
parchoicesy2 = list(sorted(favchartlabelsy2.items(), key = lambda x:x[1]))
parchoicesx = list(sorted(favchartlabelsx.items(), key = lambda x:x[1]))
            
# Saving a chart as a favorite chart
class FavoriteChart(models.Model):
    workouttypechoices = (
        ('ote','Erg/SkiErg'),
        ('otw','On The Water'),
        ('both','both')
        )
    
    plottypes = (
        ('line','Line Chart'),
        ('scatter','Scatter Chart')
        )
    
    yparam1 = models.CharField(max_length=50,choices=parchoicesy1,verbose_name='Y1')
    yparam2 = models.CharField(max_length=50,choices=parchoicesy2,verbose_name='Y2',default='None',blank=True)
    xparam = models.CharField(max_length=50,choices=parchoicesx,verbose_name='X')
    plottype = models.CharField(max_length=50,choices=plottypes,
                                default='line',
                                verbose_name='Chart Type')
    workouttype = models.CharField(max_length=50,choices=workouttypechoices,
                                   default='both',
                                   verbose_name='Workout Type')
    reststrokes = models.BooleanField(default=True,verbose_name="Incl. Rest")
    user = models.ForeignKey(Rower)
    

class FavoriteForm(ModelForm):
    class Meta:
        model = FavoriteChart
        fields = ['xparam','yparam1','yparam2',
                  'plottype','workouttype','reststrokes']

# To generate favorite chart forms on the fly
class BaseFavoriteFormSet(BaseFormSet):
    def clean(self):
        if any(self.errors):
            return

        for form in self.forms:
            if form.cleaned_data:
                xparam = form.cleaned_data['xparam']
                yparam1 = form.cleaned_data['yparam1']
                yparam2 = form.cleaned_data['yparam2']
                plottype = form.cleaned_data['plottype']
                reststrokes = form.cleaned_data['reststrokes']
                
            if not xparam:
                raise forms.ValidationError(
                    'Must have x parameter.',
                    code='missing_xparam'
                    )

            if not yparam1:
                raise forms.ValidationError(
                    'Must have Y1 parameter.',
                    code='missing_yparam1'
                    )

            if not yparam2:
                yparam2 = 'None'

# Check if workout is owned by this user
def checkworkoutuser(user,workout):
    try:
	r = Rower.objects.get(user=user)
        teams = workout.team.all()
        if workout.user == r:
            return True
        elif teams:
            for team in teams:
                if user == team.manager:
                    return True
        else:
            return False
    except Rower.DoesNotExist:
	return False

                
# Workout
class Workout(models.Model):
    workouttypes = types.workouttypes
    workoutsources = types.workoutsources
    boattypes = types.boattypes
    privacychoices = types.privacychoices
    
    user = models.ForeignKey(Rower)
    team = models.ManyToManyField(Team,blank=True)
    name = models.CharField(max_length=150)
    date = models.DateField()
    workouttype = models.CharField(choices=workouttypes,max_length=50)
    workoutsource = models.CharField(choices=workoutsources,max_length=100,
                                     default='unknown')
    boattype = models.CharField(choices=boattypes,max_length=50,
				default='1x',
				verbose_name = 'Boat Type')
    starttime = models.TimeField(blank=True,null=True)
    startdatetime = models.DateTimeField(blank=True,null=True)
    distance = models.IntegerField(default=0,blank=True)
    duration = models.TimeField(default=1,blank=True)
    weightcategory = models.CharField(default="hwt",max_length=10)
    weightvalue = models.FloatField(default=80.0,blank=True,verbose_name = 'Average Crew Weight (kg)')
    csvfilename = models.CharField(blank=True,max_length=150)
    uploadedtoc2 = models.IntegerField(default=0)
    averagehr = models.IntegerField(blank=True,null=True)
    maxhr = models.IntegerField(blank=True,null=True)
    uploadedtostrava = models.IntegerField(default=0)
    uploadedtosporttracks = models.IntegerField(default=0)
    uploadedtounderarmour = models.IntegerField(default=0)
    uploadedtotp = models.IntegerField(default=0)
    uploadedtorunkeeper = models.IntegerField(default=0)
    
    # empower stuff
    inboard = models.FloatField(default=0.88)
    oarlength = models.FloatField(default=2.89)
    
    
    notes = models.CharField(blank=True,null=True,max_length=1000)
    summary = models.TextField(blank=True)
    privacy = models.CharField(default='visible',max_length=30,
                               choices=privacychoices)
    rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece')
    
    def __unicode__(self):

	date = self.date
	name = self.name
        distance = str(self.distance)
        ownerfirst = self.user.user.first_name
        ownerlast = self.user.user.last_name
        duration = self.duration
        boattype = self.boattype
        workouttype = self.workouttype

        if workouttype != 'water':
            stri = u'{d} {n} {dist}m {duration:%H:%M:%S} {workouttype} {ownerfirst} {ownerlast}'.format(
                d = date.strftime('%Y-%m-%d'),
                n = name,
                dist = distance,
                duration = duration,
                workouttype = workouttype,
                ownerfirst = ownerfirst,
                ownerlast = ownerlast,
            )
        else:
            stri = u'{d} {n} {dist}m {duration:%H:%M:%S} {workouttype} {boattype} {ownerfirst} {ownerlast}'.format(
                d = date.strftime('%Y-%m-%d'),
                n = name,
                dist = distance,
                duration = duration,
                workouttype = workouttype,
                boattype=boattype,
                ownerfirst = ownerfirst,
                ownerlast = ownerlast,
            )
            
	return stri

# delete files belonging to workout instance
# related GraphImage objects should be deleted automatically
@receiver(models.signals.post_delete,sender=Workout)
def auto_delete_file_on_delete(sender, instance, **kwargs):
    # delete CSV file
    if instance.csvfilename:
	if os.path.isfile(instance.csvfilename):
	    os.remove(instance.csvfilename)
    if instance.csvfilename+'.gz':
	if os.path.isfile(instance.csvfilename+'.gz'):
	    os.remove(instance.csvfilename+'.gz')
            
# Delete stroke data from the database when a workout is deleted
@receiver(models.signals.post_delete,sender=Workout)
def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
    if instance.id:
        query = sa.text('DELETE FROM strokedata WHERE workoutid={id};'.format(
            id=instance.id,
            ))
        engine = create_engine(database_url, echo=False)
        with engine.connect() as conn, conn.begin():
            try:
                result = conn.execute(query)
            except:
                print "Database Locked"
        conn.close()
        engine.dispose()

# Model of StrokeData table
# the definition here is used only to enable easy Django migration
# when the StrokeData are expanded.
# No Django Instances of this model are managed. Strokedata table is
# accesssed directly with SQL commands
class StrokeData(models.Model):
    class Meta:
        db_table = 'strokedata'
        index_together = ['workoutid']

    workoutid = models.IntegerField(null=True)
    time = models.FloatField(null=True,verbose_name='Time')
    hr = models.IntegerField(null=True,verbose_name='Heart Rate')
    pace = models.FloatField(null=True,verbose_name='Pace')
    workoutstate = models.IntegerField(null=True,default=1)
    spm = models.FloatField(null=True,verbose_name='Stroke Rate')
    cumdist = models.FloatField(null=True,verbose_name='Cumulative Distance')
    ftime = models.CharField(max_length=30)
    fpace = models.CharField(max_length=30)
    driveenergy = models.FloatField(null=True,verbose_name='Work per Stroke')
    power = models.FloatField(null=True,verbose_name='Power')
    averageforce = models.FloatField(null=True,verbose_name='Average Force')
    drivelength = models.FloatField(null=True,verbose_name='Drive Length')
    peakforce = models.FloatField(null=True,verbose_name='Peak Force')
    forceratio = models.FloatField(null=True,verbose_name='Average/Peak Force Ratio')
    distance = models.FloatField(null=True,verbose_name='Distance')
    drivespeed = models.FloatField(null=True,verbose_name='Drive Speed')
    hr_ut2 = models.IntegerField(null=True)
    hr_ut1 = models.IntegerField(null=True)
    hr_at = models.IntegerField(null=True)
    hr_tr = models.IntegerField(null=True)
    hr_an = models.IntegerField(null=True)
    hr_max = models.IntegerField(null=True)
    hr_bottom = models.IntegerField(null=True)
    x_right = models.FloatField(null=True)
    ergpace = models.FloatField(null=True)
    nowindpace = models.FloatField(null=True)
    equivergpower = models.FloatField(null=True)
    fergpace = models.CharField(max_length=30)
    fnowindpace = models.CharField(max_length=30)
    catch = models.FloatField(default=0,null=True,verbose_name='Catch Angle')
    slip = models.FloatField(default=0,null=True,verbose_name='Slip')
    finish = models.FloatField(default=0,null=True,verbose_name='Finish Angle')
    wash = models.FloatField(default=0,null=True,verbose_name='Wash')
    peakforceangle = models.FloatField(default=0,null=True,verbose_name='Peak Force Angle')
    rhythm = models.FloatField(default=1.0,null=True,verbose_name='Rhythm')
    totalangle = models.FloatField(default=0.0,null=True,verbose_name='Total Stroke Length (deg)')
    effectiveangle = models.FloatField(default=0.0,null=True,verbose_name='Effective Stroke Length (deg)')
    efficiency = models.FloatField(default=-1,null=True,verbose_name='OTW Efficiency')
    
# A wrapper around the png files
class GraphImage(models.Model):
    filename = models.CharField(default='',max_length=150,blank=True,null=True)
    creationdatetime = models.DateTimeField()
    workout = models.ForeignKey(Workout)

    def __str__(self):
	return self.filename

# delete related file object when image is deleted
@receiver(models.signals.post_delete,sender=GraphImage)
def auto_delete_image_on_delete(sender,instance, **kwargs):
    if instance.filename:
	if os.path.isfile(instance.filename):
	    os.remove(instance.filename)
	else:
	    print "couldn't find the file "+instance.filename

# Date input utility
class DateInput(forms.DateInput):
    input_type = 'date'

# Form to update Workout data
class WorkoutForm(ModelForm):
    duration = forms.TimeInput(format='%H:%M:%S.%f')
    class Meta:
	model = Workout
	fields = ['name','date','starttime','duration','distance','workouttype','notes','privacy','rankingpiece','boattype']
	widgets = {
	    'date': DateInput(),
	    'notes': forms.Textarea,
	    'duration': forms.TimeInput(format='%H:%M:%S.%f'),
	    }
        
    def __init__(self, *args, **kwargs):
        super(WorkoutForm, self).__init__(*args, **kwargs)
        # this line to be removed
        del self.fields['privacy']
                    
        if self.instance.workouttype != 'water':
            del self.fields['boattype']
            
# Used for the rowing physics calculations
class AdvancedWorkoutForm(ModelForm):
    class Meta:
	model = Workout
	fields = ['boattype','weightvalue']

# Simple form to set rower's Functional Threshold Power
class RowerPowerForm(ModelForm):
    class Meta:
	model = Rower
	fields = ['ftp','otwslack']

# Form to set rower's Power zones, including test routines
# to enable consistency
class RowerPowerZonesForm(ModelForm):
        
    powerzones = ['UT3','UT2','UT1','AT','TR','AN']
    ut3name = forms.CharField(initial=powerzones[0])
    ut2name = forms.CharField(initial=powerzones[1])
    ut1name = forms.CharField(initial=powerzones[2])
    atname = forms.CharField(initial=powerzones[3])
    trname = forms.CharField(initial=powerzones[4])
    anname = forms.CharField(initial=powerzones[5])
    
    def __init__(self, *args,**kwargs):
        super(RowerPowerZonesForm, self).__init__(*args, **kwargs)
        
        if 'instance' in kwargs:
            powerzones = kwargs['instance'].powerzones
        else:
            powerzones = ['UT3','UT2','UT1','AT','TR','AN']

        self.fields['ut3name'].initial = powerzones[0]
        self.fields['ut2name'].initial = powerzones[1]
        self.fields['ut1name'].initial = powerzones[2]
        self.fields['atname'].initial = powerzones[3]
        self.fields['trname'].initial = powerzones[4]
        self.fields['anname'].initial = powerzones[5]

    class Meta:
        model = Rower
        fields = ['pw_ut2','pw_ut1','pw_at','pw_tr','pw_an']

    def clean(self):
        cleaned_data = super(RowerPowerZonesForm, self).clean()

        try:
            pw_ut2 = cleaned_data['pw_ut2']
        except KeyError:
            raise ValidationError("Value cannot be empty")
        except:
            pw_ut2 = int(self.data['pw_ut2'])
        try:
            pw_ut1 = cleaned_data['pw_ut1']
        except KeyError:
            raise ValidationError("Value cannot be empty")
        except:
            pw_ut1 = int(self.data['pw_ut1'])
        try:
            pw_at = cleaned_data['pw_at']
        except KeyError:
            raise ValidationError("Value cannot be empty")
        except:
            pw_at = int(self.data['pw_at'])
        try:
            pw_tr = cleaned_data['pw_tr']
        except KeyError:
            raise ValidationError("Value cannot be empty")
        except:
            pw_tr = int(self.data['pw_tr'])
        try:
            pw_an = cleaned_data['pw_an']
        except KeyError:
            raise ValidationError("Value cannot be empty")
        except:
            pw_an = int(self.data['pw_an'])

        try:
            ut3name = cleaned_data['ut3name']
        except:
            ut2name = 'UT3'
            cleaned_data['ut3name'] = 'UT3'
        try:
            ut2name = cleaned_data['ut2name']
        except:
            ut2name = 'UT2'
            cleaned_data['ut2name'] = 'UT2'
        try:
            ut1name = cleaned_data['ut1name']
        except:
            ut1name = 'UT1'
            cleaned_data['ut1name'] = 'UT1'
        try:
            atname = cleaned_data['atname']
        except:
            atname = 'AT'
            cleaned_data['atname'] = 'AT'
        try:
            trname = cleaned_data['trname']
        except:
            trname = 'TR'
            cleaned_data['ut1name'] = 'TR'
        try:
            anname = cleaned_data['anname']
        except:
            anname = 'AN'
            cleaned_data['ut1name'] = 'AN'


        try:
            ut3name = cleaned_data['ut3name']
        except:
            ut2name = 'UT3'
            cleaned_data['ut3name'] = 'UT3'
        try:
            ut2name = cleaned_data['ut2name']
        except:
            ut2name = 'UT2'
            cleaned_data['ut2name'] = 'UT2'
        try:
            ut1name = cleaned_data['ut1name']
        except:
            ut1name = 'UT1'
            cleaned_data['ut1name'] = 'UT1'
        try:
            atname = cleaned_data['atname']
        except:
            atname = 'AT'
            cleaned_data['atname'] = 'AT'
        try:
            trname = cleaned_data['trname']
        except:
            trname = 'TR'
            cleaned_data['ut1name'] = 'TR'
        try:
            anname = cleaned_data['anname']
        except:
            anname = 'AN'
            cleaned_data['ut1name'] = 'AN'


        if pw_ut1 <= pw_ut2:
            e = "{ut1name} should be higher than {ut2name}".format(
                ut1name = ut1name,
                ut2name= ut2name,
                )
            raise forms.ValidationError(e)
        if pw_at <= pw_ut1:
            e = "{atname} should be higher than {ut1name}".format(
                atname = atname,
                ut1name= ut1name,
                )
            raise forms.ValidationError(e)
        if pw_tr <= pw_at:
            e = "{trname} should be higher than {atname}".format(
                atname = atname,
                trname= trname,
                )
            raise forms.ValidationError(e)
        if pw_an <= pw_tr:
            e = "{anname} should be higher than {trname}".format(
                anname = anname,
                trname= trname,
                )
            raise forms.ValidationError(e)

        return cleaned_data

# Form to set rower's Email and Weight category
class AccountRowerForm(ModelForm):
    class Meta:
        model = Rower
        fields = ['weightcategory','getemailnotifications']

class UserForm(ModelForm):
    class Meta:
        model = User
        fields = ['first_name','last_name','email']


    def clean(self):
        cleaned_data = super(UserForm, self).clean()

# Form to set rower's Heart Rate zones, including test routines
# to enable consistency
class RowerForm(ModelForm):
    class Meta:
	model = Rower
	fields = ['rest','ut2','ut1','at','tr','an','max']


    def clean_rest(self):
	rest = self.cleaned_data['rest']

	if rest<10:
	    self.data['rest']=10
	    raise forms.ValidationError("Resting heart rate should be higher than 10 bpm")
	

	if rest>250:
	    self.data['rest'] = 250
	    raise forms.ValidationError("Resting heart rate should be lower than 250 bpm")


	return rest

    def clean_ut2(self):
	ut2 = self.cleaned_data['ut2']

	if ut2<10:
	    raise forms.ValidationError("UT2 heart rate should be higher than 10 bpm")

	if ut2>250:
	    raise forms.ValidationError("UT2 heart rate should be lower than 250 bpm")

	return ut2

    def clean_ut1(self):
	ut1 = self.cleaned_data['ut1']

	if ut1<10:
	    raise forms.ValidationError("UT1 heart rate should be higher than 10 bpm")

	if ut1>250:
	    raise forms.ValidationError("Resting heart rate should be lower than 250 bpm")

	return ut1

    def clean_at(self):
	at = self.cleaned_data['at']

	if at<10:
	    raise forms.ValidationError("AT heart rate should be higher than 10 bpm")

	if at>250:
	    raise forms.ValidationError("AT heart rate should be lower than 250 bpm")

	return at

    def clean_tr(self):
	tr = self.cleaned_data['tr']

	if tr<10:
	    raise forms.ValidationError("TR heart rate should be higher than 10 bpm")

	if tr>250:
	    raise forms.ValidationError("TR heart rate should be lower than 250 bpm")

	return tr

    def clean_an(self):
	an = self.cleaned_data['an']

	if an<10:
	    raise forms.ValidationError("AN heart rate should be higher than 10 bpm")

	if an>250:
	    raise forms.ValidationError("AN heart rate should be lower than 250 bpm")

	return an

    def clean_max(self):
	max = self.cleaned_data['max']

	if max<10:
	    raise forms.ValidationError("Max heart rate should be higher than 10 bpm")

	if max>250:
	    raise forms.ValidationError("Max heart rate should be lower than 250 bpm")

	return max


    def clean(self):

	
	try:
	    rest = self.cleaned_data['rest']
	except:
	    rest = int(self.data['rest'])

	try:
	    ut2 = self.cleaned_data['ut2']
	except:
	    ut2 = self.data['ut2']

	try:
	    ut1 = self.cleaned_data['ut1']
	except:
	    ut1 = self.data['ut1']

	try:
	    at = self.cleaned_data['at']
	except:
	    at = self.data['at']

	try:
	    an = self.cleaned_data['an']
	except:
	    an = self.data['an']

	try:
	    tr = self.cleaned_data['tr']
	except:
	    tr = self.data['tr']

	try:
	    max = self.cleaned_data['max']
	except:
	    max = self.data['max']
	
	if rest>=ut2:
	    raise forms.ValidationError("Resting heart rate should be lower than UT2")
	if ut2>=ut1:
	    raise forms.ValidationError("UT2 should be lower than UT1")
	if ut2>=ut1:
	    raise forms.ValidationError("UT2 should be lower than UT1")
	if ut1>=at:
	    raise forms.ValidationError("UT1 should be lower than AT")
	if at>=tr:
	    raise forms.ValidationError("AT should be lower than TR")
	if tr>=an:
	    raise forms.ValidationError("TR should be lower than AN")
	if an>=max:
	    raise forms.ValidationError("AN should be lower than Max")

        
# An announcement that goes to the right of the workouts list
# optionally sends a tweet to our twitter account
class SiteAnnouncement(models.Model):
    created = models.DateField(default=timezone.now)
    announcement = models.TextField(max_length=140)
    expires = models.DateField(default=timezone.now)
    modified = models.DateField(default=timezone.now)
    dotweet = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        if not self.id:
            self.created = timezone.now()
            self.expires = timezone.now()+datetime.timedelta(days=10)
        self.modified = timezone.now()
        if self.dotweet:
            try:
                status = tweetapi.PostUpdate(self.announcement)
            except:
                try:
                    status = tweetapi.PostUpdate(self.announcement[:135])
                except:
                    pass
        return super(SiteAnnouncement,self).save(*args, **kwargs)

# A comment by a user on a training
class WorkoutComment(models.Model):
    comment = models.TextField(max_length=300)
    created = models.DateTimeField(default=timezone.now)
    read = models.BooleanField(default=False)
    notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications")
    user = models.ForeignKey(User)
    workout = models.ForeignKey(Workout)

    def __unicode__(self):
        return u'Comment to: {w} by {u1} {u2}'.format(
            w=self.workout,
            u1 = self.user.first_name,
            u2 = self.user.last_name,
            )
        
    
class WorkoutCommentForm(ModelForm):
    class Meta:
        model = WorkoutComment
        fields = ['comment','notification']
	widgets = {
	    'comment': forms.Textarea,
	    }
    
