__all__ = ['imread', 'imread_collection']

import numpy as np
import skimage.io as io

try:
    import pyfits
except ImportError:
    raise ImportError("PyFITS could not be found. Please refer to\n"
        "http://www.stsci.edu/resources/software_hardware/pyfits\n"
        "for further instructions.")


def imread(fname, dtype=None):
    """Load an image from a FITS file.

    Parameters
    ----------
    fname : string
        Image file name, e.g. ``test.fits``.
    dtype : dtype, optional
        For FITS, this argument is ignored because Stefan is planning on
        removing the dtype argument from imread anyway.

    Returns
    -------
    img_array : ndarray
        Unlike plugins such as PIL, where different colour bands/channels are
        stored in the third dimension, FITS images are greyscale-only and can
        be N-dimensional, so an array of the native FITS dimensionality is
        returned, without colour channels.

        Currently if no image is found in the file, None will be returned

    Notes
    -----

    Currently FITS ``imread()`` always returns the first image extension when
    given a Multi-Extension FITS file; use ``imread_collection()`` (which does
    lazy loading) to get all the extensions at once.

    """

    hdulist = pyfits.open(fname)

    # Iterate over FITS image extensions, ignoring any other extension types
    # such as binary tables, and get the first image data array:
    img_array = None
    for hdu in hdulist:
        if isinstance(hdu, pyfits.ImageHDU) or \
           isinstance(hdu, pyfits.PrimaryHDU):
           if hdu.data is not None:
               img_array = hdu.data
               break
    hdulist.close()

    return img_array


def imread_collection(load_pattern, conserve_memory=True):
    """Load a collection of images from one or more FITS files

       Parameters
       ----------
       load_pattern : str or list
           List of extensions to load. Filename globbing is currently
           unsupported.
       converve_memory : bool
           If True, never keep more than one in memory at a specific
           time. Otherwise, images will be cached once they are loaded.

       Returns
       -------

       ic : ImageCollection
           Collection of images.

    """

    intype = type(load_pattern)
    if intype is not list and intype is not str:
        raise TypeError("Input must be a filename or list of filenames")

    # Ensure we have a list, otherwise we'll end up iterating over the string:
    if intype is not list:
        load_pattern = [load_pattern]

    # Generate a list of filename/extension pairs by opening the list of
    # files and finding the image extensions in each one:
    ext_list = []
    for filename in load_pattern:
        hdulist = pyfits.open(filename)
        for n, hdu in zip(range(len(hdulist)), hdulist):
            if isinstance(hdu, pyfits.ImageHDU) or \
               isinstance(hdu, pyfits.PrimaryHDU):
                # Ignore (primary) header units with no data (use '.size'
                # rather than '.data' to avoid actually loading the image):
                try:
                    data_size = hdu.size()
                except TypeError:  # (size changed to int in PyFITS 3.1)
                    data_size = hdu.size
                if data_size > 0:
                    ext_list.append((filename, n))
        hdulist.close()

    return io.ImageCollection(ext_list, load_func=FITSFactory,
                              conserve_memory=conserve_memory)


def FITSFactory(image_ext):
    """Load an image extension from a FITS file and return a NumPy array
    
    Parameters
    ----------

    image_ext : tuple
        FITS extension to load, in the format ``(filename, ext_num)``.
        The FITS ``(extname, extver)`` format is unsupported, since this
        function is not called directly by the user and
        ``imread_collection()`` does the work of figuring out which
        extensions need loading.

    """

    # Expect a length-2 tuple with a filename as the first element:
    if not isinstance(image_ext, tuple):
        raise TypeError("Expected a tuple")

    if len(image_ext) != 2:
        raise ValueError("Expected a tuple of length 2")

    filename = image_ext[0]
    extnum = image_ext[1]

    if type(filename) is not str or type(extnum) is not int:
        raise ValueError("Expected a (filename, extension) tuple")

    hdulist = pyfits.open(filename)
        
    data = hdulist[extnum].data

    hdulist.close()

    if data is None:
        raise RuntimeError("Extension %d of %s has no data" %
                  (extnum, filename))

    return data

