import uuid
import re

from django.forms import Textarea, MultiWidget, Select, \
        HiddenInput, FileInput, SelectMultiple
from django.utils.safestring import mark_safe
from django.conf import settings
from django.template.loader import render_to_string

from upload_views import get_files_for_id

class TextInpuWithPredefinedValues(MultiWidget):
    CLIENT_CODE = '''
    <script type="text/javascript">
    $(document).ready(function () {
        $('#id_%(name)s_0').change(function () {
            $('#id_%(name)s_1').val($(this).val());
        });
        $('#id_%(name)s_1').keypress(function () {
            $('#id_%(name)s_0').val('---');
        });
    });
    </script>'''

    def __init__(self, attrs=None, choices=[]):
        widget_list = (Select(attrs=attrs, choices=choices),
                Textarea(attrs=attrs))
        super(TextInpuWithPredefinedValues, self).__init__(widget_list, attrs)

    def decompress(self, value):
        return ['---', value]

    def value_from_datadict(self, data, files, name):
        select, text_input = super(TextInpuWithPredefinedValues, self).value_from_datadict(data, files, name)
        if text_input or select == '---':
            return text_input
        else:
            return select

    def render(self, name, value, attrs=None):
        output = super(TextInpuWithPredefinedValues, self).render(name, value,
                attrs)
        return output + mark_safe(self.CLIENT_CODE % { 'name': name })

    class Media:
        js = ('jquery/js/jquery-1.6.2.min.js',)

class MultiFileInput(FileInput):
    '''
       FileInput field supporting the multiple attribute
    '''
    def __init__(self, attrs=None):
        super(MultiFileInput, self).__init__(attrs)
        self.attrs['multiple'] = 'true'

    def value_from_datadict(self, data, files, name):
        if name in files:
            return files.getlist(name)
        else:
            return []

class JqueryFileUploadFileInput(MultiFileInput):
    def __init__(self, extensions=[], attached_file_kind=None, *args,**kwargs):
        self.extensions = extensions
        self.attached_file_kind = attached_file_kind
        super(JqueryFileUploadFileInput, self).__init__(*args, **kwargs)

    def render(self, name, value, attrs=None):
        # output = super(JqueryFileUploadFileInput, self).render(name, value, attrs)
        output = render_to_string('docbow/upload.html', {
            'open_tv': '{{',
            'close_tv': '}}',
            'upload_url': self.url,
            'extensions': self.extensions,
            'attached_file_kind': self.attached_file_kind,
            'files': self.files,
            'name': name,
            'STATIC_URL': settings.STATIC_URL})
        return mark_safe(output)

    class Media:
        js = ('jquery/js/jquery-1.6.2.min.js',
              'jquery-ui/js/jquery-ui-1.8.4.min.js',
              'jquery-plugin/js/jquery.tmpl.min-beta1.js',
              'jquery-plugin/js/jquery.iframe-transport.js',
              'jquery-plugin/js/jquery.fileupload.js',
              'jquery-plugin/js/jquery.fileupload-ui.js')
        css = {'all': ('jquery-ui/css/jquery-ui-1.8.4.css', 
               'jquery-plugin/css/jquery.fileupload-ui.css',)}

class JqueryFileUploadInput(MultiWidget):
    needs_multipart_form = True
    CLIENT_CODE = '''
    <script type="text/javascript">
    </script>'''
    upload_id_re = re.compile(r'^[a-z0-9A-Z-]+$')
    upload_id = None

    def __init__(self, attrs=None, choices=[], max_filename_length=None, extensions=[], attached_file_kind=None):
        self.extensions = extensions
        self.max_filename_length = max_filename_length
        self.attached_file_kind = attached_file_kind
        widget_list = (HiddenInput(attrs=attrs),
                JqueryFileUploadFileInput(attrs=attrs, extensions=extensions,
                    attached_file_kind=attached_file_kind))
        super(JqueryFileUploadInput, self).__init__(widget_list, attrs)

    def decompress(self, value):
        # map python value to widget contents
        if self.upload_id:
            pass
        elif isinstance(value, (list, tuple)) and value and value[0] is not None:
            self.upload_id = str(value[0])
        else:
            self.upload_id = str(uuid.uuid4())
        return [self.upload_id, None]

    def value_from_datadict(self, data, files, name):
        '''
           If some file was submitted, that's the value,
           If a regular hidden_id is present, use it to find uploaded files,
           otherwise return an empty list
        '''
        upload_id, file_input = super(JqueryFileUploadInput, self).value_from_datadict(data, files, name)
        if file_input:
            pass
        elif JqueryFileUploadInput.upload_id_re.match(upload_id):
            file_input = list(get_files_for_id(upload_id))
        else:
            file_input = []
        return [upload_id, file_input]

    def render(self, name, value, attrs=None):
        self.decompress(value)
        url = '/upload/%s/' % self.upload_id
        if self.attached_file_kind and self.attached_file_kind.id:
            url += '%s/' % self.attached_file_kind.id
            if self.attached_file_kind.cardinality:
                url += '?cardinality=%s' % self.attached_file_kind.cardinality
        if self.max_filename_length:
            url += '&' if '?' in url else '?'
            url += 'max_filename_length=%d' % self.max_filename_length
        self.widgets[1].url = url
        self.widgets[1].files = '/upload/%s/' % get_files_for_id(self.upload_id)
        output = super(JqueryFileUploadInput, self).render(name, value,
                attrs)
        fileinput_id = '%s_%s' % (attrs['id'], '1')
        return output + mark_safe(self.CLIENT_CODE % {
            'upload_id': self.upload_id, 'fileinput_id': fileinput_id })

class ForcedValueWidget(SelectMultiple):
    def __init__(self, attrs=None, format=None, value=None, display_value=""):
        super(ForcedValueWidget, self).__init__(attrs)
        self.display_value = display_value
        self.value = value

    def value_from_datadict(self, data, files, name):
        return self.value

    def render(self, name, value, attrs=None):
        return mark_safe(u'<div class="selector"><span class="display-value">%s</span></div>' % self.display_value)

class FilteredSelectMultiple(SelectMultiple):
    """
    Imported from django.contrib.admin.widget, to improve on javascript files.

    A SelectMultiple with a JavaScript filter interface.

    Note that the resulting JavaScript assumes that the jsi18n
    catalog has been loaded in the page
    """
    class Media:
        js = ("docbow/filter-widget/js/core.js",
              "docbow/filter-widget/js/SelectBox.js",
              "docbow/filter-widget/js/SelectFilter2.js",
              "js/i18n.js")
        css = { 'all': ('docbow/filter-widget/css/filter-widget.css',)}

    def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
        self.verbose_name = verbose_name
        self.is_stacked = is_stacked
        super(FilteredSelectMultiple, self).__init__(attrs, choices)

    def render(self, name, value, attrs=None, choices=()):
        if attrs is None: attrs = {}
        attrs['class'] = 'selectfilter'
        if self.is_stacked: attrs['class'] += 'stacked'
        output = [super(FilteredSelectMultiple, self).render(name, value, attrs, choices)]
        output.append(u'<script type="text/javascript">addEvent(window, "load", function(e) {')
        # TODO: "id_" is hard-coded here. This should instead use the correct
        # API to determine the ID dynamically.
        output.append(u'SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % \
            (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.STATIC_URL))
        return mark_safe(u''.join(output))
