#
# PythonImage.py -- Abstraction of an generic data image.
#
# Eric Jeschke (eric@naoj.org) 
#
# Copyright (c) Eric R. Jeschke.  All rights reserved.
# This is open-source software licensed under a BSD license.
# Please see the file LICENSE.txt for details.
#
import sys, time
import numpy
import mimetypes
import os
import hashlib

try:
    # do we have Python Imaging Library available?
    import PIL.Image as Image
    from PIL.ExifTags import TAGS
    have_pil = True
except ImportError:
    have_pil = False

# We only need one of { have_pilutil, have_qtimage }, but both have
# their strengths
try:
    from  scipy.misc import pilutil, imsave
    have_pilutil = True
except ImportError:
    have_pilutil = False

try:
    from ginga.qtw.QtHelp import QtCore, QtGui
    QImage, QColor = QtGui.QImage, QtGui.QColor
    have_qtimage = True
except ImportError, e:
    have_qtimage = False

try:
    # How about color management (ICC profile) support?
    import ImageCms
    have_cms = True
except ImportError:
    have_cms = False

# For testing...
#have_qtimage = False
#have_pilutil = False
#have_pil = False
#have_cms = False

from ginga.misc import Bunch
from ginga.BaseImage import BaseImage, ImageError

try:
    basedir = os.environ['GINGA_HOME']
except KeyError:
    basedir = os.path.join(os.environ['HOME'], '.ginga')
working_profile = os.path.join(basedir, "profiles", "working.icc")


class PythonImage(BaseImage):

    def load_file(self, filepath):
        kwds = {}
        metadata = { 'exif': {}, 'path': filepath }

        data_np = self._imload(filepath, kwds)

        self.set_data(data_np, metadata=metadata)
        self.set(exif=kwds)

    def save_file_as(self, filepath):
        if not have_pil:
            raise ImageError("Install PIL to be able to save images")

        data = self.get_data()
        imsave(filepath, data)


    def copy(self, astype=None):
        other = PythonImage()
        self.transfer(other, astype=astype)
        return other

    def get_scaled_cutout_wdht(self, x1, y1, x2, y2, new_wd, new_ht,
                                  method='bicubic'):
        # calculate dimensions of NON-scaled cutout
        old_wd = x2 - x1 + 1
        old_ht = y2 - y1 + 1
        self.logger.debug("old=%dx%d new=%dx%d" % (
            old_wd, old_ht, new_wd, new_ht))

        data = self.get_data()
        newdata = data[y1:y2+1, x1:x2+1]

        newdata = self._imresize(newdata, new_wd, new_ht, method=method)

        ht, wd = newdata.shape[:2]
        scale_x = float(wd) / old_wd
        scale_y = float(ht) / old_ht
        res = Bunch.Bunch(data=newdata, org_fac=1,
                          scale_x=scale_x, scale_y=scale_y)
        return res

    def get_scaled_cutout_pil(self, x1, y1, x2, y2, scale_x, scale_y,
                                  method='bicubic'):
        # calculate dimensions of NON-scaled cutout
        old_wd = x2 - x1 + 1
        old_ht = y2 - y1 + 1
        new_wd = int(round(scale_x * old_wd))
        new_ht = int(round(scale_y * old_ht))
        self.logger.debug("old=%dx%d new=%dx%d" % (
            old_wd, old_ht, new_wd, new_ht))

        data = self.get_data()
        newdata = data[y1:y2+1, x1:x2+1]

        newdata = self._imresize(newdata, new_wd, new_ht, method=method)

        ht, wd = newdata.shape[:2]
        scale_x = float(wd) / old_wd
        scale_y = float(ht) / old_ht
        res = Bunch.Bunch(data=newdata, org_fac=1,
                          scale_x=scale_x, scale_y=scale_y)
        return res

    def get_scaled_cutout(self, x1, y1, x2, y2, scale_x, scale_y,
                          method=None):
        if method == None:
            if (have_pilutil or have_qtimage):
                method = 'bicubic'
            else:
                method = 'basic'
                
        if method == 'basic':
            return self.get_scaled_cutout_basic(x1, y1, x2, y2,
                                                scale_x, scale_y)

        return self.get_scaled_cutout_pil(x1, y1, x2, y2,
                                          scale_x, scale_y,
                                          method=method)
    def _imload(self, filepath, kwds):
        """Load an image file, guessing the format, and return a numpy
        array containing an RGB image.  If EXIF keywords can be read
        they are returned in the dict _kwds_.
        """
        start_time = time.time()
        typ, enc = mimetypes.guess_type(filepath)
        if not typ:
            typ = 'image/jpeg'
        typ, subtyp = typ.split('/')
        self.logger.debug("MIME type is %s/%s" % (typ, subtyp))

        if (typ == 'image') and (subtyp in ('x-portable-pixmap',
                                            'x-portable-greymap')):
            # Special opener for PPM files, preserves high bit depth
            means = 'built-in'
            data_np = open_ppm(filepath)

        elif have_pil:
            # PIL seems to be the faster loader than QImage, and can
            # return EXIF info, where QImage will not.
            means = 'PIL'
            image = Image.open(filepath)

            try:
                info = image._getexif()
                for tag, value in info.items():
                    kwd = TAGS.get(tag, tag)
                    kwds[kwd] = value

            except Exception, e:
                self.logger.warn("Failed to get image metadata: %s" % (str(e)))

            # If we have a working color profile then handle any embedded
            # profile or color space information, if possible
            if have_cms and os.path.exists(working_profile):