/*  Inti: Integrated Foundation Classes
 *  Copyright (C) 2002-2003 The Inti Development Team.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

//! @file inti/gdk-pixbuf/pixbuf-loader.h
//! @brief A GdkPixbufLoader C++ wrapper interface.
//!
//! PixbufLoader is an object that provides application-driven progressive image loading.

#ifndef INTI_GDK_PIXBUF_LOADER_H
#define INTI_GDK_PIXBUF_LOADER_H

#ifndef INTI_G_OBJECT_H
#include <inti/glib/object.h>
#endif

#ifndef GDK_PIXBUF_H
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif

#ifndef GDK_PIXBUF_LOADER_H
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
#endif

namespace Inti {

namespace G {
class Error;
}

namespace Gdk {
	
class Pixbuf;
class PixbufAnimation;
class PixbufFormat;
class PixbufLoaderClass;

//! @class PixbufLoader pixbuf-loader.h inti/gdk-pixbuf/pixbuf-loader.h
//! @brief A GdkPixbufLoader C++ wrapper class.
//!
//! PixbufLoader provides a way for applications to drive the process of loading an image, by
//! letting them send the image data directly to the loader instead of having the loader read
//! the data from a file. Applications can use this functionality instead of constructing a 
//! Pixbuf or a PixbufAnimation directly from a file when they need to parse image data in
//! small chunks. For example, it should be used when reading an image from a (potentially)
//! slow network connection, or when loading an extremely large file.
//!
//! To use PixbufLoader to load an image, just construct a new one, and call write() to send
//! the data to it. When done, close() should be called to end the stream and finalize 
//! everything. The loader will emit three important signals throughout the process. The
//! first, <EM>size_prepared</EM>, will be called as soon as the image has enough information
//! to determine the size of the image to be used. If you want to scale the image while 
//! loading it, you can call set_size() in response to this signal.
//!
//! The second signal, <EM>area_prepared</EM>, will be called as soon as the pixbuf of the
//! desired size has been allocated. You can obtain it by calling get_pixbuf(). If you want
//! to use it, simply ref() it. In addition, no actual information will be passed in yet, so
//! the pixbuf can be safely filled with any temporary graphics (or an initial color) as
//! needed. You can also call get_pixbuf() later and get the same pixbuf.
//!
//! The last signal, <EM>area_updated</EM> gets called every time a region is updated. This
//! way you can update a partially completed image. Note that you do not know anything about
//! the completeness of an image from the area updated. For example, in an interlaced image,
//! you need to make several passes before the image is done loading.
//!
//! Loading an animation is almost as easy as loading an image. Once the first <EM>area_prepared</EM>
//! signal has been emitted, you can call get_animation() to get the PixbufAnimation object and 
//! get_iter() to get an PixbufAnimationIter for displaying it.

class PixbufLoader : public G::Object
{
	friend class G::Object;
	friend class PixbufLoaderClass;

	PixbufLoader(const PixbufLoader&);
	PixbufLoader& operator=(const PixbufLoader&);
	
protected:
//! @name Constructors
//! @{

	explicit PixbufLoader(GdkPixbufLoader *pixbuf_loader, bool reference = true);
	//!< Construct a new PixbufLoader from an existing GdkPixbufLoader.
	//!< @param pixbuf_loader A pointer to a GdkPixbufLoader.
	//!< @param reference Set false if the initial reference count is floating, set true if it's not.
	//!<
	//!< <BR>The <EM>pixbuf_loader</EM> can be a newly created GdkPixbufLoader or an existing
	//!< GdkPixbufLoader. (see G::Object::Object).

//! @}
//! @name Signal Handlers
//! @{

	void on_size_prepared(int width, int height);
	//!< Called when the pixbuf loader has been fed the initial amount of data that
	//!< is required to figure out the size of the image that it will create.
	//!< @param width The width of the image the pixbuf loader will create.
	//!< @param height The height of the image the pixbuf loader will create.
	//!<
	//!< <BR>Applications can call set_size() in response to this signal to set
	//!< the desired size to which the image should be scaled.
	
	void on_area_prepared();
	//!< Called when the pixbuf loader has allocated the pixbuf in the desired size.
	//!< After this signal is emitted, applications can call get_pixbuf() to fetch
	//!< the partially-loaded pixbuf.

	void on_area_updated(int x, int y, int width, int height);
	//!< Called when a significant area of the image being loaded has been updated.
	//!< @param x The X coordinate of the updated area.
	//!< @param y The Y coordinate of the updated area.
	//!< @param width The width of the updated area.
	//!< @param height The height of the updated area.
	//!<
	//!< <BR>Normally it means that one or more complete scanlines has been read in,
	//!< but it could be a different area as well. Applications can use this signal 
	//!< to know when to repaint areas of an image that is being loaded. Usually the
	//!< x coordinate and the width will remain the same. The y coordinate changes
	//!< each time one or more scanlines are read in. The height is the number of 
	//!< scanlines, in pixels.

	void on_closed();
	//!< Called when close() is called. It can be used by different parts of an
	//!< application to receive notification when an image loader is closed by
	//!< the code that drives it.

//! @}
//  Signals

	typedef G::Signal2<void, int, int> SizePreparedSignalType;
	typedef G::SignalProxy<TypeInstance, SizePreparedSignalType> SizePreparedSignalProxy;
	static const SizePreparedSignalType size_prepared_signal;
	
	typedef G::Signal0<void> AreaPreparedSignalType;
	typedef G::SignalProxy<TypeInstance, AreaPreparedSignalType> AreaPreparedSignalProxy;
	static const AreaPreparedSignalType area_prepared_signal;

	typedef G::Signal4<void, int, int, int, int> AreaUpdatedSignalType;
	typedef G::SignalProxy<TypeInstance, AreaUpdatedSignalType> AreaUpdatedSignalProxy;
	static const AreaUpdatedSignalType area_updated_signal;

	typedef G::Signal0<void> ClosedSignalType;
	typedef G::SignalProxy<TypeInstance, ClosedSignalType> ClosedSignalProxy;
	static const ClosedSignalType closed_signal;

public:
//! @name Constructors
//! @{

	PixbufLoader();
	//!< Constructs a new pixbuf loader object.

	PixbufLoader(const char *image_type, G::Error *error = 0);
	//!< Constructs a new pixbuf loader object that always attempts to parse
	//!< image data as if it were an image of type image_type, instead of 
	//!< identifying the type automatically. 
	//!< @param image_type The name of the image format to be loaded with the image.
	//!< @param error The return location for an allocated G::Error, or null to ignore errors.
	//!<
	//!< <BR>Useful if you want an error if the image isn't the expected type,
	//!< for loading image formats that can't be reliably identified by looking
	//!< at the data, or if the user manually forces a specific type. The
	//!< <EM>image_type</EM> can be png, jpeg, tiff, gif, xpm, pnm, ras, ico,
	//!< bmp or wbmp.

	virtual ~PixbufLoader();
	//!< Destructor.

//! @}
//! @name Accessors
//! @{

	GdkPixbufLoader* gdk_pixbuf_loader() const { return (GdkPixbufLoader*)instance; }
	//!< Get a pointer to the GdkPixbufLoader structure.

	GdkPixbufLoaderClass* gdk_pixbuf_loader_class() const;
	//!< Get a pointer to the GdkPixbufLoaderClass structure.

	operator GdkPixbufLoader* () const;
	//!< Conversion operator; safely converts a PixbufLoader to a GdkPixbufLoader pointer.

	Pointer<Pixbuf> get_pixbuf() const;
	//!< Queries the Pixbuf that the pixbuf loader is currently creating.
	//!< @return A smart pointer to the new Pixbuf the loader is creating, or null if
	//!< not enough data has been read to determine how to create the image buffer.
	//!<
	//!< <BR>In general it only makes sense to call this function after the
	//!< <EM>area_prepared</EM> signal has been emitted by the loader; this
	//!< means that enough data has been read to know the size of the image
	//!< that will be allocated. If the loader has not received enough data
	//!< via write(), then this function returns null. The returned pixbuf
	//!< will be the same in all future calls to the loader. If the loader
	//!< is an animation, it will return the "static image" of the animation
	//!< (see Gdk::PixbufAnimation::get_static_image()).

	Pointer<PixbufAnimation> get_animation() const;
	//!< Queries the PixbufAnimation that the pixbuf loader is currently creating.
	//!< @return A smart pointer to the PixbufAnimation that the loader is loading,
	//!< or null if not enough data has been read to determine the information.
	//!<
	//!< <BR>In general it only makes sense to call this function after the
	//!< <EM>area_prepared</EM> signal has been emitted by the loader. If the
	//!< loader doesn't have enough bytes yet (hasn't emitted the area_prepared
	//!< signal) this method will return null.

	Pointer<PixbufFormat> get_format() const;
	//!< Obtains the available information about the format of the currently loading image file.
	//!< @return A smart pointer to the new PixbufFormat, or null.

//! @}
//! @name Methods
//! @{

	void set_size(int width, int height);
	//!< Causes the image to be scaled while it is loaded.
	//!< @param width The desired width of the image being loaded.
	//!< @param height The desired height of the image being loaded.
	//!<
	//!< <BR>The desired image size can be determined relative to the original
	//!< size of the image by calling set_size() from a signal handler for the
	//!< <EM>size_prepared</EM> signal. Attempts to set the desired image size
	//!< are ignored after the emission of the <EM>size_prepared</EM> signal.

	bool write(const unsigned char *buffer, size_t count, G::Error *error);
	//!< This method will cause a pixbuf loader to parse the next count bytes of an image.
	//!< @param buffer A pointer to the image data.
	//!< @param count The length of <EM>buffer</EM> in bytes.
	//!< @param error The return location for errors.
	//!< @return <EM>true</EM> if the data was loaded successfully, <EM>false</EM> if an error occurred.
	//!<
	//!< <BR>If an error occurs, the loader will be closed, and will not accept further writes.
	//!< If false is returned, error will be set to an error from the GDK_PIXBUF_ERROR or G_FILE_ERROR domains.

	bool close(G::Error *error = 0);
	//!< Informs a pixbuf loader that no further writes with write() will occur,
	//!< so that it can free its internal loading structures. 
	//!< @param error The return location for a G::Error, or null to ignore errors.
	//!< @return <EM>true</EM> if all image data written so far was successfully
	//!< passed out via the <EM>area_updated</EM> signal.
	//!<
	//!< <BR>This method tries to parse any data that hasn't yet been parsed;
	//!< if the remaining data is partial or corrupt, an error will be returned.
	//!< If false is returned, error will be set to an error from the 
	//!< GDK_PIXBUF_ERROR or G_FILE_ERROR domains. If you're just cancelling a
	//!< load rather than expecting it to be finished, passing null for error to
	//!< ignore it is reasonable.

//! @}
//! @name Signal Proxies
//! @{

	const SizePreparedSignalProxy sig_size_prepared()
	{
		return SizePreparedSignalProxy(this, &size_prepared_signal);
	}
	//!< Connect to the size_prepared_signal; emitted when the pixbuf loader
	//!< has been fed the initial amount of data that is required to figure
	//!< out the size of the image that it will create.

	const AreaPreparedSignalProxy sig_area_prepared()
	{
		return AreaPreparedSignalProxy(this, &area_prepared_signal);
	}
	//!< Connect to the area_prepared_signal; emitted when the pixbuf loader
	//!< has allocated the pixbuf in the desired size.

	const AreaUpdatedSignalProxy sig_area_updated()
	{
		return AreaUpdatedSignalProxy(this, &area_updated_signal);
	}
	//!< Connect to the area_updated_signal; emitted when a significant area
	//!< of the image being loaded has been updated.

	const ClosedSignalProxy sig_closed()
	{
		return ClosedSignalProxy(this, &closed_signal);
	}
	//!< Connect to the closed_signal; emitted when close() is called.

//! @}
};

} // namespace Gdk

} // namespace Inti

#endif // INTI_GDK_PIXBUF_LOADER_H

