# wrap VipsObject

import logging

import pyvips
from pyvips import ffi, vips_lib, gobject_lib, Error, _to_bytes, _to_string

logger = logging.getLogger(__name__)


class VipsObject(pyvips.GObject):
    """Manage a VipsObject."""
    __slots__ = ('vobject', 'gobject')
    _pspec_cache = {}

    def __init__(self, pointer):
        # logger.debug('VipsObject.__init__: pointer = %s', pointer)
        super(VipsObject, self).__init__(pointer)
        self.vobject = ffi.cast('VipsObject*', pointer)
        self.gobject = ffi.cast('GObject*', pointer)

    @staticmethod
    def print_all():
        """Print all objects.

        Print a table of all active libvips objects. Handy for debugging.

        """
        vips_lib.vips_object_print_all()

    def _get_pspec(self, name):
        # logger.debug('VipsObject.get_typeof: self = %s, name = %s',
        #              str(self), name)

        # this is pretty slow, and used a lot, so we cache results
        # this cache makes the libvips test suite about 10% faster
        class_pointer = self.gobject.g_type_instance.g_class
        cache = VipsObject._pspec_cache
        if class_pointer not in cache:
            cache[class_pointer] = {}
        if name not in cache[class_pointer]:
            pspec = ffi.new('GParamSpec **')
            argument_class = ffi.new('VipsArgumentClass **')
            argument_instance = ffi.new('VipsArgumentInstance **')
            result = vips_lib.vips_object_get_argument(self.vobject,
                                                       _to_bytes(name),
                                                       pspec, argument_class,
                                                       argument_instance)

            if result != 0:
                return None

            cache[class_pointer][name] = pspec[0]

        return cache[class_pointer][name]

    def get_typeof(self, name):
        """Get the GType of a GObject property.

        This function returns 0 if the property does not exist.

        """

        # logger.debug('VipsObject.get_typeof: self = %s, name = %s',
        #              str(self), name)

        pspec = self._get_pspec(name)
        if pspec is None:
            # need to clear any error, this is horrible
            Error('')
            return 0

        return pspec.value_type

    def get_blurb(self, name):
        """Get the blurb for a GObject property."""

        c_str = gobject_lib.g_param_spec_get_blurb(self._get_pspec(name))
        return _to_string(c_str)

    def get(self, name):
        """Get a GObject property.

        The value of the property is converted to a Python value.

        """

        logger.debug('VipsObject.get: name = %s', name)

        pspec = self._get_pspec(name)
        if pspec is None:
            raise Error('Property not found.')
        gtype = pspec.value_type

        gv = pyvips.GValue()
        gv.set_type(gtype)
        go = ffi.cast('GObject *', self.pointer)
        gobject_lib.g_object_get_property(go, _to_bytes(name), gv.pointer)

        return gv.get()

    def set(self, name, value):
        """Set a GObject property.

        The value is converted to the property type, if possible.

        """

        logger.debug('VipsObject.set: name = %s, value = %s', name, value)

        gtype = self.get_typeof(name)

        gv = pyvips.GValue()
        gv.set_type(gtype)
        gv.set(value)
        go = ffi.cast('GObject *', self.pointer)
        gobject_lib.g_object_set_property(go, _to_bytes(name), gv.pointer)

    def set_string(self, string_options):
        """Set a series of properties using a string.

        For example::

            'fred=12, tile'
            '[fred=12]'

        """

        cstr = _to_bytes(string_options)
        result = vips_lib.vips_object_set_from_string(self.vobject, cstr)

        return result == 0

    def get_description(self):
        """Get the description of a GObject."""

        return _to_string(vips_lib.vips_object_get_description(self.vobject))


__all__ = ['VipsObject']
