from django.db import models
from datetime import datetime,date,time
from django.db.models import Q

from signals import *
from modules.notifications.models import *
from modules.core.functions import *

class Election(models.Model):

    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200)

    registration_introduction = models.TextField()
    voting_introduction = models.TextField()

    election_registration_starts = models.DateField(blank=True,null=True)
    election_registration_ends = models.DateField(blank=True,null=True)

    election_starts = models.DateField(blank=True,null=True,verbose_name='Election Voting Starts')
    election_ends = models.DateField(blank=True,null=True,verbose_name='Election Voting Ends')

    approval_deadline = models.DateField(blank=True,null=True)
    registration_message = models.TextField(blank=True,null=True,verbose_name='Message once a member has registered')
    confirmation_message = models.TextField(blank=True,null=True,verbose_name='Message once a member has voted')

    enabled = models.BooleanField(default=False)

    member_types_allowed_view = models.ManyToManyField('members.MemberType',related_name='member_types_allowed_view',blank=True,verbose_name='Member Types Allowed to View',help_text='Leave blank to allow non-members to View.')
    member_groups_allowed_view = models.ManyToManyField('members.MemberGroup',related_name='member_groups_allowed_view',blank=True,verbose_name='Member Groups Allowed to View')

    member_types_allowed_register = models.ManyToManyField('members.MemberType',related_name='member_types_allowed_register',blank=True,verbose_name='Member Types Allowed to Register',help_text='Leave blank to allow non-members to Register.')
    member_groups_allowed_register = models.ManyToManyField('members.MemberGroup',related_name='member_groups_allowed_register',blank=True,verbose_name='Member Groups Allowed to Register')

    member_types_allowed_vote = models.ManyToManyField('members.MemberType',related_name='member_types_allowed_vote',blank=True,verbose_name='Member Types Allowed to Vote',help_text='Leave blank to allow non-members to Vote.')
    member_groups_allowed_vote = models.ManyToManyField('members.MemberGroup',related_name='member_groups_allowed_vote',blank=True,verbose_name='Member Groups Allowed to Vote')

    show_dob  = models.BooleanField(verbose_name='Show Date of Birth Field',default=False)
    vote_for_self = models.BooleanField(verbose_name='Allow Members to Vote for themselves',default=False)

    def __unicode__(self):
        return self.name

    def get_positions(self):

        positions = ElectionPosition.objects.filter(election=self).order_by('order')
        return positions

    def get_positions_registration_member(self,member):

        positions = ElectionPosition.objects.filter(Q(member_types_allowed_register__isnull=True) | Q(member_types_allowed_register=member.member_type),election=self).order_by('order')

        final_positions = []

        for position in positions:

            if position.member_groups_allowed_register.all():
                in_groups = False
                for group in position.member_groups_allowed_register.all():
                    if member in group.members.all():
                        in_groups = True
                if in_groups:
                    final_positions.append(position)

            else:
                final_positions.append(position)

        return final_positions

    def get_positions_voting_member(self,member):

        positions = ElectionPosition.objects.filter(Q(member_types_allowed_vote__isnull=True) | Q(member_types_allowed_vote=member.member_type),election=self).order_by('order')

        final_positions = []

        for position in positions:

            if position.member_groups_allowed_vote.all():
                in_groups = False
                for group in position.member_groups_allowed_vote.all():
                    if member in group.members.all():
                        in_groups = True
                if in_groups:
                    final_positions.append(position)

            else:
                final_positions.append(position)

        return final_positions


    def get_candidates(self):

        candidates = ElectionCandidate.objects.filter(election=self)
        return candidates

    def get_status(self):

        today = date.today()

        if self.election_registration_starts > today:
            return 'disabled'
        elif self.election_registration_starts <= today and self.election_registration_ends >= today:
            return 'registration'
        elif self.election_starts <= today and self.election_ends >= today:
            return 'voting'
        elif self.election_registration_ends < today and self.election_starts > today:
            return 'registration-complete'
        elif self.election_ends <= today:
            return 'complete'
        else :
            return 'disabled'


class ElectionPosition(models.Model):

    election = models.ForeignKey('Election')
    name = models.CharField(max_length=200)
    order = models.IntegerField()
    num_votes = models.IntegerField(verbose_name='Number of votes allowed for each voter')

    member_types_allowed_register = models.ManyToManyField('members.MemberType',related_name='position_member_types_allowed_register',blank=True,verbose_name='Member Types Allowed to Register for this Position')
    member_groups_allowed_register = models.ManyToManyField('members.MemberGroup',related_name='position_member_groups_allowed_register',blank=True,verbose_name='Member Groups Allowed to Register for this Position')

    member_types_allowed_vote = models.ManyToManyField('members.MemberType',related_name='position_member_types_allowed_vote',blank=True,verbose_name='Member Types Allowed to Vote for this Position')
    member_groups_allowed_vote = models.ManyToManyField('members.MemberGroup',related_name='position_member_groups_allowed_vote',blank=True,verbose_name='Member Groups Allowed to Vote for this Position')

    def __unicode__(self):
        return self.name

    def get_approved_candidates(self):
        candidates = ElectionCandidate.objects.filter(position=self,status='approved').order_by('-created')
        return candidates

    def get_vote_count(self):
        votes = ElectionVote.objects.filter(candidate__position=self)
        vote_count = votes.count()
        return vote_count


    class Meta:
        ordering = ["order"]


class ElectionCandidate(models.Model):

    STATUS_CHOICES = (
        (u'pending',u'Pending'),
        (u'approved',u'Approved'),
        (u'rejected',u'Rejected'),
    )

    member = models.ForeignKey('members.Member')
    election = models.ForeignKey('Election')
    position = models.ForeignKey('ElectionPosition')

    title = models.CharField(max_length=20)
    given_name = models.CharField(max_length=200)
    surname = models.CharField(max_length=200)
    email = models.EmailField()
    telephone = models.CharField(max_length=20,blank=True,null=True)
    qualifications = models.TextField(blank=True,null=True)
    current_post = models.CharField(max_length=200,blank=True,null=True)
    hospital = models.CharField(max_length=200,blank=True,null=True,verbose_name='Hospital or Clinic')
    date_of_birth = models.DateField(blank=True,null=True)

    picture = models.ImageField(upload_to='elections/candidates',blank=True,null=True)
    manifesto = models.TextField()

    sponsor_name_1 = models.CharField(max_length=200,blank=True,null=True)
    sponsor_email_1 = models.EmailField(max_length=200,blank=True,null=True)
    sponsor_confirmed_1 = models.BooleanField(default=False)
    sponsor_key_1 = models.CharField(max_length=200,blank=True,null=True)
    sponsor_time_1 = models.DateTimeField(blank=True,null=True)

    sponsor_name_2 = models.CharField(max_length=200,blank=True,null=True)
    sponsor_email_2 = models.EmailField(max_length=200,blank=True,null=True)
    sponsor_confirmed_2 = models.BooleanField(default=False)
    sponsor_key_2 = models.CharField(max_length=200,blank=True,null=True)
    sponsor_time_2 = models.DateTimeField(blank=True,null=True)

    created = models.DateTimeField(auto_now_add=True)

    status = models.CharField(max_length=200,choices=STATUS_CHOICES,default='pending')

    def __unicode__(self):
        return "%s %s" % (self.given_name,self.surname)

    def get_votes(self):
        votes = ElectionVote.objects.filter(candidate=self).order_by('created')
        return votes

    def get_vote_count(self):

        votes = self.get_votes()
        vote_count = votes.count()
        return vote_count

    def get_vote_percentage(self):

        vote_count = self.get_vote_count()
        total_votes = self.position.get_vote_count()

        if vote_count > 0 :
            percent = (float(vote_count) / float(total_votes)) * 100
            return percent
        else:
            return 0


class ElectionVote(models.Model):

    member = models.ForeignKey('members.Member')
    candidate = models.ForeignKey('ElectionCandidate')
    created = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return "%s for %s" % (self.member,self.candidate)

def election_registered_handler(sender,**kwargs):

    request = kwargs['request']
    election_candidate = kwargs['election_candidate']

    try:
        template = EmailTemplate.objects.get(key='election_registered_admin')

        message = template.content % (election_candidate.given_name,election_candidate.surname,election_candidate.member.user.email,election_candidate.election,election_candidate.position,request.META['HTTP_HOST'],reverse('admin_elections_election_candidates',args=[election_candidate.election.id]),request.META['HTTP_HOST'],reverse('admin_elections_election_candidates',args=[election_candidate.election.id]))
        subject = template.subject
        send_mail(template.key,subject,message,template.from_address.email_address,template.get_to_addresses())
    except Exception,e:
        raise e

    try:
        template = EmailTemplate.objects.get(key='election_referrer')

        if election_candidate.election.approval_deadline:
            approval_deadline = custom_strftime("{S} %B %Y",election_candidate.election.approval_deadline)
        else:
            approval_deadline = 'None'

        message = template.content % (approval_deadline,election_candidate.given_name,election_candidate.surname,'proposer',election_candidate.position,election_candidate.election,request.META['HTTP_HOST'],reverse('elections_election_registration_approve',args=[election_candidate.election.slug,election_candidate.sponsor_key_1]),approval_deadline)
        subject = template.subject
        send_mail(template.key,subject,message,template.from_address.email_address,election_candidate.sponsor_email_1)

        message = template.content % (approval_deadline,election_candidate.given_name,election_candidate.surname,'seconder',election_candidate.position,election_candidate.election,request.META['HTTP_HOST'],reverse('elections_election_registration_approve',args=[election_candidate.election.slug,election_candidate.sponsor_key_2]),approval_deadline)
        subject = template.subject
        send_mail(template.key,subject,message,template.from_address.email_address,election_candidate.sponsor_email_2)

    except Exception,e:
        raise e

election_registered.connect(election_registered_handler,dispatch_uid="election_registered")
