/* libgeglmm - a C++ wrapper for libgegl
 *
 * (c) 2008-2009 Hubert Figuiere
 *
 * 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 3 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 GEGL; if not, see <http://www.gnu.org/licenses/>.
 */

#include <babl/babl.h>

#include <glibmm/object.h>
#include <glibmm/value.h>

#include <geglmm/rectangle.h>

_DEFS(geglmm,gegl)
_PINCLUDE(glibmm/private/object_p.h)

namespace Gegl
{

class Processor;
class Operation;

_WRAP_ENUM(BlitFlags, GeglBlitFlags, NO_GTYPE)

class Node
	: public Glib::Object
{
	_CLASS_GOBJECT(Node, GeglNode, GEGL_NODE, Glib::Object, GObject)
protected:
	_CTOR_DEFAULT()

public:
	_WRAP_CREATE()

public:
	/** create a new_child
	 * @param first_property_name 
	 */
    Glib::RefPtr<Node> new_child(const Glib::ustring & first_property_name, const Glib::ustring & first_value);
	_IGNORE(gegl_node_new_child)

	_WRAP_METHOD(bool connect_from(const Glib::ustring & input_pad_name, const Glib::RefPtr<Node> & source, const Glib::ustring & output_pad_name), gegl_node_connect_from)
	_WRAP_METHOD(bool connect_to(const Glib::ustring & output_pad_name, const Glib::RefPtr<Node> & sink, const Glib::ustring & input_pad_name), gegl_node_connect_to)

    /** link the object to a sink. Return the %sink. */
    Glib::RefPtr<Node> link(const Glib::RefPtr<Node> & sink);
    _IGNORE(gegl_node_link)
	_IGNORE(gegl_node_link_many)
//	_WRAP_METHOD(void link_many(const Glib::RefPtr<Node> & first_sink, ...) G_GNUC_NULL_TERMINATED, gegl_node_link_many)

	_WRAP_METHOD(bool disconnect(const Glib::ustring & input_pad), gegl_node_disconnect)
	_IGNORE(gegl_node_set)
	_IGNORE(gegl_node_get)
	_IGNORE(gegl_node_set_valist)
	_IGNORE(gegl_node_get_valist)

  void set(const Glib::ustring & first_property_name, ...) G_GNUC_NULL_TERMINATED;
  void get(const Glib::ustring & first_property_name, ...) G_GNUC_NULL_TERMINATED;

	_WRAP_METHOD(void blit(double scale, const Rectangle &roi, const Babl * format, void * destination_buf, int rowstride, BlitFlags flags), gegl_node_blit)
	_WRAP_METHOD(void process(), gegl_node_process)

  _IGNORE(gegl_node_adopt_child)

  _WRAP_METHOD(Glib::RefPtr<Node> add_child(const Glib::RefPtr<Node> & child), gegl_node_add_child)
  _WRAP_METHOD(Glib::RefPtr<Node> remove_child(const Glib::RefPtr<Node> & child), gegl_node_remove_child)

	_WRAP_METHOD(Glib::RefPtr<Node> get_parent(), gegl_node_get_parent, refreturn)
	_WRAP_METHOD(Glib::RefPtr<const Node> get_parent() const, gegl_node_get_parent, refreturn, constversion)

	_WRAP_METHOD(Glib::RefPtr<Node> detect(int x, int y), gegl_node_detect, refreturn)
	_WRAP_METHOD(Glib::RefPtr<const Node> detect(int x, int y) const, gegl_node_detect, refreturn, constversion)

	_WRAP_METHOD(GParamSpec* find_property(const Glib::ustring & property_name), gegl_node_find_property)
	_WRAP_METHOD(Rectangle get_bounding_box() const, gegl_node_get_bounding_box)

//TODO: Use the appropriate SListHandle ownership, and add a const version:
	_WRAP_METHOD(Glib::SListHandle< Glib::RefPtr<Node> > get_children(), gegl_node_get_children)

	_WRAP_METHOD(int get_consumers(const Glib::ustring & output_pad, GeglNode    ***nodes, const gchar ***pads) const, gegl_node_get_consumers)

	_WRAP_METHOD(Glib::RefPtr<Node> get_input_proxy(const Glib::ustring & pad_name), gegl_node_get_input_proxy, refreturn)
	_WRAP_METHOD(Glib::RefPtr<const Node> get_input_proxy(const Glib::ustring & pad_name) const, gegl_node_get_input_proxy, refreturn, constversion)

	_WRAP_METHOD(Glib::RefPtr<Node> get_output_proxy(const Glib::ustring & pad_name), gegl_node_get_output_proxy, refreturn)
	_WRAP_METHOD(Glib::RefPtr<const Node> get_output_proxy(const Glib::ustring & pad_name) const, gegl_node_get_output_proxy, refreturn, constversion)

	_WRAP_METHOD(Glib::ustring get_operation() const, gegl_node_get_operation)

	// implemented by hand
	//	_WRAP_METHOD(Glib::RefPtr<Node> get_producer(const Glib::ustring & input_pad_name, Glib::ustring * output_pad_name), gegl_node_get_producer)
//TODO: Use a & instead of a * and add an override witout the output_pad_name:
	_IGNORE(gegl_node_get_producer)
	Glib::RefPtr<Node> get_producer(const Glib::ustring & input_pad_name, Glib::ustring * output_pad_name) const;

	_WRAP_METHOD(bool has_pad(const Glib::ustring & pad_name) const, gegl_node_has_pad)

	_WRAP_METHOD(Glib::RefPtr<Node> create_child(const Glib::ustring & operation), gegl_node_create_child)


	_IGNORE(gegl_node_get_property)
	_IGNORE(gegl_node_set_property)

	template <class T>
	Node & set(const Glib::ustring & _property_name, const T & value);
	template <class T>
	Node & get(const Glib::ustring & _property_name, T & value);

	_WRAP_METHOD(static Glib::RefPtr<Node> new_from_xml(const Glib::ustring & xmldata, const Glib::ustring & path_root), gegl_node_new_from_xml)
	_WRAP_METHOD(static Glib::RefPtr<Node> new_from_file(const Glib::ustring & path), gegl_node_new_from_file)
	_WRAP_METHOD(Glib::ustring to_xml(const Glib::ustring & path_root) const, gegl_node_to_xml)

	_WRAP_METHOD(Glib::RefPtr<Processor> new_processor(const Rectangle & rectangle), gegl_node_new_processor)

	// Properties.
	_WRAP_PROPERTY("gegl-operation", Glib::RefPtr<Operation>)
	_WRAP_PROPERTY("operation", Glib::ustring)
	_WRAP_PROPERTY("name", Glib::ustring)
	_WRAP_PROPERTY("dont_cache", bool);

#m4 _CONVERSION(`GeglRectangle*',`const Rectangle&',`Glib::wrap($3)')
	_WRAP_SIGNAL(void invalidated(const Rectangle &r), "invalidated", no_default_handler)
	_WRAP_SIGNAL(void computed(const Rectangle &r), "computed", no_default_handler)
};

template <class T>
Node & Node::set(const Glib::ustring & _property_name, const T & value)
{
	Glib::Value<T> v;
	v.init(Glib::Value<T>::value_type());
	v.set(value);
	gegl_node_set_property(gobj(), _property_name.c_str(), v.gobj());
	return *this;
}

template <class T>
Node & Node::get(const Glib::ustring & _property_name, T & value)
{
	Glib::Value<T> v;
	v.init(Glib::Value<T>::value_type());
	gegl_node_get_property(gobj(), _property_name.c_str(), v.gobj());
	value = v.get();
	return *this;
}


}
