from django.newforms.forms import BaseForm, BoundField, ErrorList
from django.utils.html import escape
    
def include_formfield_callback(*alloweds):
    def newfunc(f, **kwargs):
        return [None, f.formfield(**kwargs)][f.name in alloweds]	
    newfunc.alloweds = alloweds
    return newfunc

def form_fieldsets(*fieldsets):
    allowed_fields = []
    for fieldset in fieldsets:
        allowed_fields += fieldset[1]['fields']
        
    # TODO: Study whether we need to add separate name for each type we produce dynamically
    return {
        'form': type("DynamicFieldsetForm", (FieldsetForm,), {"fieldsets":fieldsets}), 
        'formfield_callback' : include_formfield_callback(*allowed_fields) }

class FieldsetForm(BaseForm):
    def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row, normal_fieldset, fieldset_nameholder):
        top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
        output = []
        
        for fieldset in self.fieldsets:
            fieldset_name = fieldset[0]
            fieldset_content = fieldset[1]
            fieldset_field_names = []
            fieldset_classes = ""
            normal_fieldset_rows = []
            # TODO: Test hidden fields
            hidden_fields = []
            
            # TODO: Implement error check (fields supposed to be list, and classes supposed to be string)
            if fieldset_content.has_key('fields'):
                fieldset_field_names = fieldset_content['fields']
            if fieldset_content.has_key('classes'):
                fieldset_classes = fieldset_content['classes']
            
            normal_fieldset_nameholder = ""
            if fieldset_name:
                normal_fieldset_nameholder = fieldset_nameholder % {'fieldset_name':fieldset_name}
            
            # Contents of this for loop is almost identical with BaseForm loop (except that I use normal_fieldset_rows at the end)
            for field_name in fieldset_field_names:
                name = field_name
                field = self.fields[field_name]
                
                bf = BoundField(self, field, name)
                bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable.
                if bf.is_hidden:
                    if bf_errors:
                        top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors])
                    hidden_fields.append(unicode(bf))
                else:
                    if errors_on_separate_row and bf_errors:
                        output.append(error_row % bf_errors)
                    label = bf.label and bf.label_tag(escape(bf.label + ':')) or ''
                    if field.help_text:
                        help_text = help_text_html % field.help_text
                    else:
                        help_text = u''
                    normal_fieldset_rows.append(normal_row % {'errors': bf_errors, 'label': label, 'field': unicode(bf), 'help_text': help_text})
                        
            output.append(normal_fieldset % {
                'fieldset_nameholder':      normal_fieldset_nameholder, 
                'fieldset_rows' :           "\n".join(normal_fieldset_rows), 
                'fieldset_hidden_fields':   "\n".join(hidden_fields), 
                'fieldset_classes' :        fieldset_classes})

        if top_errors:
            output.insert(0, error_row % top_errors)

        return u'\n'.join(output)

    def as_table(self):
        "Returns this form rendered as HTML <table> -- including the <table></table>."
        # TODO: Is class attribute allowed to be empty?
        # TODO: Add ability to add extra attributes to table element and fieldset element
        # TODO: Think about moving all this to templates (since it sounds more sane)
        #   It is not done that way yet because this is just first scetch (and BaseForm did this way)
        
        return self._html_output(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'<br />%s', False, u'<fieldset class="%(fieldset_classes)s">%(fieldset_nameholder)s<table class="form">%(fieldset_rows)s</table>%(fieldset_hidden_fields)s</fieldset>', u"<legend>%(fieldset_name)s</legend>")

    # I'm too excited to define the following, so we shall just pass at this point:
    def as_ul(self):
        pass
        '''
        "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
        return self._html_output(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False)
        '''

    def as_p(self):
        pass
        '''
        "Returns this form rendered as HTML <p>s."
        return self._html_output(u'<p>%(label)s %(field)s%(help_text)s</p>', u'<p>%s</p>', '</p>', u' %s', True)
        '''