# Copyright (c) 2011-2013 Kunal Mehta. All rights reserved.
# Use of this source code is governed by a BSD License found in README.md.

from django.contrib.auth import authenticate, login
from django.contrib.auth.models import AbstractUser
from django.core.urlresolvers import reverse
from django.db import models

from huxley.accounts.constants import *
from huxley.core.models import *

import re

class HuxleyUser(AbstractUser):

    TYPE_ADVISOR = 1
    TYPE_CHAIR = 2
    USER_TYPE_CHOICES = ((TYPE_ADVISOR, 'Advisor'),
                         (TYPE_CHAIR, 'Chair'))

    user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES, default=TYPE_ADVISOR)
    school = models.OneToOneField(School, related_name='advisor', null=True)  # Advisors only.
    committee = models.ForeignKey(Committee, related_name='chair', null=True) # Chairs only.

    def is_advisor(self):
        return self.user_type == self.TYPE_ADVISOR

    def is_chair(self):
        return self.user_type == self.TYPE_CHAIR

    def default_path(self):
        if self.is_advisor():
            return reverse('advisors:welcome')
        elif self.is_chair():
            return reverse('chairs:attendance')

    @staticmethod
    def authenticate(username, password):
        '''Attempt to authenticate a user, given a username (or email) and
        password. Return a 2-tuple of (User) user, (str) error.'''
        if not (username and password):
            return None, AuthenticationErrors.MISSING_FIELDS

        user = authenticate(username=username, password=password)
        if user is None:
            try:
                u = HuxleyUser.objects.get(email=username)
                user = authenticate(username=u.username, password=password)
            except HuxleyUser.DoesNotExist:
                pass

        if user is None:
            return None, AuthenticationErrors.INVALID_LOGIN
        if not user.is_active:
            return None, AuthenticationErrors.INACTIVE_ACCOUNT

        return user, None

    @staticmethod
    def login(request, user):
        """ Logs in a user and returns a redirect url based on whether they're
        an advisor or chair. """
        login(request, user)
        return user.default_path()

    @classmethod
    def reset_password(cls, username):
        """ Reset and return a user's password, or return False if the user
        doesn't exist. """
        if not username:
            return False
        try:
            user = cls.objects.get(models.Q(username=username) |
                                   models.Q(email=username))
            new_password = cls.objects.make_random_password(length=10)
            user.set_password(new_password)
            user.save()    
            return new_password
        except cls.DoesNotExist:
            return False

    def change_password(self, old, new1, new2):
        """ Attempts to change the given user's password. Returns a 2-tuple
            of (bool) success, (str) error. """
        if not (old and new1 and new2):
            return False, ChangePasswordErrors.MISSING_FIELDS
        if new1 != new2:
            return False, ChangePasswordErrors.MISMATCHED_PASSWORDS
        if len(new1) < 6:
            return False, ChangePasswordErrors.PASSWORD_TOO_SHORT
        if not re.match("^[A-Za-z0-9\_\.!@#\$%\^&\*\(\)~\-=\+`\?]+$", new1):
            return False, ChangePasswordErrors.INVALID_CHARACTERS
        if not self.check_password(old):
            return False, ChangePasswordErrors.INCORRECT_PASSWORD
        
        self.set_password(new1)
        self.save();
        return True, None

    class Meta:
        db_table = 'huxley_user'
        verbose_name = 'user'

@@ -2070,16 +2070,14 @@
     
-%22%22%22 
+'''
 Log
-s
  in 
@@ -2093,17 +2093,16 @@
 d return
-s
  a redir
@@ -2162,20 +2162,19 @@
 r chair.
- %22%22%22
+'''
 %0A       
@@ -2295,20 +2295,19 @@
         
-%22%22%22 
+'''
 Reset an
@@ -2384,20 +2384,19 @@
 t exist.
- %22%22%22
+'''
 %0A       
@@ -2871,20 +2871,18 @@
     
-%22%22%22 
+'''
 Attempt
-s
  to 
@@ -2921,17 +2921,16 @@
 . Return
-s
  a 2-tup
@@ -2940,20 +2940,16 @@
         
- 
-   
 of (bool
@@ -2975,12 +2975,11 @@
 ror.
- %22%22%22
+'''
 %0A   

Update docstrings in huxley.accounts.models.