'''A Form subclass that provides close to the same API as the old form
class (useful for transitioning existing forms).
'''

from quixote import get_request, get_path, redirect
from quixote.form import Form as _Form, Widget, StringWidget, FileWidget, \
    PasswordWidget, TextWidget, CheckboxWidget, RadiobuttonsWidget, \
    SingleSelectWidget, SelectWidget, OptionSelectWidget, \
    MultipleSelectWidget, SubmitWidget, HiddenWidget, \
    FloatWidget, IntWidget
from quixote.html import url_quote

_widget_names = {
    "string" : StringWidget,
    "file" : FileWidget,
    "password" : PasswordWidget,
    "text" : TextWidget,
    "checkbox" : CheckboxWidget,
    "single_select" : SingleSelectWidget,
    "radiobuttons" : RadiobuttonsWidget,
    "multiple_select" : MultipleSelectWidget,
    "submit_button" : SubmitWidget,
    "hidden" : HiddenWidget,
    "float" : FloatWidget,
    "int" : IntWidget,
    "option_select" : OptionSelectWidget,
}


class Form(_Form):
    def __init__(self, action_url=None, *args, **kwargs):
        _Form.__init__(self, action=action_url, *args, **kwargs)
        self.cancel_url = None
        self.action_url = self.action

    def add_widget(self, widget_class, name, value=None,
                   title=None, hint=None, required=False, **kwargs):
        try:
            widget_class = _widget_names[widget_class]
        except KeyError:
            pass
        self.add(widget_class, name, value=value, title=title, hint=hint,
                 required=required, **kwargs)

    def add_submit_button(self, name, value):
        self.add_submit(name, value)

    def add_cancel_button(self, caption, url):
        self.add_submit("cancel", caption)
        self.cancel_url = url

    def get_action_url(self):
        action_url = url_quote(get_path())
        query = get_request().get_query()
        if query:
            action_url += "?" + query
        return action_url

    def render(self, action_url=None):
        if action_url:
            self.action_url = action_url
        return _Form.render(self)

    def process(self):
        values = {}
        request = get_request()
        for name, widget in self._names.items():
            values[name] = widget.parse()
        return values

    def action(self, submit, values):
        raise NotImplementedError, "sub-classes must implement 'action()'"

    def handle(self):
        """handle() -> string

        Master method for handling forms.  It should be called after
        initializing a form.  Controls form action based on a request.  You
        probably should override 'process' and 'action' instead of
        overriding this method.
        """
        request = get_request()
        if not self.is_submitted():
            return self.render(self.action_url)
        submit = self.get_submit()
        if submit == "cancel":
            return redirect(self.cancel_url)
        values = self.process()
        if submit == True:
            # The form was submitted by an unregistered submit button, assume
            # that the submission was required to update the layout of the form.
            self.clear_errors()
            return self.render(self.action_url)

        if self.has_errors():
            return self.render(self.action_url)
        else:
            return self.action(submit, values)
