from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from django.contrib.sites.models import Site
from django.template import RequestContext, Context, loader
from django.core import validators
from django import forms
from django.utils.translation import ugettext_lazy as _
from models import *
from pycon.core import safe_utf8_encode, safe_ascii_encode, bind_meth_to_class

from django.contrib.auth.forms import AuthenticationForm

@bind_meth_to_class(AuthenticationForm)
def hasCookiesEnabled(self, field_data, all_data):
    if self.request and not self.request.session.test_cookie_worked():
        raise validators.ValidationError, _("Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in. "
                "There is currently a bug which can cause you to get this error incorrectly. "
                "The problem is due to bad processes on the server. "
                "If you have cookies enabled and see this error, please send e-mail to pycon@python.org "
                "and we will fix the problem.")

class NewUserAndProfileForm(UserProfile.AddManipulator):
    """
    Base class for creating users. Extend this to get a form that accepts
    username/password creation.
    """
    def __init__(self, request=None, **kwdargs):
        """
        If request is passed in, the manipulator will validate that cookies are
        enabled. Note that the request (a HttpRequest object) must have set a
        cookie with the key TEST_COOKIE_NAME and value TEST_COOKIE_VALUE before
        running this validator.

        Encoding is the string encoding to be used for the username and
        optional first and last names. This should match your Database.
        """
        #super(NewUserAndProfileForm, self).__init__(**kwdargs)
        UserProfile.AddManipulator.__init__(self, follow=None)
        self.request = request
        passwdind = None
        ind=0
        user_fields = [
            forms.TextField(field_name='username', length=30, maxlength=30,
                            is_required=True,
                validator_list=[validators.isAlphaNumeric,
                                self.isValidNewUsername,
                                self.hasCookiesEnabled]),
            forms.TextField(field_name='first_name', length=30, maxlength=30,
                            is_required=True),
            forms.TextField(field_name='last_name', length=30, maxlength=30,
                            is_required=True),
            forms.TextField(field_name='email', length=40, is_required=True,
                validator_list=[validators.isValidEmail]),
            forms.PasswordField(field_name="password", length=15, maxlength=30,
                                is_required=True),
            forms.PasswordField(field_name="password_confirm", length=15,
                                maxlength=30,
                                is_required=True,
                validator_list=[validators.AlwaysMatchesOtherField(
                    'password', "The two password fields didn't match.")]),
            forms.LargeTextField(field_name='bio'),
        ]
        uind = 0
        for ind, field in enumerate(self.fields):
            if field.field_name == 'user':
                uind = ind
            if field.field_name == 'middle':
                field.length=10
        self.fields[uind:uind+1] = user_fields

        self.user_cache = None
        self.profile_cache = None

    def isValidNewUsername(self, field_data, all_data):
        try:
            User.objects.get(username=field_data)
        except User.DoesNotExist:
            return
        raise validators.ValidationError, 'A user with that username already exists.'

    def hasCookiesEnabled(self, field_data, all_data):
        if self.request and not self.request.session.test_cookie_worked():
            raise validators.ValidationError, _(
                "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in. "
                "There is currently a bug which can cause you to get this error incorrectly. "
                "The problem is due to bad processes on the server. "
                "If you have cookies enabled and see this error, please send e-mail to pycon@python.org "
                "and we will fix the problem.")

    def save(self, new_data):
        "Creates the user and profile, and logs the user in."
        from sha import sha
        from datetime import datetime
        user = User.objects.create_user(new_data['username'], new_data['email'], new_data['password'])
        user.first_name = safe_utf8_encode(new_data['first_name'])
        user.last_name = safe_utf8_encode(new_data['last_name'])
        user.save()
        self.user_cache = authenticate(username=new_data['username'], password=new_data['password'])
        if not self.user_cache: self.user_cache = user
        new_data['user'] = user.id
        new_data['middle'] = safe_utf8_encode(new_data['middle'])
        self.profile_cache = super(NewUserAndProfileForm, self).save(new_data)
        self.profile_cache.user = user
        code = sha(datetime.now().ctime())
        code.update(safe_ascii_encode(self.profile_cache.long_name))
        code.update(safe_ascii_encode(user.email))
        haveMatch = True
        while haveMatch:
            codetext = code.hexdigest().upper()
            try:
                UserProfile.objects.get(code=codetext)
                code.update('collision')
            except UserProfile.DoesNotExist:
                haveMatch=False
        self.profile_cache.code = codetext
        self.profile_cache.save()
        user.is_active = False
        user.save()
        return self.profile_cache

    def get_user_id(self):
        if self.user_cache:
            return self.user_cache.id
        return None

    def get_profile_id(self):
        if self.user_cache:
            return self.profile_cache.id
        return None

    def get_user(self):
        return self.user_cache

    def get_profile(self):
        return self.profile_cache


class EditUserAndProfileForm(UserProfile.ChangeManipulator):
    def __init__(self, request, **kwdargs):
        profile = None
        self.request = request
        user = request.user
        try:
            profile = user.get_profile()
        except:
            profile = UserProfile()
            profile.user = user
            profile.save()

        UserProfile.ChangeManipulator.__init__(self, str(profile.id),
                                               follow={})
        self.user = user
        user_fields = [
            forms.TextField(field_name='username', length=30, maxlength=30, is_required=True,
                validator_list=[validators.isAlphaNumeric, self.isValidUsername]),
            forms.TextField(field_name='first_name', length=30, maxlength=30, is_required=True),
            forms.TextField(field_name='last_name', length=30, maxlength=30, is_required=True),
            forms.TextField(field_name='email', length=40, is_required=True,
                validator_list=[validators.isValidEmail]),
            forms.LargeTextField(field_name='bio'),
        ]
        uind = 0
        for ind, field in enumerate(self.fields):
            if field.field_name == 'user':
                uind = ind
            if field.field_name == 'middle':
                field.length=10
        self.fields[uind:uind+1] = user_fields

        self.profile_cache = None

    def isValidUsername(self, field_data, all_data):
        user = None
        try:
            user = User.objects.get(username=field_data)
        except User.DoesNotExist:
            return
        if user == self.user:
            return
        raise validators.ValidationError, 'A user with that username already exists.'

    def flatten_data(self):
        data = super(EditUserAndProfileForm, self).flatten_data()
        data['username'] = self.user.username
        data['first_name'] = self.user.first_name
        data['last_name'] = self.user.last_name
        data['email'] = self.user.email
        return data

    def save(self, new_data):
        self.user.username = new_data['username']
        self.user.first_name = safe_utf8_encode(new_data['first_name'])
        self.user.last_name = safe_utf8_encode(new_data['last_name'])
        self.user.email = safe_utf8_encode(new_data['email'])
        self.user.save()
        new_data['user'] = self.user.id
        new_data['middle'] = safe_utf8_encode(new_data['middle'])
        new_data['bio'] = safe_utf8_encode(new_data['bio'])
        self.profile_cache = super(EditUserAndProfileForm, self).save(new_data)
        return self.profile_cache


class ResetPasswordsForm(forms.Manipulator):
    "A form that lets a user request a password reset"
    def __init__(self, request):
        self.request = request
        self.fields = (
            forms.EmailField(field_name="email", length=40, is_required=True,
                validator_list=[self.isValidUserEmail]),
        )

    def isValidUserEmail(self, new_data, all_data):
        "Validates that a user exists with the given e-mail address"
        try:
            self.user_cache = list(User.objects.filter(email__iexact=new_data))
        except User.DoesNotExist:
            raise validators.ValidationError, "That e-mail address doesn't have an associated user acount. Are you sure you've registered?"
        if not self.user_cache:
            raise validators.ValidationError, "That e-mail address doesn't have an associated user acount. Are you sure you've registered?"

    def save(self, subject=settings.CONFERENCE_NAME + " Account Password Reset",
             email_template_name='email/reset_password.txt'):
        "Calculates a new password randomly and sends it to the user"
        from pycon.core.mail import send_mail
        for user in self.user_cache:
            new_pass = User.objects.make_random_password()
            user.set_password(new_pass)
            user.save()
            user.new_password = new_pass
        t = loader.get_template(email_template_name)
        c = {
            'mailto': safe_ascii_encode(self.user_cache[0]),
            'email': self.user_cache[0].email,
            'users': self.user_cache,
            'user': self.user_cache[0],
            'num_users': len(self.user_cache)
        }
        self.request.user = self.user_cache[0]
        message = t.render(RequestContext(self.request, c))
        send_mail(subject, message, settings.USERMGR_FROM_EMAIL,
                  [self.user_cache[0].email],
                  replyto_email=settings.USERMGR_REPLYTO_EMAIL)
