""" ImageKit image specifications

All imagekit specifications must inherit from the ImageSpec class. Models
inheriting from ImageModel will be modified with a descriptor/accessor for each
spec found.

"""
import os
from StringIO import StringIO
from imagekit.lib import *
from imagekit.utils import img_to_fobj
from django.core.files.base import ContentFile

class ImageSpec(object):
    pre_cache = False
    quality = 70
    increment_count = False
    processors = []
    
    @classmethod
    def name(cls):
        return getattr(cls, 'access_as', cls.__name__.lower())
        
    @classmethod
    def process(cls, image, obj):
        processed_image = image.copy()
        for proc in cls.processors:
            processed_image = proc.process(processed_image, obj)
        return processed_image
        

class Accessor(object):
    def __init__(self, obj, spec):
        self._img = None
        self._obj = obj
        self.spec = spec
        
    def _get_imgfile(self):
        format = self._img.format or 'JPEG'
        if format != 'JPEG':
            imgfile = img_to_fobj(self._img, format)
        else:
            imgfile = img_to_fobj(self._img, format,
                                  quality=int(self.spec.quality),
                                  optimize=True)
        return imgfile
        
    def _create(self):
        if self._exists():
            return
        # process the original image file
        fp = self._obj._imgfield.storage.open(self._obj._imgfield.name)
        fp.seek(0)
        fp = StringIO(fp.read())
        try:
            self._img = self.spec.process(Image.open(fp), self._obj)
            # save the new image to the cache
            content = ContentFile(self._get_imgfile().read())
            self._obj._imgfield.storage.save(self.name, content)
        except IOError:
            pass
        
    def _delete(self):
        self._obj._imgfield.storage.delete(self.name)

    def _exists(self):
        return self._obj._imgfield.storage.exists(self.name)

    def _basename(self):
        filename, extension =  \
            os.path.splitext(os.path.basename(self._obj._imgfield.name))
        return self._obj._ik.cache_filename_format % \
            {'filename': filename,
             'specname': self.spec.name(),
             'extension': extension.lstrip('.')}

    @property
    def name(self):
        return os.path.join(self._obj._ik.cache_dir, self._basename())

    @property
    def url(self):
        self._create()
        if self.spec.increment_count:
            fieldname = self._obj._ik.save_count_as
            if fieldname is not None:
                current_count = getattr(self._obj, fieldname)
                setattr(self._obj, fieldname, current_count + 1)
                self._obj.save(clear_cache=False)
        return self._obj._imgfield.storage.url(self.name)
        
    @property
    def file(self):
        self._create()
        return self._obj._imgfield.storage.open(self.name)
        
    @property
    def image(self):
        if self._img is None:
            self._create()
            if self._img is None:
                self._img = Image.open(self.file)
        return self._img
        
    @property
    def width(self):
        return self.image.size[0]
        
    @property
    def height(self):
        return self.image.size[1]


class Descriptor(object):
    def __init__(self, spec):
        self._spec = spec

    def __get__(self, obj, type=None):
        return Accessor(obj, self._spec)