/* abstract base class for all vips objects
 */

/*

    Copyright (C) 1991-2003 The National Gallery

    This library 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 2.1 of the License, or (at your option) any later version.

    This library 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 library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301  USA

 */

/*

    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk

 */

#ifndef VIPS_OBJECT_H
#define VIPS_OBJECT_H

#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/

/* Handy!
 */
#ifdef VIPS_DEBUG
#define VIPS_UNREF( X ) G_STMT_START { \
	if( X ) { \
		g_assert( G_OBJECT( X )->ref_count > 0 ); \
		g_object_unref( X ); \
		(X) = 0; \
	} \
} G_STMT_END
#else /*!VIPS_DEBUG*/
#define VIPS_UNREF( X ) VIPS_FREEF( g_object_unref, (X) )
#endif /*VIPS_DEBUG*/

typedef struct _VipsObject VipsObject;
typedef struct _VipsObjectClass VipsObjectClass;

/* Track extra stuff for arguments to objects
 */

typedef enum /*< flags >*/ {
	VIPS_ARGUMENT_NONE = 0,
	VIPS_ARGUMENT_REQUIRED = 1,
	VIPS_ARGUMENT_CONSTRUCT = 2,
	VIPS_ARGUMENT_SET_ONCE = 4,
	VIPS_ARGUMENT_SET_ALWAYS = 8,
	VIPS_ARGUMENT_INPUT = 16,
	VIPS_ARGUMENT_OUTPUT = 32,
	VIPS_ARGUMENT_DEPRECATED = 64,
	VIPS_ARGUMENT_MODIFY = 128
} VipsArgumentFlags;

/* Useful flag combinations. User-visible ones are:

VIPS_ARGUMENT_REQUIRED_INPUT 	Eg. the "left" argument for an add operation

VIPS_ARGUMENT_OPTIONAL_INPUT 	Eg. the "caption" for an object

VIPS_ARGUMENT_REQUIRED_OUTPUT  	Eg. the "result" of an add operation

VIPS_ARGUMENT_OPTIONAL_OUTPUT   Eg. the x pos of the image minimum

   Other combinations are used internally, eg. supplying the cast-table for an 
   arithmetic operation

 */

#define VIPS_ARGUMENT_REQUIRED_INPUT \
	(VIPS_ARGUMENT_INPUT | \
	 VIPS_ARGUMENT_REQUIRED | \
	 VIPS_ARGUMENT_CONSTRUCT) 

#define VIPS_ARGUMENT_OPTIONAL_INPUT \
	(VIPS_ARGUMENT_INPUT | \
	 VIPS_ARGUMENT_CONSTRUCT)

#define VIPS_ARGUMENT_REQUIRED_OUTPUT \
	(VIPS_ARGUMENT_OUTPUT | \
	 VIPS_ARGUMENT_REQUIRED | \
	 VIPS_ARGUMENT_CONSTRUCT)

#define VIPS_ARGUMENT_OPTIONAL_OUTPUT \
	(VIPS_ARGUMENT_OUTPUT | \
	 VIPS_ARGUMENT_CONSTRUCT)

#define VIPS_ARG_IMAGE( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_object( (NAME), (LONG), (DESC),  \
		VIPS_TYPE_IMAGE, \
		(GParamFlags) (G_PARAM_READWRITE) ); \
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_INTERPOLATE( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_object( (NAME), (LONG), (DESC),  \
		VIPS_TYPE_INTERPOLATE, \
		(GParamFlags) (G_PARAM_READWRITE) ); \
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_BOOL( CLASS, NAME, PRIORITY, LONG, DESC, \
	FLAGS, OFFSET, VALUE ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_boolean( (NAME), (LONG), (DESC), \
		(VALUE), \
		(GParamFlags) (G_PARAM_READWRITE) ); \
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_DOUBLE( CLASS, NAME, PRIORITY, LONG, DESC, \
	FLAGS, OFFSET, MIN, MAX, VALUE ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_double( (NAME), (LONG), (DESC), \
		(MIN), (MAX), (VALUE), \
		(GParamFlags) (G_PARAM_READWRITE) );\
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_BOXED( CLASS, NAME, PRIORITY, LONG, DESC, \
	FLAGS, OFFSET, TYPE ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_boxed( (NAME), (LONG), (DESC), \
		(TYPE), \
		(GParamFlags) (G_PARAM_READWRITE) );\
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_INT( CLASS, NAME, PRIORITY, LONG, DESC, \
	FLAGS, OFFSET, MIN, MAX, VALUE ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_int( (NAME), (LONG), (DESC), \
		(MIN), (MAX), (VALUE), \
		(GParamFlags) (G_PARAM_READWRITE) );\
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_UINT64( CLASS, NAME, PRIORITY, LONG, DESC, \
	FLAGS, OFFSET, MIN, MAX, VALUE ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_uint64( (NAME), (LONG), (DESC), \
		(MIN), (MAX), (VALUE), \
		(GParamFlags) (G_PARAM_READWRITE) );\
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_ENUM( CLASS, NAME, PRIORITY, LONG, DESC, \
	FLAGS, OFFSET, TYPE, VALUE ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_enum( (NAME), (LONG), (DESC), \
		(TYPE), (VALUE), \
		(GParamFlags) (G_PARAM_READWRITE) );\
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_FLAGS( CLASS, NAME, PRIORITY, LONG, DESC, \
	FLAGS, OFFSET, TYPE, VALUE ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_flags( (NAME), (LONG), (DESC), \
		(TYPE), (VALUE), \
		(GParamFlags) (G_PARAM_READWRITE) );\
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_STRING( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, \
	VALUE ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_string( (NAME), (LONG), (DESC), \
		(VALUE), \
		(GParamFlags) (G_PARAM_READWRITE) ); \
	g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

#define VIPS_ARG_POINTER( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET ) { \
	GParamSpec *pspec; \
	\
	pspec = g_param_spec_pointer( (NAME), (LONG), (DESC), \
		(GParamFlags) (G_PARAM_READWRITE) ); \
	g_object_class_install_property( gobject_class,  \
		vips_argument_get_id(), pspec ); \
	vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \
		pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET) ); \
}

/* Keep one of these for every argument.
 */
typedef struct _VipsArgument {
	GParamSpec *pspec;	/* pspec for this argument */

	/* More stuff, see below */
} VipsArgument;

/* Keep one of these in the class struct for every argument.
 */
typedef struct _VipsArgumentClass {
	VipsArgument parent;

	/* The class of the object we are an arg for.
	 */
	VipsObjectClass *object_class;

	VipsArgumentFlags flags;
	int priority;		/* Order args by this */
	guint offset;		/* G_STRUCT_OFFSET of member in object */
} VipsArgumentClass;

/* Keep one of these in the object struct for every argument instance.
 */
typedef struct _VipsArgumentInstance {
	VipsArgument parent;

	/* The class we are part of.
	 */
	VipsArgumentClass *argument_class;

	/* The object we are attached to.
	 */
	VipsObject *object;

	/* Has been set.
	 */
	gboolean assigned;

	/* If this is an output argument, keep the id of our "close" handler
	 * here.
	 */
	gulong close_id;	

	/* We need to listen for "invalidate" on input images and send our own
	 * "invalidate" out. If we go, we need to disconnect.
	 */
	gulong invalidate_id;
} VipsArgumentInstance;

/* Need to look up our VipsArgument structs from a pspec. Just hash the
 * pointer (ie. we assume pspecs are never shared, is this correct?)
 */
typedef GHashTable VipsArgumentTable;

int vips_argument_get_id( void );
void vips__object_set_member( VipsObject *object, GParamSpec *pspec,
	GObject **member, GObject *argument );
typedef void *(*VipsArgumentMapFn)( VipsObject *object, GParamSpec *pspec,
	VipsArgumentClass *argument_class, 
	VipsArgumentInstance *argument_instance, void *a, void *b );
void *vips_argument_map( VipsObject *object, 
	VipsArgumentMapFn fn, void *a, void *b );
int vips_object_get_args( VipsObject *object, 
	const char ***names, int **flags, int *n_args );
typedef void *(*VipsArgumentClassMapFn)( VipsObjectClass *object_class, 
	GParamSpec *pspec,
	VipsArgumentClass *argument_class, void *a, void *b );
void *vips_argument_class_map( VipsObjectClass *object_class, 
	VipsArgumentClassMapFn fn, void *a, void *b );
gboolean vips_argument_class_needsstring( VipsArgumentClass *argument_class );
int vips_object_get_argument( VipsObject *object, const char *name,
	GParamSpec **pspec,
	VipsArgumentClass **argument_class,
	VipsArgumentInstance **argument_instance );
gboolean vips_object_argument_isset( VipsObject *object, const char *name );
VipsArgumentFlags vips_object_get_argument_flags( VipsObject *object, 
	const char *name );
int vips_object_get_argument_priority( VipsObject *object, const char *name );

/* We have to loop over an objects args in several places, and we can't always
 * use vips_argument_map(), the preferred looper. Have the loop code as a
 * macro as well for these odd cases.
 */
#define VIPS_ARGUMENT_FOR_ALL( OBJECT, PSPEC, ARG_CLASS, ARG_INSTANCE ) { \
	VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( OBJECT ); \
	GSList *p; \
 	\
	for( p = object_class->argument_table_traverse; p; p = p->next ) { \
		VipsArgumentClass *ARG_CLASS = \
			(VipsArgumentClass *) p->data; \
		VipsArgument *argument = (VipsArgument *) argument_class; \
		GParamSpec *PSPEC = argument->pspec; \
		VipsArgumentInstance *ARG_INSTANCE __attribute__ ((unused)) = \
			vips__argument_get_instance( argument_class, \
			VIPS_OBJECT( OBJECT ) ); \

#define VIPS_ARGUMENT_FOR_ALL_END } }

/* And some macros to collect args from a va list. 
 *
 * Use something like this:

	GParamSpec *pspec;
	VipsArgumentClass *argument_class;
	VipsArgumentInstance *argument_instance;

	if( vips_object_get_argument( VIPS_OBJECT( operation ), name,
		&pspec, &argument_class, &argument_instance ) )
		return( -1 );

	VIPS_ARGUMENT_COLLECT_SET( pspec, argument_class, ap );

		GValue value holds the value of an input argument, do 
		something with it

	VIPS_ARGUMENT_COLLECT_GET( pspec, argument_class, ap );

		void **arg points to where to write an output argument

	VIPS_ARGUMENT_COLLECT_END
 
 */
#define VIPS_ARGUMENT_COLLECT_SET( PSPEC, ARG_CLASS, AP ) \
	if( (ARG_CLASS->flags & VIPS_ARGUMENT_INPUT) ) { \
		GValue value = { 0, }; \
		gchar *error = NULL; \
 		\
		/* Input args are given inline, eg. ("factor", 12.0)  \
		 * and must be collected. \
		 */ \
		g_value_init( &value, G_PARAM_SPEC_VALUE_TYPE( PSPEC ) ); \
		G_VALUE_COLLECT( &value, AP, 0, &error ); \
		\
		/* Don't bother with the error message. \
		 */ \
		if( error ) { \
			VIPS_DEBUG_MSG( "VIPS_OBJECT_COLLECT_SET: err\n" ); \
			g_free( error ); \
		}

#define VIPS_ARGUMENT_COLLECT_GET( PSPEC, ARG_CLASS, AP ) \
		g_value_unset( &value ); \
	} \
	else if( (ARG_CLASS->flags & VIPS_ARGUMENT_OUTPUT) ) { \
		void **arg __attribute__ ((unused)); \
 		\
		/* Output args are a pointer to where to send the \
		 * result. \
		 */ \
		arg = va_arg( AP, void ** ); 

#define VIPS_ARGUMENT_COLLECT_END \
	} 

#define VIPS_TYPE_OBJECT (vips_object_get_type())
#define VIPS_OBJECT( obj ) \
	(G_TYPE_CHECK_INSTANCE_CAST( (obj), VIPS_TYPE_OBJECT, VipsObject ))
#define VIPS_OBJECT_CLASS( klass ) \
	(G_TYPE_CHECK_CLASS_CAST( (klass), VIPS_TYPE_OBJECT, VipsObjectClass))
#define VIPS_IS_OBJECT( obj ) \
	(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_OBJECT ))
#define VIPS_IS_OBJECT_CLASS( klass ) \
	(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_OBJECT ))
#define VIPS_OBJECT_GET_CLASS( obj ) \
	(G_TYPE_INSTANCE_GET_CLASS( (obj), VIPS_TYPE_OBJECT, VipsObjectClass ))

struct _VipsObject {
	GObject parent_instance;

	/* Set after ->build() has run succesfully: construct is fully done
	 * and checked.
	 */
	gboolean constructed;

	/* Set for static objects which are allocated at startup and never
	 * freed. These objects are ommitted from leak reports.
	 */
	gboolean static_object;

	/* Table of argument instances for this class and any derived classes.
	 */
	VipsArgumentTable *argument_table;

	/* Class properties (see below), duplicated in the instance so we can
	 * get at them easily via the property system.
	 */
	char *nickname;
	char *description;

	/* The pre/post/close callbacks are all fire-once. 
	 */
	gboolean preclose;
	gboolean close;
	gboolean postclose;

	/* Total memory allocated relative to this object, handy for
	 * profiling.
	 */
	size_t local_memory;

};

struct _VipsObjectClass {
	GObjectClass parent_class;

	/* Build the object ... all argument properties have been set,
	 * now build the thing.
	 */
	int (*build)( VipsObject *object );

	/* Just after build ... the object is fully ready for work. 
	 */
	int (*postbuild)( VipsObject *object );

	/* Try to print something about the class, handy for help displays.
	 * Keep to one line.
	 */
	void (*summary_class)( struct _VipsObjectClass *cls, VipsBuf *buf );

	/* Try to print a one-line summary for the object, the user can see
	 * this output via things like "header fred.tif", --vips-cache-trace,
	 * etc. 
	 */
	void (*summary)( VipsObject *object, VipsBuf *buf );

	/* Try to print everything about the object, handy for debugging.
	 */
	void (*dump)( VipsObject *object, VipsBuf *buf );

	/* Sanity-check the object. Print messages and stuff. 
	 * Handy for debugging.
	 */
	void (*sanity)( VipsObject *object, VipsBuf *buf );

	/* Rewind. Save and restore any stuff that needs to survive a
	 * dispose().
	 */
	void (*rewind)( VipsObject *object );

	/* Just before close, everything is still alive.
	 */
	void (*preclose)( VipsObject *object );

	/* Close, time to free stuff.
	 */
	void (*close)( VipsObject *object );

	/* Post-close, everything is dead, except the VipsObject pointer.
	 * Useful for eg. deleting the file associated with a temp image.
	 */
	void (*postclose)( VipsObject *object );

	/* The CLI interface. Implement these four to get CLI input and output
	 * for your object.
	 */

	/* Given a command-line arg (eg. a filename), make an instance of the
	 * object. Just do the g_object_new(), don't call _build().
	 *
	 * Don't call this directly, see vips_object_new_from_string().
	 */
	VipsObject *(*new_from_string)( const char *string );

	/* The inverse of ^^. Given an object, output what ->new_from_string()
	 * would have been given to make that object. 
	 */
	void (*to_string)( VipsObject *object, VipsBuf *buf ); 

	/* Does this output arg need an arg from the command line? Image
	 * output, for example, needs a filename to write to.
	 */
	gboolean output_needs_arg;

	/* Write the object to the string. Return 0 for success, or -1 on
	 * error, setting vips_error(). string is NULL if output_needs_arg()
	 * was FALSE.
	 */
	int (*output_to_arg)( VipsObject *object, const char *string );

	/* Class nickname, eg. "VipsInterpolateBicubic" has "bicubic" as a
	 * nickname. Not internationalised. 
	 */
	const char *nickname;

	/* Class description. Used for help messages, so internationalised.
	 */
	const char *description;

	/* Hash from pspec to VipsArgumentClass.
	 *
	 * This records the VipsArgumentClass for every pspec used in 
	 * VipsObject and any subclass (ie. everywhere), so it's huge. Don't
	 * loop over this hash! Fine for lookups though.
	 */
	VipsArgumentTable *argument_table;

	/* A sorted (by priority) list of the VipsArgumentClass for this class 
	 * and any superclasses. This is small and specific to this class.
	 *
	 * Use the stored GType to work out when to restart the list for a
	 * subclass.
	 */
	GSList *argument_table_traverse;
	GType argument_table_traverse_gtype;

	/* This class is deprecated and therefore hidden from various UI bits.
	 *
	 * VipsOperation has a deprecated flag, use that in preference to this
	 * if you can. 
	 */
	gboolean deprecated;

	/* Reserved for future expansion.
	 */
	void (*_vips_reserved1)( void ); 
	void (*_vips_reserved2)( void ); 
	void (*_vips_reserved3)( void ); 
	void (*_vips_reserved4)( void ); 
};

gboolean vips_value_is_null( GParamSpec *psoec, const GValue *value );
void vips_object_set_property( GObject *gobject, 
	guint property_id, const GValue *value, GParamSpec *pspec );
void vips_object_get_property( GObject *gobject, 
	guint property_id, GValue *value, GParamSpec *pspec );

void vips_object_preclose( VipsObject *object );
int vips_object_build( VipsObject *object );

void vips_object_summary_class( VipsObjectClass *klass, VipsBuf *buf );
void vips_object_summary( VipsObject *object, VipsBuf *buf );
void vips_object_dump( VipsObject *object, VipsBuf *buf );

void vips_object_print_summary_class( VipsObjectClass *klass );
void vips_object_print_summary( VipsObject *object );
void vips_object_print_dump( VipsObject *object );
void vips_object_print_name( VipsObject *object );

gboolean vips_object_sanity( VipsObject *object );

/* Don't put spaces around void here, it breaks gtk-doc.
 */
GType vips_object_get_type(void);

void vips_object_class_install_argument( VipsObjectClass *cls, 
	GParamSpec *pspec, VipsArgumentFlags flags, 
	int priority, guint offset );
int vips_object_set_argument_from_string( VipsObject *object, 
	const char *name, const char *value );
gboolean vips_object_argument_needsstring( VipsObject *object, 
	const char *name );
int vips_object_get_argument_to_string( VipsObject *object, 
	const char *name, const char *arg );
int vips_object_set_required( VipsObject *object, const char *value );

typedef void *(*VipsObjectSetArguments)( VipsObject *object, void *a, void *b );
VipsObject *vips_object_new( GType type, 
	VipsObjectSetArguments set, void *a, void *b );

int vips_object_set_valist( VipsObject *object, va_list ap );
int vips_object_set( VipsObject *object, ... )
	__attribute__((sentinel));
int vips_object_set_from_string( VipsObject *object, const char *string );

VipsObject *vips_object_new_from_string( VipsObjectClass *object_class, 
	const char *p );
void vips_object_to_string( VipsObject *object, VipsBuf *buf );

void *vips_object_map( VipsSListMap2Fn fn, void *a, void *b );

typedef void *(*VipsTypeMapFn)( GType type, void *a );
typedef void *(*VipsTypeMap2Fn)( GType type, void *a, void *b );
typedef void *(*VipsClassMapFn)( VipsObjectClass *cls, void *a );
void *vips_type_map( GType base, VipsTypeMap2Fn fn, void *a, void *b );
void *vips_type_map_all( GType base, VipsTypeMapFn fn, void *a );
int vips_type_depth( GType type );
GType vips_type_find( const char *basename, const char *nickname );
const char *vips_nickname_find( GType type );

void *vips_class_map_all( GType type, VipsClassMapFn fn, void *a );
const VipsObjectClass *vips_class_find( const char *basename, 
	const char *nickname );

VipsObject **vips_object_local_array( VipsObject *parent, int n );

void vips_object_local_cb( VipsObject *vobject, GObject *gobject );
#define vips_object_local( V, G ) \
	(g_signal_connect( V, "close", G_CALLBACK( vips_object_local_cb ), G ))

void vips_object_set_static( VipsObject *object, gboolean static_object );
void vips_object_print_all( void );
void vips_object_sanity_all( void );

void vips_object_rewind( VipsObject *object );

void vips_object_unref_outputs( VipsObject *object );

const char *vips_object_get_description( VipsObject *object );

#ifdef __cplusplus
}
#endif /*__cplusplus*/

#endif /*VIPS_OBJECT_H*/