"""Attendee Registration Forma
"""
from django.conf import settings
from django.newforms import BaseForm, Form, ValidationError
from django.newforms import ChoiceField, DecimalField, CharField, EmailField
from django.newforms import Textarea, TextInput, Select, RadioSelect
from django.newforms import HiddenInput, BooleanField
from django.newforms import form_for_model, form_for_instance
from django.newforms.widgets import RadioFieldRenderer
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_unicode
from datetime import datetime
from decimal import Decimal
from models import *

## django has two conflicting ValidationError classes!!!
from django.newforms import ValidationError


PAYPAL_LOGIN   = getattr(settings, 'PAYPAL_LOGIN',   'testing')
PAYPAL_PARTNER = getattr(settings, 'PAYPAL_PARTNER', 'testing')
PAYPAL_URL     = getattr(settings, 'PAYPAL_URL',
                         'testing')

## RED_FLAG: must match data in admin on the number of sessions
reg_costs = ( ## EarlyBirdReg Feature is enabled
              { 'reg':  (('200.00', 'Early-Bird ($200)'),
                         ('100.00', 'Student Early-Bird ($100)'),
                         ( '50.00', 'Tutorial Only Pass ($50.00)')),
                'tut':  ('0.00', '100.00', '200.00', '300.00') },
              ## EarlyBirdReg Feature is disabled
              { 'reg':  (('200.00', 'Regular ($200)'),
                         ('100.00', 'Student ($100)'),
                         ( '50.00', 'Tutorial Only Pass ($50.00)')),
                'tut':  ('0.00', '100.00', '200.00', '300.00') },
              ## at door costs (how to integrate?)
              { 'reg':  (('200.00', 'Regular ($200)'),
                         ('100.00', 'Student ($100)'),
                         ( '50.00', 'Tutorial Only Pass ($50.00)')),
                'tut':  ('0.00', '100.00', '200.00', '300.00') },
            )

def donation_fields(field, **kwdargs):
    if field.name.startswith("donation"):
        return field.formfield(**kwdargs)
    return None

FakePayPalAckForm = form_for_model(PayPalAck, fields=PayPalAck.post_fields)
#EditRegForm = form_for_model(Registration, formfield_callback=edit_fields)
_DonationForm = form_for_model(Invoice, formfield_callback=donation_fields)

class DonationForm(_DonationForm):
    def __init__(self, user, *args, **kwdargs):
        self.user = user
        initial = {'donation_name': unicode(user) }
        initial.update(kwdargs.get('initial', dict()))
        kwdargs['initial'] = initial
        super(DonationForm, self).__init__(*args, **kwdargs)
        self.fields['donation'].min_value=Decimal("0.00")
        self.fields['donation'].max_value=Decimal("1000.00")
        self.fields['donation'].help_text=u""
    def clean_donation_name(self):
        if (self.cleaned_data['donation_name'] == u'' and
            self.cleaned_data['donation'] > Decimal("0.00")):
            raise ValidationError, (
            "The name under which the donation is being made must be given.")
        return self.cleaned_data['donation_name']

def EditRegForm(reg, *args, **kwdargs):
    return form_for_instance(
        reg, fields=Registration.changable)(*args, **kwdargs)

class RemovedRegEntryForm(Form):
    '''We need to keep track of removed entries to keep the data in
    later reg entries intact, and only loose the specific deleted entry.
    To do this, we replace the real entry with a hidden entry, keeping
    the prefix id unique.
    '''
    deleted = BooleanField(widget=HiddenInput, initial=True)

    def save(self, invoice=None):
        pass

class RadioFieldInlineRenderer(RadioFieldRenderer):
    def render(self):
        tags = ( (force_unicode(w), w.attrs['id']+u'-sel') for w in self )
        inner = u'\n'.join([u'<span class="inline-selection" id="%s">%s</span>'
                                % (id, t) for t, id in tags])
        return u'<div class="inline-select">' + inner + u'</div>'

class NewRegEntryForm(Form):
    sentinal    = BooleanField(widget=HiddenInput, initial=True)
    not_me      = BooleanField(
                    label="Check if this registration is for someone else:")
    name        = CharField(max_length="60",  help_text=_("(required)"))
    email       = EmailField(max_length="60", help_text=_("(required)"))
    reg_type    = ChoiceField(widget=RadioSelect(
                                renderer=RadioFieldInlineRenderer))
    badge_name  = CharField(max_length="60", required=False)
    badge_text1 = CharField(max_length="60", required=False)
    badge_text2 = CharField(max_length="60", required=False)
    shirt_size  = ChoiceField(choices=SHIRT_SIZES, initial='L',
                              widget=RadioSelect(
                                renderer=RadioFieldInlineRenderer))
    shirt_type  = ChoiceField(choices=SHIRT_TYPES, initial='M',
                              widget=RadioSelect(
                                renderer=RadioFieldInlineRenderer))
    vegan       = BooleanField()
    email_ok    = BooleanField(initial=True)
    listing_ok  = BooleanField(initial=True)
    extra_info  = CharField(required=False, widget=Textarea)


    def __init__(self, early_reg, user=None, *args, **kwdargs):
        self.user = user
        self.early_reg = early_reg
        if user is not None:
            initial = {}
            initial['name'] = unicode(user)[:60]
            initial['email'] = user.email
            initial.update(kwdargs.get('initial', dict()))
            kwdargs['initial'] = initial
        super(NewRegEntryForm, self).__init__(*args, **kwdargs)
        if user is None: self.fields.pop('not_me')
        mycosts = reg_costs[0 if early_reg else 1]
        self.fields['reg_type'].choices = mycosts['reg']
        self.fields['reg_type'].initial = mycosts['reg'][0][0]
        self.reg_costs = [x for x,y in mycosts['reg']]
        self.tut_costs = mycosts['tut']
        self.sessions = []
        for session, label in SESSIONS:
            choices = [ (t['id'], t['title']) for t in
                Tutorial.objects.filter(status='Open',
                                        session=session).values('id','title')]
            if len(choices) == 0: continue
            choices.insert(0,('', 'None'))
            self.fields.setdefault(session,
                ChoiceField(label=label, initial='',
                    required=False, choices=choices, widget=RadioSelect))
            self.sessions.append(session)

    def clean_reg_type(self):
        """There is an issue with early bound special cross fields validators
        like this one. We have not processed teh tutorial data yet. So
        we are in a real bind here. We must back off to the data object
        for the post. yuck!
        """
        val = self.cleaned_data['reg_type']
        index = self.reg_costs.index(val)
        if index == 2:
            n = sum(1 for s in self.sessions
                    if self.data.get(self.prefix+'-'+s,'') != '')
            if n == 0:
                raise ValidationError, (
                    "You must select at least one tutorial for a tutorial pass")
        return Decimal(val)

    def subtotal(self):
        if not self.is_valid():
            if self.data: return Decimal("0.00")
            return Decimal(self.fields['reg_type'].initial)
        reg = self.cleaned_data['reg_type']
        ind = sum(1 for s in self.sessions if self.cleaned_data[s] != '')
        tut = Decimal(self.tut_costs[ind])
        return reg+tut

    def save(self, invoice):
        if not self.is_valid():
            raise ValidationError, "Something broke"
        reg = Registration()
        reg.invoice = invoice
        if self.user is not None and not self.cleaned_data['not_me']:
            reg.user = self.user
        reg.early_reg = self.early_reg
        reg.name = self.cleaned_data['name']
        reg.email = self.cleaned_data['email']
        index = self.reg_costs.index(self.data[self.prefix+'-reg_type'])
        if index < 2:  reg.conference=True
        if index == 1: reg.student=True
        if index == 2: reg.tutorial=True
        reg.cost = self.subtotal()
        for name in Registration.changable:
            if name in self.cleaned_data:
                setattr(reg, name, self.cleaned_data[name])
        reg.save()
        tut_ids = [ self.cleaned_data[s] for s in self.sessions
                   if self.cleaned_data[s] != '']
        if tut_ids:
            tuts = Tutorial.objects.filter(pk__in=tut_ids)
            #assert(len(tut_ids) == len(tuts))
            reg.tutorial = True
            reg.tutorials = tuts
            reg.save()
        ## red_flag: send e-mail's here!?!? or in view?
        ## in view is safer in case of crash? hmmm...

        return reg

class PayPalCheckoutForm(Form):
    LOGIN        = CharField(max_length=100, widget=HiddenInput,
                             initial=PAYPAL_LOGIN)
    PARTNER      = CharField(max_length=100, widget=HiddenInput,
                             initial=PAYPAL_PARTNER)
    TYPE         = CharField(max_length=1,   widget=HiddenInput,
                             initial='S')
    AMOUNT       = DecimalField(max_digits=4, decimal_places=2,
                                             widget=HiddenInput)
    INVOICE      = CharField(max_length=9,   widget=HiddenInput)
    NAME         = CharField(max_length=60,  widget=HiddenInput, required=False)
    CUSTID       = CharField(max_length=11,  widget=HiddenInput, required=False)
    EMAIL        = EmailField(max_length=40, widget=HiddenInput, required=False)
    DESCRIPTION  = CharField(max_length=255, widget=HiddenInput, required=False)
    COMMENT1     = CharField(max_length=255, widget=HiddenInput, required=False)
    COMMENT2     = CharField(max_length=255, widget=HiddenInput, required=False)

    def __init__(self, invoice, *args, **kwdargs):
        self.invoice = invoice
        self.url = PAYPAL_URL
        initial = {}
        initial['AMOUNT'] = '%.2f' % invoice.total_cost
        initial['INVOICE'] = unicode(invoice)
        ## RED_FLAG: safe ascii_ize?
        #initial['NAME'] = unicode(invoice.user)[:60]
        initial['CUSTID'] = str(invoice.user.id)[:11]
        initial['EMAIL'] = invoice.user.email[:40]
        desc = invoice.get_desc()
        initial['DESCRIPTION'] = desc[:255]
        if len(desc) > 255: initial['COMMENT1'] = desc[255:510]
        if len(desc) > 510: initial['COMMENT2'] = desc[510:765]
        if 'initial' in kwdargs:
            initial.update(kwdargs['initial'])
        kwdargs['initial'] = initial
        super(PayPalCheckoutForm, self).__init__(*args, **kwdargs)
