from quixote.html import htmltext
import quixote.directory
from authentic.admin.menu import html_top
from quixote import get_publisher, get_request, get_response, get_session, redirect
import quixote.form
import qommon.form
import schema
from qommon.publisher import get_cfg, get_publisher
import authentic.misc as misc

class ConfigurationForm(object):
    '''Create and parse forms for a configuration schema'''

    _widget_class_map = {
            schema.Boolean: quixote.form.CheckboxWidget,
            schema.String: quixote.form.StringWidget,
            schema.Regexp: quixote.form.StringWidget,
            schema.EMail: qommon.form.EmailWidget,
            schema.Integer: quixote.form.IntWidget,
            (schema.String, 'Text'): quixote.form.TextWidget,
            (schema.String, 'Password'): quixote.form.PasswordWidget,
            (schema.String, 'File'): quixote.form.FileWidget
    }

    def __init__(self, configuration, path = None):
        self.configuration = configuration
        if path:
            self.configuration = self.configuration.cd(path)

    def __getWidgetClass(self, s):
        if s.presentation_hint and s.presentation_hint.get('widget'):
            widget_class = self._widget_class_map.get((type(s), s.presentation_hint.get('widget')))
        else:
            widget_class = self._widget_class_map.get(type(s))
        return widget_class

    def __addLeafWidget(self, form, s, value, name):
        widget_class = self.__getWidgetClass(s)
        if widget_class:
            other_kwargs = s.presentation_hint.get('args', {})
            if s.presentation_hint.get('hidden'):
                return
            form.add(widget_class, name,
                    title = _(s.title),
                    hint = s.description and _(s.description),
                    value = value, **other_kwargs)
            # if value if overrided, disable the widget
            # and show a justification
            if callable(s.override):
                o = s.override()
                if o:
                    value,hint=o
                    w=form.get_widget(name)
                    w.hint = hint
                    w.value = value
                    w.attrs['disabled'] = 'disabled'
            if not s.check(value):
                form._names[name].set_error(N_('This value is not correct'))
        else:
            raise NotImplementedError('%s is not supported by %s' % (s.__class__, self.__class__))

    def fillForm(self,form):
        for k in self.configuration._schema.ordered:
            s = self.configuration.schema(k)
            name = '.'.join(self.configuration.prefix + [k])
            if isinstance(s, schema.Options):
                value=self.configuration.get([k])
                options = []
                for k, v in s.content.iteritems():
                    options.append((k, _(v['description'])))
                form.add(quixote.form.SingleSelectWidget,
                        name,
                        title = _(s.title),
                        hint = s.description and _(s.description),
                        value = value, options = options)
            elif isinstance(s, schema.LeafBase):
                v=self.configuration.get([k])
                self.__addLeafWidget(form, s, v, name)

    def hasError(self,form):
        '''Get a form for current schema and eventually a path'''
        if form.has_errors():
            return True
        result=False
        for k in self.configuration.keys():
            s = self.configuration.schema(k)
            if isinstance(s, schema.LeafBase):
                widget = form.get_widget('.'.join(self.configuration.prefix + [k]))
                check=s.check(widget.parse())
                if not check:
                    widget.set_error(_(s.CHECK_ERROR))
                result = result or not check
        return result

    def parseForm(self, form):
        if self.hasError(form):
            return False
        self.__parseForm(form)
        return True

    def __parseForm(self, form):
        for k in self.configuration.keys():
            s = self.configuration.schema(k)
            if isinstance(s, schema.LeafBase):
                widget=form.get_widget('.'.join(self.configuration.prefix + [k]))
                value=widget.parse()
                if hasattr(value, 'fp'):
                    value=value.fp.read()
                self.configuration.set(k, value)
        self.configuration.store()

class SettingPage(object):
    def __init__(self, get_configuration, path):
        self.get_configuration = get_configuration
        self.path = path

    def isReadOnly(self):
        c=self.get_configuration(self.path)
        s=c._schema
        # is it write only ?
        read_only=s.presentation_hint.get('read_only')
        if callable(read_only):
            return read_only(c)
        return 

    def __call__(self):
        c=self.get_configuration(self.path)
        s=c._schema
        cf=ConfigurationForm(c)
        f = qommon.form.Form(enctype='multipart/form-data')
        f.keep_referer()
        cf.fillForm(f)
        readOnly = self.isReadOnly()
        if not readOnly:
            f.add_submit('submit', _('Submit'))
        f.add_submit('cancel', _('Cancel'))

        if f.get_submit() == 'cancel':
            return redirect(f.referer() or '.')

        if f.is_submitted() and not readOnly:
            if cf.parseForm(f):
                return redirect(f.referer() or '.')
        # FIXME: here handle other submits

        out=''
        out+=get_session().display_message()
        get_response().breadcrumb.append((s.name, _(s.title)))
        out+=html_top('settings', title = _(s.title))
        out+=htmltext('<h2>%s</h2>') % _(s.title)
        out+=f.render()
        return out

class SettingDirectory(quixote.directory.AccessControlled, quixote.directory.Directory):
    def __init__(self, *args, **kwargs):
        super(SettingDirectory, self).__init__(*args, **kwargs)

    def __getattr__(self, name):
        c=self.get_schema()
        if name in c.content:
            return SettingPage(self.get_configuration, name)
        return super(SettingDirectory, self).__getattr__(name)

    def _q_traverse(self, path):
        s=self.get_schema()
        get_response().breadcrumb.append((s.name + '/', _(s.title)))
        return super(SettingDirectory, self)._q_traverse(path)

class PublisherConfiguration(schema.Configuration):
    def store(self):
        get_publisher().cfg = self._root[1]
        get_publisher().write_cfg()

def get_configuration(schema):
    p=get_publisher()
    p.reload_cfg()
    c=PublisherConfiguration(schema, p.cfg)
    return c
