/* Copyright (C) 2007 The cluttermm Development Team
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <cluttermm/actor.h>
#include <cluttermm/childmeta.h>
#include <glibmm/interface.h>
#include <glibmm/ustring.h>
#include <clutter/clutter.h>
 
_DEFS(cluttermm,clutter)
_PINCLUDE(glibmm/private/interface_p.h)

namespace Clutter
{

class Container : public Glib::Interface
{
  _CLASS_INTERFACE(Container, ClutterContainer, CLUTTER_CONTAINER, ClutterContainerIface)

public:
  _WRAP_METHOD(void add_actor(const Glib::RefPtr<Actor>& actor), clutter_container_add_actor)
  _WRAP_METHOD(void remove_actor(const Glib::RefPtr<Actor>& actor), clutter_container_remove_actor)

  std::vector<Glib::RefPtr<Actor> >       get_children();
  std::vector<Glib::RefPtr<const Actor> > get_children() const;

  _WRAP_METHOD(void lower_child(const Glib::RefPtr<Actor>& actor, const Glib::RefPtr<Actor>& sibling), clutter_container_lower_child)
  void lower_child(const Glib::RefPtr<Actor>& actor);
  _WRAP_METHOD(void raise_child(const Glib::RefPtr<Actor>& actor, const Glib::RefPtr<Actor>& sibling), clutter_container_raise_child)
  void raise_child(const Glib::RefPtr<Actor>& actor);

  _WRAP_METHOD(Glib::RefPtr<Actor> find_child(const Glib::ustring& child_name), clutter_container_find_child_by_name, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const Actor> find_child(const Glib::ustring& child_name) const, clutter_container_find_child_by_name, constversion)

  /** For instance, 
   * void on_foreach(const Glib::RefPtr<Actor>& actor)
   */
  typedef sigc::slot<void, const Glib::RefPtr<Actor>&> SlotForEach;

  void foreach(const SlotForEach& slot);
  _IGNORE(clutter_container_foreach)

  // not sure the valist stuff is good to wrap in C++
  _IGNORE(clutter_container_add_valist, clutter_container_remove_valist, clutter_container_add,
          clutter_container_remove, clutter_container_child_get, clutter_container_child_set,
          clutter_container_class_find_child_property, clutter_container_class_list_child_properties)

 
  template <class PropertyType> inline
  void set_child_property(const Glib::RefPtr<Actor>& child, const Glib::ustring& property_name, const PropertyType& value);

  _WRAP_METHOD(void set_child_property_value(const Glib::RefPtr<Actor>& child, const Glib::ustring& property_name, const Glib::ValueBase& value), clutter_container_child_set_property)

  template <class PropertyType> inline
  void get_child_property(const Glib::RefPtr<const Actor>& child, const Glib::ustring& property_name, PropertyType& value) const;

  void get_child_property_value(const Glib::RefPtr<const Actor>& child, const Glib::ustring& property_name, Glib::ValueBase& value) const;
  _IGNORE(clutter_container_child_get_property)

  _WRAP_METHOD(Glib::RefPtr<ChildMeta> get_child_meta(const Glib::RefPtr<const Actor>& actor),
               clutter_container_get_child_meta, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const ChildMeta> get_child_meta(const Glib::RefPtr<const Actor>& actor) const,
               clutter_container_get_child_meta, refreturn, constversion)

#m4 _CONVERSION(`ClutterActor*',`const Glib::RefPtr<Actor>&',`Glib::wrap($3, true)')
  _WRAP_SIGNAL(void actor_added(const Glib::RefPtr<Actor>& actor), "actor_added")
  _WRAP_SIGNAL(void actor_removed(const Glib::RefPtr<Actor>& actor), "actor_removed")

  _WRAP_SIGNAL(void child_notify(const Glib::RefPtr<Actor>& actor, GParamSpec* pspec), "child_notify")

protected:

  // Only useful as a protected method for derived implementations.
  _WRAP_METHOD(void sort_depth_order(), clutter_container_sort_depth_order)

  _WRAP_VFUNC(void add(const Glib::RefPtr<Actor>& actor), add)
  _WRAP_VFUNC(void remove(const Glib::RefPtr<Actor>& actor), remove)
  _WRAP_VFUNC(void raise(const Glib::RefPtr<Actor>& actor, const Glib::RefPtr<Actor>& sibling), raise)
  _WRAP_VFUNC(void lower(const Glib::RefPtr<Actor>& actor, const Glib::RefPtr<Actor>& sibling), lower)
  _WRAP_VFUNC(void sort_depth_order(), sort_depth_order)

  // TODO: C++ify?
  _WRAP_VFUNC(void foreach(ClutterCallback callback, gpointer user_data), foreach)

  /** Emit signal_actor_added().
   */
  void actor_added(const Glib::RefPtr<Actor>& actor);

  /** Emit signal_actor_removed().
   */
  void actor_removed(const Glib::RefPtr<Actor>& actor);

  _WRAP_VFUNC(void create_child_meta(const Glib::RefPtr<Actor>& actor), create_child_meta)
  _WRAP_VFUNC(void destroy_child_meta(const Glib::RefPtr<Actor>& actor), destroy_child_meta)
  _WRAP_VFUNC(Glib::RefPtr<ChildMeta> get_child_meta(const Glib::RefPtr<Actor>& actor), get_child_meta)
};

#ifndef DOXYGEN_SHOULD_SKIP_THIS

template <class PropertyType> inline
void Container::set_child_property(const Glib::RefPtr<Actor>& child, const Glib::ustring& property_name, const PropertyType& value)
{
  Glib::Value<PropertyType> property_value;
  property_value.init(Glib::Value<PropertyType>::value_type());

  property_value.set(value);
  this->set_child_property_value(child, property_name, property_value);
}

template <class PropertyType> inline
void Container::get_child_property(const Glib::RefPtr<const Actor>& child, const Glib::ustring& property_name, PropertyType& value) const
{
  Glib::Value<PropertyType> property_value;
  property_value.init(Glib::Value<PropertyType>::value_type());

  this->get_child_property_value(child, property_name, property_value);

  value = property_value.get();
}

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

} // namespace Clutter
