# Copyright (C) 2007-2015 various contributors (see AUTHORS)
#
# This file is part of Python-EFL.
#
# Python-EFL is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# Python-EFL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this Python-EFL.  If not, see <http://www.gnu.org/licenses/>.

"""

:mod:`efl.ethumb` Module
########################

.. versionadded:: 1.17

    
Classes
=======

.. toctree::

   class-ethumb.rst


Enumerations
============

.. _Ethumb_Thumb_FDO_Size:

Ethumb_Thumb_FDO_Size
---------------------

.. data:: ETHUMB_THUMB_NORMAL

    128x128 as defined by FreeDesktop.Org standard 

.. data:: ETHUMB_THUMB_LARGE

    256x256 as defined by FreeDesktop.Org standard 


.. _Ethumb_Thumb_Format:

Ethumb_Thumb_Format
-------------------

.. data:: ETHUMB_THUMB_FDO

    PNG as defined by FreeDesktop.Org standard. 

.. data:: ETHUMB_THUMB_JPEG

    JPEGs are often smaller and faster to read/write. 

.. data:: ETHUMB_THUMB_EET 

    EFL's own storage system, supports key parameter.


.. _Ethumb_Thumb_Aspect:

Ethumb_Thumb_Aspect
-------------------

.. data:: ETHUMB_THUMB_KEEP_ASPECT

    Keep original proportion between width and height

.. data:: ETHUMB_THUMB_IGNORE_ASPECT 

    Ignore aspect and foce it to match thumbnail's width and height 

.. data:: ETHUMB_THUMB_CROP 

    keep aspect but crop (cut) the largest dimension


.. _Ethumb_Thumb_Orientation:

Ethumb_Thumb_Orientation
------------------------

.. data:: ETHUMB_THUMB_ORIENT_NONE 

    Keep orientation as pixel data is 

.. data:: ETHUMB_THUMB_ROTATE_90_CW 

    Rotate 90° clockwise 

.. data:: ETHUMB_THUMB_ROTATE_180 

    Rotate 180° 

.. data:: ETHUMB_THUMB_ROTATE_90_CCW 

    Rotate 90° counter-clockwise 

.. data:: ETHUMB_THUMB_FLIP_HORIZONTAL 

    Flip horizontally 

.. data:: ETHUMB_THUMB_FLIP_VERTICAL 

    Flip vertically 

.. data:: ETHUMB_THUMB_FLIP_TRANSPOSE 

    Transpose

.. data:: ETHUMB_THUMB_FLIP_TRANSVERSE 

    Transverse

.. data:: ETHUMB_THUMB_ORIENT_ORIGINAL 

    Use orientation from metadata (EXIF-only currently) 


Module level functions
======================

"""

from libc.stdint cimport uintptr_t
from cpython cimport Py_INCREF, Py_DECREF, PyUnicode_AsUTF8String

from efl.eina cimport Eina_Bool
from efl.utils.conversions cimport _ctouni
from efl.c_ethumb cimport Ethumb as cEthumb, Ethumb_Thumb_FDO_Size, \
    Ethumb_Thumb_Format, Ethumb_Thumb_Aspect, Ethumb_Thumb_Orientation, \
    ethumb_init, ethumb_shutdown, \
    ethumb_new, ethumb_free, ethumb_file_set, ethumb_file_get, ethumb_file_free, \
    ethumb_thumb_path_set, ethumb_thumb_path_get, ethumb_exists, ethumb_generate, \
    ethumb_frame_set, ethumb_frame_get, ethumb_thumb_dir_path_set, \
    ethumb_thumb_dir_path_get, ethumb_thumb_category_set, \
    ethumb_thumb_category_get, ethumb_thumb_fdo_set, ethumb_thumb_size_set, \
    ethumb_thumb_size_get, ethumb_thumb_format_set, ethumb_thumb_format_get, \
    ethumb_thumb_aspect_set, ethumb_thumb_aspect_get, ethumb_thumb_orientation_set, \
    ethumb_thumb_orientation_get, ethumb_thumb_crop_align_set, \
    ethumb_thumb_crop_align_get, ethumb_thumb_quality_set, ethumb_thumb_quality_get, \
    ethumb_thumb_compress_set, ethumb_thumb_compress_get, \
    ethumb_video_start_set, ethumb_video_start_get, ethumb_video_time_set, \
    ethumb_video_time_get, ethumb_video_interval_set, ethumb_video_interval_get, \
    ethumb_video_ntimes_set, ethumb_video_ntimes_get, ethumb_video_fps_set, \
    ethumb_video_fps_get, ethumb_document_page_set, ethumb_document_page_get

import atexit
import traceback


cdef void _generate_cb(void *data, cEthumb *e, Eina_Bool success) with gil:
    obj = <object>data
    (self, func, args, kargs) = obj
    try:
        func(self, bool(success), *args, **kargs)
    except Exception:
        traceback.print_exc()

cdef void _generate_free_cb(void *data) with gil:
    obj = <object>data
    Py_DECREF(obj)


def init():
    """ Initialize the ethumb library.

    .. note:: You never need to call this function, it is automatically called
              on module import.

    """
    return ethumb_init()

def shutdown():
    """ Shutdown the ethumb library.

    .. note:: You never need to call this function, it is automatically called
              at exit.

    """
    ethumb_shutdown()


cdef class Ethumb(object):
    """

    Ethumb thumbnail generator.

    .. versionadded:: 1.17

    Use this class to generate thumbnails in the local process.

    .. seealso:: :class:`~efl.ethumb_client.EthumbClient` to generate thumbnails
        using a server (recommended).

    """
    def __cinit__(self):
        self.obj = NULL

    def __init__(self):
        """ Ethumb constructor. """
        assert self.obj == NULL, "Object must be clean"
        self.obj = ethumb_new()
        if self.obj == NULL:
            raise SystemError("Error creating the ethumb object.")

    def __repr__(self):
        return ("<%s object at %#x (file='%s', thumb='%s')>") % (
            type(self).__name__, <uintptr_t><void *>self,
            self.file[0], self.thumb_path[0])

    def delete(self):
        """ Delete the underlying C object.

        .. note:: You MUST call this function when you don't need the object
                  anymore, as it will free all internal used resources.

        """
        ethumb_free(self.obj)

    def file_free(self):
        """ Reset the source file information. """
        ethumb_file_free(self.obj)

    def exists(self):
        """ Test if the thumbnail already exists.

        :return: ``True`` if thumbnail exists, ``False`` otherwise

        """
        return bool(ethumb_exists(self.obj))

    def generate(self, func, *args, **kargs):
        """ Generate the thumbnail. 

        Thumbnail generation is asynchronous and depend on ecore main
        loop running. Given function will be called back with
        generation status if True is returned by this call. If False
        is returned, given function will not be called.

        Existing thumbnails will be overwritten with this call. Check
        if they already exist with :func:`exists` before calling.

        :param func: function to call on generation completion, even
            if failed or succeeded. Signature is::

                func(Ethumb, success, *args, **kargs)

            with success being ``True`` for successful generation or
            ``False`` on failure.

        :return: ``True`` on success and ``False`` on failure 

        :raise TypeError: if **func** is not callable.

        """
        cdef:
            tuple func_data

        if not callable(func):
            raise TypeError("func must be callable")

        func_data = (self, func, args, kargs)
        if ethumb_generate(self.obj, _generate_cb, <void*>func_data,
                           _generate_free_cb) != 0:
            Py_INCREF(func_data)
            return True
        else:
            return False

    ## source file properties
    property file:
        """ The file to thumbnail.

        This is a tuple of 2 strings: ``path`` and ``key``.

        ``path``: Is the file to use.

        ``key``: If path allows storing multiple resources in a single file
        (EET or Edje for instance), this is the name used to locate the right
        resource inside the file.

        For convenience you can also assign a single string value (``path``),
        ignoring the key.

        :type: **str** or (**str**, **str**)

        :raise RuntimeError: on failure setting the property

        """
        def __set__(self, value):
            if isinstance(value, tuple):
                path, key = value
            else:
                path, key = value, None
            if isinstance(path, unicode): path = PyUnicode_AsUTF8String(path)
            if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
            if ethumb_file_set(self.obj,
                    <const char *>path if path is not None else NULL,
                    <const char *>key if key is not None else NULL) == 0:
                raise RuntimeError("Cannot set file")

        def __get__(self):
            cdef:
                const char *path
                const char *key
            ethumb_file_get(self.obj, &path, &key)
            return (_ctouni(path), _ctouni(key))

    property frame:
        """ The optional edje file used to generate a frame around the thumbnail

        This can be used to simulate frames (wood, polaroid, etc) in the
        generated thumbnails.

        :type: (**str**, **str**, **str**): (theme_file, group_name, swallow_name)

        :raise RuntimeError: on failure setting the property

        """
        def __set__(self, tuple value):
            theme, group, swallow = value
            if isinstance(theme, unicode): theme = PyUnicode_AsUTF8String(theme)
            if isinstance(group, unicode): group = PyUnicode_AsUTF8String(group)
            if isinstance(swallow, unicode): swallow = PyUnicode_AsUTF8String(swallow)
            if ethumb_frame_set(self.obj,
                    <const char *>theme if theme is not None else NULL,
                    <const char *>group if group is not None else NULL,
                    <const char *>swallow if swallow is not None else NULL) == 0:
                raise RuntimeError("Cannot set frame")

        def __get__(self):
            cdef:
                const char *theme
                const char *group
                const char *swallow
            ethumb_frame_get(self.obj, &theme, &group, &swallow)
            return _ctouni(theme), _ctouni(group), _ctouni(swallow)

    # destination thumb properties
    property thumb_path:
        """ The complete path of the generated thumbnail.

        This is a tuple of 2 strings: ``path`` and ``key``.

        ``path``: Is the complete file path.

        ``key``: If path allows storing multiple resources in a single file
        (EET or Edje for instance), this is the name used to locate the right
        resource inside the file.

        For convenience you can also assign a single string value (``path``),
        ignoring the key.

        :type: **str** or (**str**, **str**)

        """
        def __set__(self, value):
            if isinstance(value, tuple):
                path, key = value
            else:
                path, key = value, None
            if isinstance(path, unicode): path = PyUnicode_AsUTF8String(path)
            if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
            ethumb_thumb_path_set(self.obj,
                    <const char *>path if path is not None else NULL,
                    <const char *>key if key is not None else NULL)

        def __get__(self):
            cdef:
                const char *path
                const char *key
            ethumb_thumb_path_get(self.obj, &path, &key)
            return (_ctouni(path), _ctouni(key))

    property thumb_dir_path:
        """ Destination folder for the thumbnails.

        This is the base folder, a category folder is added to this path
        as a sub directory. Default is ``~/.thumbnails``

        :type: **str**

        """
        def __set__(self, path):
            if isinstance(path, unicode): path = PyUnicode_AsUTF8String(path)
            ethumb_thumb_dir_path_set(self.obj,
                    <const char *>path if path is not None else NULL)

        def __get__(self):
            cdef const char *path
            path = ethumb_thumb_dir_path_get(self.obj)
            return _ctouni(path)

    property thumb_category:
        """ The thumbnails category

        Category sub directory to store thumbnail. Default is either "normal"
        or "large" for FDO compliant thumbnails or
        ``WIDTHxHEIGHT-ASPECT[-FRAMED]-FORMAT``. It can be a string or None to
        use auto generated names.

        :type: **str**

        """
        def __set__(self, cat):
            if isinstance(cat, unicode): cat = PyUnicode_AsUTF8String(cat)
            ethumb_thumb_category_set(self.obj,
                    <const char *>cat if cat is not None else NULL)

        def __get__(self):
            return _ctouni(ethumb_thumb_category_get(self.obj))

    property thumb_fdo:
        """ Set a standard FDO thumbnail size

        This is a preset to provide freedesktop.org (fdo) standard
        compliant thumbnails. That is, files are stored as JPEG under
        ~/.thumbnails/SIZE, with size being either normal (128x128) or
        large (256x256).

        :type: :ref:`Ethumb_Thumb_FDO_Size` **writeonly**

        """
        def __set__(self, Ethumb_Thumb_FDO_Size value):
            ethumb_thumb_fdo_set(self.obj, value)

    property thumb_size:
        """ The size of thumbnails.

        :type: (int **width**, int **height**)

        """
        def __set__(self, tuple value):
            w, h = value
            ethumb_thumb_size_set(self.obj, w, h)

        def __get__(self):
            cdef int w, h
            ethumb_thumb_size_get(self.obj, &w, &h)
            return w, h

    property thumb_format:
        """ The fileformat for the thumbnails.

        Thumbnails are compressed; possible formats are PNG, JPEG and EET.

        :type: :ref:`Ethumb_Thumb_Format`

        """
        def __set__(self, Ethumb_Thumb_Format value):
            ethumb_thumb_format_set(self.obj, value)

        def __get__(self):
            return ethumb_thumb_format_get(self.obj)

    property thumb_aspect:
        """ The aspect ratio policy.

        When the source and thumbnail aspect ratios don't match, this policy
        sets how to adapt from the former to the latter: resize keeping source
        aspect ratio, resize ignoring it or crop.

        :type: :ref:`Ethumb_Thumb_Aspect`

        """
        def __set__(self, Ethumb_Thumb_Aspect value):
            ethumb_thumb_aspect_set(self.obj, value)

        def __get__(self):
            return ethumb_thumb_aspect_get(self.obj)

    property thumb_orientation:
        """ The thumbnail rotation or flip.

        :type: :ref:`Ethumb_Thumb_Orientation`

        """
        def __set__(self, Ethumb_Thumb_Orientation value):
            ethumb_thumb_orientation_set(self.obj, value)

        def __get__(self):
            return ethumb_thumb_orientation_get(self.obj)

    property thumb_crop_align:
        """ Crop alignment in use.

        :param x: horizontal alignment. 0.0 means left side will be
                  visible or right side is being lost. 1.0 means right side
                  will be visible or left side is being lost. 0.5 means just
                  center is visible, both sides will be lost. Default is 0.5.
        :param y: vertical alignment. 0.0 is top visible, 1.0 is
                  bottom visible, 0.5 is center visible. Default is 0.5

        :type: (float **x**, float **y**)

        """
        def __set__(self, tuple value):
            x, y = value
            ethumb_thumb_crop_align_set(self.obj, x, y)

        def __get__(self):
            cdef:
                float x
                float y
            ethumb_thumb_crop_align_get(self.obj, &x, &y)
            return x, y

    property thumb_quality:
        """ The thumbnail compression quality.

        Value from 0 to 100, default is 80. The effect depends on the format
        being used, PNG will not use it.

        :type: int

        """
        def __set__(self, int value):
            ethumb_thumb_quality_set(self.obj, value)

        def __get__(self):
            return ethumb_thumb_quality_get(self.obj)

    property thumb_compress:
        """ The thumbnail compression rate.

        Value from 0 to 9, default is 9. The effect depends on the format being
        used, JPEG will not use it.

        :type: int

        """
        def __set__(self, int value):
            ethumb_thumb_compress_set(self.obj, value)

        def __get__(self):
            return ethumb_thumb_compress_get(self.obj)

    ## video related
    property video_start:
        """ The start point for video thumbnails.

        :type: float (from 0.0 to 1.0)

        """
        def __set__(self, float value):
            ethumb_video_start_set(self.obj, value)

        def __get__(self):
            return ethumb_video_start_get(self.obj)

    property video_time:
        """ The video time (duration) in seconds.

        :type: float

        """
        def __set__(self, float value):
            ethumb_video_time_set(self.obj, value)

        def __get__(self):
            return ethumb_video_time_get(self.obj)

    property video_interval:
        """ The video frame interval, in seconds.

        This is useful for animated thumbnail and will define skip time before
        going to the next frame.

        .. note:: that video backends might not be able to
                  precisely skip that amount as it will depend on various
                  factors, including video encoding.
 
        :type: float

        """
        def __set__(self, float value):
            ethumb_video_interval_set(self.obj, value)

        def __get__(self):
            return ethumb_video_interval_get(self.obj)

    property video_ntimes:
        """ The number of times the video loops (if applicable).

        :type: int

        """
        def __set__(self, int value):
            ethumb_video_ntimes_set(self.obj, value)

        def __get__(self):
            return ethumb_video_ntimes_get(self.obj)

    property video_fps:
        """ The thumbnail framerate.

        Default to 10.

        :type: int

        """
        def __set__(self, int value):
            ethumb_video_fps_set(self.obj, value)

        def __get__(self):
            return ethumb_video_fps_get(self.obj)

    ## document
    property document_page:
        """ The page number to thumbnail in paged documents.

        :type: int

        """
        def __set__(self, int value):
            ethumb_document_page_set(self.obj, value)

        def __get__(self):
            return ethumb_document_page_get(self.obj)

init()
atexit.register(shutdown)
