# -*- encoding: utf-8 -*-
"""
@File    : forms.py
@Time    : 2020/1/3 11:14
@Author  : chise
@Email   : chise123@live.com
@Software: PyCharm
@info    :simpleui自定义表单
"""
from django import forms
import uuid

from django.core import validators
from django.core.exceptions import ValidationError
# Provide this import for backwards compatibility.
from django.core.validators import EMPTY_VALUES  # NOQA
from django.forms.boundfield import BoundField
from django.forms.forms import DeclarativeFieldsMetaclass, BaseForm
from django.forms.utils import from_current_timezone, to_current_timezone
from django.forms.widgets import (
    FILE_INPUT_CONTRADICTION, CheckboxInput, ClearableFileInput, DateInput,
    DateTimeInput, EmailInput, FileInput, HiddenInput, MultipleHiddenInput,
    NullBooleanSelect, NumberInput, Select, SelectMultiple,
    SplitDateTimeWidget, SplitHiddenDateTimeWidget, TextInput, TimeInput,
    URLInput,
)
from django.utils import formats
from django.utils.dateparse import parse_duration
from django.utils.duration import duration_string
from django.utils.ipv6 import clean_ipv6_address
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _, ngettext_lazy


import copy

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
# BoundField is imported for backwards compatibility in Django 1.9
from django.forms.boundfield import BoundField  # NOQA
from django.forms.fields import Field, FileField
# pretty_name is imported for backwards compatibility in Django 1.9
from django.forms.utils import ErrorDict, ErrorList, pretty_name  # NOQA
from django.forms.widgets import Media, MediaDefiningClass
from django.utils.functional import cached_property
from django.utils.html import conditional_escape, html_safe
from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from simpleui.widgets import *

class SimpleForm(BaseForm, metaclass=DeclarativeFieldsMetaclass):
    def get_vue_app_js(self,app_id):
        """
        将该方法需要的js渲染进去
        :return:
        """
        base_vue_app="""
<script>
var %(app_name)s = new Vue({
    el: "#%(app_name)s",
    data() {
        return {
            %(data)s
        }
    }
})
</script>
        """
        data={}
        for name, field in self.fields.items():
            data[name] = ''
        data.update(self.data)
        data_s=""
        for key,value in data.items():
            data_s+="%(key)s:'%(value)s'"%{
                'key':key,
                'value':value
            }+','
        return base_vue_app %{"app_name":app_id,"data":data_s}
    def submit_button(self):
        """
        渲染模板增加submit格式
        :return:
        """
        # return '<input type="submit">'


        pass
    def as_element(self):
        "Return this form rendered as HTML <tr>s -- excluding the <table></table>."
        x= self._html_output(
            normal_row='<div %(html_class_attr)s>%(label)s %(field)s%(help_text)s</div>',
            error_row='%s',
            row_ender='</div>',
            help_text_html=' <span class="helptext">%s</span>',
            errors_on_separate_row=True,flag=True
        )
        return x

    def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row,flag=False):
        "Output HTML. Used by as_table(), as_ul(), as_p()."
        top_errors = self.non_field_errors()  # Errors that should be displayed above all fields.
        output, hidden_fields = [], []

        for name, field in self.fields.items():
            html_class_attr = ''
            bf = self[name]
            if flag:
                bf.field.widget.flag=True
            bf_errors = self.error_class(bf.errors)
            if bf.is_hidden:
                if bf_errors:
                    top_errors.extend(
                        [_('(Hidden field %(name)s) %(error)s') % {'name': name, 'error': str(e)}
                         for e in bf_errors])
                hidden_fields.append(str(bf))
            else:
                # Create a 'class="..."' attribute if the row should have any
                # CSS classes applied.
                css_classes = bf.css_classes()
                if css_classes:
                    html_class_attr = ' class="%s"' % css_classes

                if errors_on_separate_row and bf_errors:
                    output.append(error_row % str(bf_errors))

                if bf.label:
                    label = conditional_escape(bf.label)
                    label = bf.label_tag(label) or ''
                else:
                    label = ''

                if field.help_text:
                    help_text = help_text_html % field.help_text
                else:
                    help_text = ''

                output.append(normal_row % {
                    'errors': bf_errors,
                    'label': label,
                    'field': bf,
                    'help_text': help_text,
                    'html_class_attr': html_class_attr,
                    'css_classes': css_classes,
                    'field_name': bf.html_name,
                })

        if top_errors:
            output.insert(0, error_row % top_errors)
        if hidden_fields:  # Insert any hidden fields in the last row.
            str_hidden = ''.join(hidden_fields)
            if output:
                last_row = output[-1]
                # Chop off the trailing row_ender (e.g. '</td></tr>') and
                # insert the hidden fields.
                if not last_row.endswith(row_ender):
                    # This can happen in the as_p() case (and possibly others
                    # that users write): if there are only top errors, we may
                    # not be able to conscript the last row for our purposes,
                    # so insert a new, empty row.
                    last_row = (normal_row % {
                        'errors': '',
                        'label': '',
                        'field': '',
                        'help_text': '',
                        'html_class_attr': html_class_attr,
                        'css_classes': '',
                        'field_name': '',
                    })
                    output.append(last_row)
                output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
            else:
                # If there aren't any rows in the output, just append the
                # hidden fields.
                output.append(str_hidden)
        if flag:
            app_id = "x" + str(uuid.uuid4())[0:5]
            output.insert(0, "<div id='%s'>" %app_id)
            output.append('</div>')
            output.append(self.get_vue_app_js(app_id))
        return mark_safe('\n'.join(output))

class SCharField(forms.CharField):
    widget = STextInput
class SIntegerField(forms.IntegerField):
    def widget_attrs(self, widget):
        """
        解决max和min无法传递到widget的问题
        """
        attrs = super().widget_attrs(widget)
        if isinstance(widget, NumberInput) or isinstance(widget,SNumberInput):
            if self.min_value is not None:
                attrs['min'] = self.min_value
            if self.max_value is not None:
                attrs['max'] = self.max_value
        return attrs
    widget = SNumberInput

class SEmailField(forms.EmailField):
    widget = SEmailInput

class SURLField(forms.URLField):
    widget = SURLInput