"""ReStructuredText form elements and helpers

"""
from django import newforms
from django.contrib.flatpages.models import FlatPage
from django.contrib.sites.models import Site
from templatetags.restructuredtext import restructuredparts
from models import FlatPageHistory, WARNING
from pycon.core import safe_utf8_encode

class ReSTField(newforms.CharField):
    def __init__(self, style=None, aclass=None, rows=None, cols=None, wrap='off',
                 include_error=False, require_title=False,
                 *args, **kwdargs):
        self.style = style
        self.rows = rows
        self.cols = cols
        self.wrap = wrap
        self.aclass = aclass
        self.include_error = include_error
        self.require_title = require_title
        if 'widget' not in kwdargs:
            kwdargs['widget'] = newforms.Textarea
        super(ReSTField, self).__init__(*args, **kwdargs)
    
    def clean(self, value):
        "Validates the string is valid ReST. Returns a Unicode object."
        cleaned = super(ReSTField, self).clean(value)
        if cleaned == u'': return u''
        parts = {}
        try:
            parts = restructuredparts(value, halt_level=2, traceback=1)
        except Exception, e:
            msg = 'ReStructuredText contains errors.'
            if self.include_error: msg = u'ReStructuredText contains errors:' + safe_utf8_encode(e)
            raise newforms.ValidationError(msg)
        if self.require_title and ('title' not in parts or not parts['title']):
            raise newforms.ValidationError(u"A single top level title is required.")
        return cleaned
    
    def widget_attrs(self, widget):
        data = super(ReSTField, self).widget_attrs(widget)
        if not isinstance(data, dict): data = {}
        if isinstance(widget, newforms.Textarea):
            if self.style is not None  and 'style' not in data:
                data['style'] = str(self.style)
            if self.rows and 'rows' not in data:
                data['rows']= str(self.rows)
            if self.cols and 'cols' not in data:
                data['cols']= str(self.cols)
            if self.wrap and 'wrap' not in data:
                data['wrap']= str(self.wrap)
            if self.aclass and 'class' not in data:
                data['class'] = str(self.aclass)
        return data

class BasicReSTForm(newforms.Form):
    content = ReSTField()


class _RstPageForm(newforms.BaseForm):
    def __init__(self, post=None, user=None, page=None, url=None,
                 *args, **kwdargs):
        self.user = user
        self.page = page
        self.url  = url
        return super(_RstPageForm, self).__init__(post, *args, **kwdargs)
    def smart_save(self, commit=True, save_callback=None):
        if self.page is None and not commit:
            raise ValueError("commit must be True for new pages.")
        rstp = save_callback(self, commit=False)
        if self.user is not None:
            rstp.user = self.user
        if self.page:
            rstp.page = self.page
        else:
            page = FlatPage()
            page.url = self.url
            page.title = u'Error: Page faild to save properly'
            page.content = WARNING + u'Error: Page failed to save properly.'
            page.enable_comments = False
            page.registration_required = False
            page.save()
            page.sites = [ Site.objects.get_current() ]
            page.save()
            rstp.page = page
        if commit:
            rstp.save()
        return rstp
    
def _content_callback(f):
    if f.name == 'content':
        return ReSTField(include_error=True, require_title=True,
                         rows=30, cols=85, aclass="monospace")
    if f.name == 'username':
        return f.formfield(required=True)
    return f.formfield()

_BaseRstPage = newforms.form_for_model(FlatPageHistory, form=_RstPageForm,
                                       fields=['content', 'comment'],
                                       formfield_callback=_content_callback)
_BaseAnonRstPage = newforms.form_for_model(FlatPageHistory, form=_RstPageForm,
                                           fields=['content', 'comment', 'username'],
                                           formfield_callback=_content_callback)    
class UserRstPageForm(_BaseRstPage):
    def save(self, commit=True):
        return super(UserRstPageForm, self).smart_save(commit,
                                        save_callback=_BaseRstPage.save)
    
class AnonRstPageForm(_BaseAnonRstPage):
    def save(self, commit=True):
        return super(AnonRstPageForm, self).smart_save(commit,
                                        save_callback=_BaseAnonRstPage.save)

## Simplify all the different types of forms intop a single helper func:
## Handles the rubrik (4 forms in 1):
##    FlatPage: create edit 
##    User:     known  anon  # (anon = username becomes required field)
##    History:  create       # (histories are always created, never edited.
##
def RstPageForm(post=None, user=None, page=None, url=None, *args, **kwdargs):
    if user is None or user.is_anonymous():
        return AnonRstPageForm(post, user, page, url, *args, **kwdargs)
    return UserRstPageForm(post, user, page, url, *args, **kwdargs)
