/*  Inti: Integrated Foundation Classes
 *  Copyright (C) 2002 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/glib/type.h
//! @brief Abstract base classes for GTK+ interfaces and objects.

#ifndef INTI_G_TYPE_H
#define INTI_G_TYPE_H

#ifndef INTI_BASE_H
#include <inti/base.h>
#endif

#ifndef INTI_G_SIGNALS_H
#include <inti/glib/signals.h>
#endif

#ifndef INTI_UTF_STRING_H
#include <inti/utf-string.h>
#endif

namespace Inti {

namespace G {

//! @class TypeInstance type.h inti/glib/type.h
//! @brief Abstract base class for GTK+ interfaces and objects.
//!
//! TypeInstance encapsulates GTypeInstance, the base structure for GObjects.
//! It exists only to serve as a common base class for concrete objects and
//! the abstract interfaces they inherit. Gtk::Entry is a good example. It
//! inherits from Gtk::Widget, Gtk::Editable and Gtk::CellEditable. Gtk::Widget
//! is the concrete object and Gtk::Editable and Gtk::CellEditable are its
//! abstract interfaces.

class TypeInstance : virtual public ReferencedBase
{
	TypeInstance(const TypeInstance&);
	TypeInstance& operator=(const TypeInstance&);

protected:
	TypeInstance();
	//!< Constructor.

	virtual ~TypeInstance() = 0;
	//!< Destructor.

 	GTypeInstance *instance;
	//!< A Pointer to the wrapped GTypeInstance structure.

public:
//! @name Accessors
//! @{

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

	template<typename T>
	T* get_class() const
	{ return reinterpret_cast<T*>(instance->g_class); }
	//!< Get a pointer to the class structure for the instance, cast to a pointer of type T.
	//!< @return The class structure for the instance or null if the class does not currently exist.
	
	bool is_a(GType type) const;
	//!< Is the instance of the specified type.
	//!< @param type The type ID of the interface or object.
	//!< @return <EM>true</EM> if the instance of the specified <EM>type</EM>.

	GType type() const;
	//!< Get the type ID for the instance.

	String type_name() const;
	//!< Get the type name for the instance.
	
	bool is_a_type(GType ancestor_type) const;
	//!< Is the instance is a descendant of the specified ancestor_type.
	//!< @param ancestor_type The type ID of the ancestor to check.
	//!< @return <EM>true</EM> if the instance is a descendant of the specified ancestor_type.

	GType parent_type() const;
	// Get the GType of the immediate parent for the instance, or 0 if it has no parent.

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

	void add_interface(GType interface_type, GInterfaceInitFunc interface_init);
	//!< Adds the static <EM>interface_type</EM> to this TypeInstance.
	//!< @param interface_type GType value of the interface type to add.
	//!< @param interface_init The location of the function that initializes <EM>interface_type</EM>.

//! @}

	static void add_interface(GType instance_type, GType interface_type, GInterfaceInitFunc interface_init);
	//!< Adds the static <EM>interface_type</EM> to the instantiable <EM>instance_type</EM>.
	//!< @param instance_type GType value of an instantiable type.
	//!< @param interface_type GType value of the interface type to add.
	//!< @param interface_init The location of the function that initializes <EM>interface_type</EM>.

	static GType register_type(GType parent_type, GClassInitFunc class_init);
	//!< Registers a new static Inti type derived from parent_type.
	//!< @param parent_type The type which this type will be derived from.
	//!< @param class_init The location of the class initialization function.
	//!< @return The new type identifier.

	template<typename T>
	static T* class_peek_parent(void *g_class)
	{ return static_cast<T*>(g_type_class_peek_parent(g_class)); }
	//!< Get a pointer to the parent class for g_class; T is the parent class.
	//!< @param g_class The GTK+ class structure to retrieve the parent class for.
	//!< @return The parent GTypeClass structure cast to a structure of type T.
	//!<
	//!< <BR>This is a convenience method, often needed in class initializers. It essentially takes
	//!< the immediate parent type of the class passed in, and returns the class structure thereof.
	//!< Since derived classes hold a reference count on their parent classes as long as they are
	//!< instantiated, the returned class will always exist.

};

//! @class TypeInterface type.h inti/glib/type.h
//! @brief Abstract base class for GTK+ interfaces.

class TypeInterface : virtual public TypeInstance
{
public:
//! @name Accessors
//! @{

	virtual ~TypeInterface() = 0;
	//!< Destructor.

	GTypeInterface* g_type_interface() const;
	//!< Get a pointer to the GTypeInterface.

	template<typename T>
	T* peek(GType type) const
	{ return static_cast<T*>(g_type_interface_peek(instance->g_class, type)); }
	//!< Get the GTypeInterface structure of the interface to which the instance conforms.
	//!< @param type An interface ID which this class conforms to.
	//!< @return The interface structure of <EM>type</EM>, or null if the instance is not instantiated.

//! @}

	template<typename T>
	static T* peek_parent(void *g_iface)
	{ return static_cast<T*>(g_type_interface_peek_parent(g_iface)); }
	//!< Get the parent GTypeInterface structure of the interface <EM>g_iface</EM>.
	//!< @param g_iface The GTypeInterface to get the parent of.
	//!< @return A pointer to the parent interface structure, or null if none exists.
};

} // namespace G

} // namespace Inti

#endif // INTI_G_TYPE_H

