/* 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 <clutter/clutter.h>
#include <iterator>

namespace Clutter
{

ActorBox::ActorBox(float x1, float y1, float x2, float y2)
{
  gobject_.x1 = x1;
  gobject_.y1 = y1;
  gobject_.x2 = x2;
  gobject_.y2 = y2;
}

bool Actor::is_mapped() const
{
  return (CLUTTER_ACTOR_IS_MAPPED(gobj()) != 0);
}

bool Actor::is_realized() const
{
  return (CLUTTER_ACTOR_IS_REALIZED(gobj()) != 0);
}

bool Actor::is_visible() const
{
  return CLUTTER_ACTOR_IS_VISIBLE(gobj());
}

bool Actor::is_reactive() const
{
  return (CLUTTER_ACTOR_IS_REACTIVE(gobj()) != 0);
}

Geometry Actor::get_geometry() const
{
  Geometry geom;
  clutter_actor_get_geometry(const_cast<ClutterActor*>(gobj()), geom.gobj());
  return geom;
}

#if 0
ActorBox Actor::get_paint_area() const
{
  ActorBox box;
  clutter_actor_get_paint_area(const_cast<ClutterActor*>(gobj()), box.gobj());
  return box;
}
#endif

void Actor::get_abs_allocation_vertices(Vertex vertices[4]) const
{
  clutter_actor_get_abs_allocation_vertices(const_cast<ClutterActor*>(gobj()), reinterpret_cast<ClutterVertex*>(vertices));
}

void Actor::get_allocation_vertices(Vertex vertices[4]) const
{
  clutter_actor_get_allocation_vertices(const_cast<ClutterActor*>(gobj()), NULL, reinterpret_cast<ClutterVertex*>(vertices));
}

void Actor::get_allocation_vertices(const Glib::RefPtr<Actor>& ancestor, Vertex vertices[4]) const
{
  clutter_actor_get_allocation_vertices(const_cast<ClutterActor*>(gobj()), Glib::unwrap(ancestor), reinterpret_cast<ClutterVertex*>(vertices));
}

ActorBox Actor::get_allocation_box() const
{
  ActorBox box;
  clutter_actor_get_allocation_box(const_cast<ClutterActor*>(gobj()), box.gobj());
  return box;
}

void Actor::apply_relative_transform_to_point(const Vertex& point, Vertex& vertex) const
{
  clutter_actor_apply_relative_transform_to_point(const_cast<ClutterActor*>(gobj()), NULL, const_cast<ClutterVertex*>(point.gobj()), vertex.gobj());
}

Geometry Actor::get_allocation_geometry() const
{
  Geometry geom;
  clutter_actor_get_allocation_geometry(const_cast<ClutterActor*>(gobj()), geom.gobj());
  return geom;
}

Glib::RefPtr<Animation>
Actor::animate(gulong mode, unsigned int duration, const std::map<std::string, Glib::ValueBase>& properties)
{
  gchar* c_properties[properties.size()];
  GValue values[properties.size()];

  for(std::map<std::string, Glib::ValueBase>::const_iterator iter = properties.begin(); iter != properties.end(); ++iter)
  {
    c_properties[std::distance(properties.begin(), iter)] = g_strdup(iter->first.c_str());
    g_value_copy(iter->second.gobj(), &values[std::distance(properties.begin(), iter)]);
  }

  return Glib::wrap(clutter_actor_animatev(gobj(), mode, duration, properties.size(), c_properties, values));
}

Glib::RefPtr<Animation>
Actor::animate(gulong mode, const Glib::RefPtr<Timeline>& timeline, const std::map<std::string, Glib::ValueBase>& properties)
{
  gchar* c_properties[properties.size()];
  GValue values[properties.size()];

  for(std::map<std::string, Glib::ValueBase>::const_iterator iter = properties.begin(); iter != properties.end(); ++iter)
  {
    c_properties[std::distance(properties.begin(), iter)] = g_strdup(iter->first.c_str());
    g_value_copy(iter->second.gobj(), &values[std::distance(properties.begin(), iter)]);
  }

  return Glib::wrap(clutter_actor_animate_with_timelinev(gobj(), mode, timeline->gobj(), properties.size(), c_properties, values));
}

Glib::RefPtr<Animation>
Actor::animate(const Glib::RefPtr<Alpha>& alpha, const std::map<std::string, Glib::ValueBase>& properties)
{
  gchar* c_properties[properties.size()];
  GValue values[properties.size()];

  for(std::map<std::string, Glib::ValueBase>::const_iterator iter = properties.begin(); iter != properties.end(); ++iter)
  {
    c_properties[std::distance(properties.begin(), iter)] = g_strdup(iter->first.c_str());
    g_value_copy(iter->second.gobj(), &values[std::distance(properties.begin(), iter)]);
  }

  return Glib::wrap(clutter_actor_animate_with_alphav(gobj(), alpha->gobj(), properties.size(), c_properties, values));
}

#if 0
// We need to hand-code this vfunc to write the result back into the
// box variable. The C++ wrapper cannot ref the existing variable, but only
// make a copy.
void Actor_Class::get_paint_area_vfunc_callback(ClutterActor* self, ClutterActorBox* box)
{
  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
      Glib::ObjectBase::_get_current_wrapper((GObject*)self));

  // Non-gtkmmproc-generated custom classes implicitly call the default
  // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc-
  // generated classes can use this optimisation, which avoids the unnecessary
  // parameter conversions if there is no possibility of the virtual function
  // being overridden:
  if(obj && obj->is_derived_())
  {
    #ifdef GLIBMM_EXCEPTIONS_ENABLED
    try // Trap C++ exceptions which would normally be lost because this is a C callback.
    {
    #endif //GLIBMM_EXCEPTIONS_ENABLED
      // Call the virtual member method, which derived classes might override.
      ActorBox cpp_box;
      obj->get_paint_area_vfunc(cpp_box);
      *box = *cpp_box.gobj();
    #ifdef GLIBMM_EXCEPTIONS_ENABLED
    }
    catch(...)
    {
      Glib::exception_handlers_invoke();
    }
    #endif //GLIBMM_EXCEPTIONS_ENABLED
  }
  else
  {
    BaseClassType *const base = static_cast<BaseClassType*>(
        g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface).
g_type_interface_peek(G_OBJECT_GET_CLASS(self), CppObjectType::get_type()) // Get the interface.
)    );

    // Call the original underlying C function:
    if(base && base->get_paint_area)
      (*base->get_paint_area)(self, box);
  }
}

void Actor::get_paint_area_vfunc(ActorBox& box) const
{
  //Call the default C implementation:

  BaseClassType *const base = static_cast<BaseClassType*>(
    g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface).
      g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface.
    )
  );

  if(base && base->get_paint_area)
    (*base->get_paint_area)(const_cast<ClutterActor*>(gobj()), box.gobj());
}
#endif

} //namespace Clutter

