from django.db import models
from django.forms import CharField
from django.utils.translation import ugettext as _
from utils.volumes import get_path_driver

try: #attempt to explain south how to handle the ElfinderField
    from south.modelsinspector import add_introspection_rules
    add_introspection_rules([], ["^elfinder\.fields\.ElfinderField"])
except:
    pass

class ElfinderFile(object):
    """
    This class represents an Elfinder file.
    """
    
    def __init__(self, hash_, optionset):
        self.hash = hash_
        self.optionset = optionset
        self._info = None
    
    def _get_info(self):
        if self._info is None:
            
            if not self.hash:
                self._info = {}
            else:
                driver = get_path_driver(self.hash, self.optionset)
                try:
                    info = driver.options(self.hash)
                    info.update(driver.file(self.hash))
                    
                    #get image dimensions
                    if not 'dim' in info and 'mime' in info and info['mime'].startswith('image'):
                        info['dim'] = driver.dimensions(self.hash)
                        
                    #calculate thumbnail url
                    if 'tmb' in info and 'tmbUrl' in info:
                        info['tmb'] = '%s%s' % (info['tmbUrl'], info['tmb'])
                        del info['tmbUrl']
                        
                    if 'archivers' in info:
                        del info['archivers']
                        
                    if 'extract' in info:
                        del info['extract']
                    
                    self._info = info
                except:
                    self._info = { 'error' : _('This file is no longer valid') }  

        return self._info
        
    @property
    def url(self):
        """
        Get the file url.
        """
        info = self._get_info()
        return info['pathUrl'] if 'pathUrl' in info else ''
    
    @property
    def info(self):
        """
        Returns:
            a **dictionary** holding information about the file, 
            as returned by the volume driver.
        """
        return self._get_info()
            
    def __unicode__(self):
        return self.hash

class ElfinderFormField(CharField):
    """
    Override the standard CharField form field
    to set :class:`elfinder.widgets.ElfinderWidget` as the default widget.
    """
    
    def __init__(self, optionset, start_path, *args, **kwargs):
        from widgets import ElfinderWidget
        super(ElfinderFormField, self).__init__(*args, **kwargs)
        #TODO: elfinder widget should be initialized using possible client options from model field declaration
        self.optionset = optionset 
        self.widget = ElfinderWidget(optionset, start_path)

    def prepare_value(self, value):
        if isinstance(value, ElfinderFile):
            return value.__unicode__()
        return value

    def to_python(self, value):
        """
        Convert ``value`` to an :class:`elfinder.fields.ElfinderFile` object.
        """
        if isinstance(value, ElfinderFile):
            return value
        return ElfinderFile(hash_=value, optionset=self.optionset) if value else None
    
    def clean(self, value):
        """
        Override the default CharField validation to validate the 
        ElfinderFile hash string before converting it to an ElfinderField
        object. Finally, return a cleaned ElfinderFile object.  
        """
        self.validate(value)
        self.run_validators(value)
        value = self.to_python(value)
        return value

class ElfinderField(models.Field):
    """
    Custom model field holding an :class:`elfinder.fields.ElfinderFile` object.
    """
    
    description = "An elfinder file model field."
    __metaclass__ = models.SubfieldBase

    def __init__(self, optionset='default', start_path=None, *args, **kwargs):
        self.optionset = optionset
        self.start_path = start_path

        if not 'max_length' in kwargs:
            kwargs['max_length'] = 100 #default field length

        super(ElfinderField, self).__init__(*args, **kwargs)
        
    def get_internal_type(self):
        """
        This lets Django know how to handle the field
        """
        return "CharField"
        
    def to_python(self, value):
        """
        Convert ``value`` to an :class:`elfinder.fields.ElfinderFile` object.
        """
        if isinstance(value, ElfinderFile):
            return value
        return ElfinderFile(hash_=value, optionset=self.optionset) if value else None
    
    def get_prep_value(self, value):
        """
        Overriden method to return a string representation of 
        the :class:`elfinder.fields.ElfinderFile`.
        """
        if isinstance(value, ElfinderFile):
            return value.hash
        return value
    
    def get_prep_lookup(self, lookup_type, value):
        """
        Overriden method to disallow 
        ``year``, ``month`` and ``day`` queries
        """
        if lookup_type in ['year', 'month', 'day']:
            raise TypeError('Lookup type %r not supported.' % lookup_type)
        
        return super(ElfinderField, self).get_prep_lookup(lookup_type, value)
        
    def formfield(self, **kwargs):
        """
        Overriden method to set the form field defaults.
        See :class:`elfinder.fields.ElfinderFormField`
        """
        
        defaults = {
                'form_class': ElfinderFormField,
                'optionset' : self.optionset,
                'start_path' : self.start_path
        }
        defaults.update(kwargs)
        return super(ElfinderField, self).formfield(**defaults)