/*
 * Copyright 2009 Canonical Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of either or both of the following licenses:
 *
 * 1) the GNU Lesser General Public License version 3, as published by the
 * Free Software Foundation; and/or
 * 2) the GNU Lesser General Public License version 2.1, as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 * MERCHANTABILITY, SATISFTOPLEVELY QUALITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the applicable version of the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of both the GNU Lesser General Public
 * License version 3 and version 2.1 along with this program.  If not, see
 * <http://www.gnu.org/licenses/>
 *
 * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
 *
 */
/**
 * SECTION:ctk-toplevel
 * @short_description: Provides a top level widget element for other CtkWidgets to exist in
 *
 * #CtkToplevel provides a #CtkBin container for the rest of your interface to exist in, this should be the 'top level
 * in that no other CtkWidget exists above this one
 */
#if HAVE_CONFIG_H
#include <config.h>
#endif

#include "ctk-toplevel.h"

G_DEFINE_TYPE (CtkToplevel, ctk_toplevel, CTK_TYPE_BIN);

#define CTK_TOPLEVEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
  CTK_TYPE_TOPLEVEL, \
  CtkToplevelPrivate))

struct _CtkToplevelPrivate
{
  ClutterActor *stage;
  ClutterActor *focused_actor;
};

enum
{
  PROP_0,

  PROP_STAGE
};

/* Globals */
static GQuark stage_toplevel_quark = 0;

/* Forwards */
static gboolean ctk_toplevel_key_press_event   (CtkToplevel     *self,
    ClutterKeyEvent *event);

static gboolean ctk_toplevel_key_release_event (CtkToplevel     *self,
    ClutterKeyEvent *event);

static void     ctk_toplevel_set_stage         (CtkToplevel     *self,
    ClutterActor    *stage);
/* GObject stuff */
static void
ctk_toplevel_finalize (GObject *object)
{
  G_OBJECT_CLASS (ctk_toplevel_parent_class)->finalize (object);
}

static void
ctk_toplevel_set_property (GObject      *object,
                           guint         prop_id,
                           const GValue *value,
                           GParamSpec   *pspec)
{
  switch (prop_id)
    {
    case PROP_STAGE:
      ctk_toplevel_set_stage (CTK_TOPLEVEL (object),
                              g_value_get_object (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
ctk_toplevel_get_property (GObject    *object,
                           guint       prop_id,
                           GValue     *value,
                           GParamSpec *pspec)
{
  CtkToplevelPrivate *priv = CTK_TOPLEVEL_GET_PRIVATE (object);

  switch (prop_id)
    {
    case PROP_STAGE:
      g_value_set_object (value, priv->stage);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static gboolean
key_press_event (ClutterActor *actor, ClutterKeyEvent *event)
{
  return FALSE;
  return ctk_toplevel_key_press_event (CTK_TOPLEVEL (actor), event);
}

static void
ctk_toplevel_class_init (CtkToplevelClass *klass)
{
  GObjectClass *obj_class = G_OBJECT_CLASS (klass);
  ClutterActorClass *act_class= CLUTTER_ACTOR_CLASS (klass);
  GParamSpec   *pspec;

  /* Overrides */
  obj_class->finalize        = ctk_toplevel_finalize;
  obj_class->set_property    = ctk_toplevel_set_property;
  obj_class->get_property    = ctk_toplevel_get_property;
  act_class->key_press_event = key_press_event;

  /* Properties */
  pspec = g_param_spec_object ("stage", "stage", "ClutterStage",
                               CLUTTER_TYPE_STAGE,
                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
  g_object_class_install_property (obj_class, PROP_STAGE, pspec);

  /* Add Private struct */
  g_type_class_add_private (obj_class, sizeof (CtkToplevelPrivate));
}

static void
ctk_toplevel_init (CtkToplevel *self)
{
  CtkToplevelPrivate *priv;

  priv = self->priv = CTK_TOPLEVEL_GET_PRIVATE (self);

  if (!stage_toplevel_quark)
    {
      stage_toplevel_quark = g_quark_from_string ("ctk-stage-toplevel-quark");
    }

  priv->focused_actor = NULL;
}

ClutterActor *
ctk_toplevel_get_default_for_stage (ClutterActor *stage)
{
  ClutterActor *toplevel;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);

  toplevel = g_object_get_qdata (G_OBJECT (stage), stage_toplevel_quark);

  if (!toplevel)
    {
      toplevel = g_object_new (CTK_TYPE_TOPLEVEL, "stage", stage, NULL);
      g_object_set_qdata (G_OBJECT (stage), stage_toplevel_quark, toplevel);
    }

  return toplevel;
}

/*
 * Private methods
 */

/*
 * Public Methods
 */
void
ctk_toplevel_set_focus (CtkToplevel     *self,
                        CtkFocusable    *focusable)
{

}

gboolean
ctk_toplevel_key_press_event (CtkToplevel     *self,
                              ClutterKeyEvent *event)
{
  ClutterActor       *focus;

  g_return_val_if_fail (CTK_IS_TOPLEVEL (self), FALSE);
  g_return_val_if_fail (event, FALSE);

  focus = ctk_bin_get_child (CTK_BIN (self));

  if (focus)
    return clutter_actor_event (focus, (ClutterEvent *)event, FALSE);

  return FALSE;
}

gboolean
ctk_toplevel_key_release_event (CtkToplevel     *self,
                                ClutterKeyEvent *event)
{
  //g_debug ("key release event");

  return FALSE;
}

static void
ctk_toplevel_set_stage (CtkToplevel *self, ClutterActor *stage)
{
  g_return_if_fail (CTK_IS_TOPLEVEL (self));
  g_return_if_fail (CLUTTER_IS_STAGE (stage));
  g_return_if_fail (self->priv->stage == NULL);

  self->priv->stage = stage;

  if (1)
    {
      g_signal_connect_swapped (stage, "key-press-event",
                                G_CALLBACK (ctk_toplevel_key_press_event), self);
      g_signal_connect_swapped (stage, "key-release-event",
                                G_CALLBACK (ctk_toplevel_key_release_event), self);
    }
  g_object_notify (G_OBJECT (self), "stage");
}

/*
 * Public methods
 */

/**
 * ctk_toplevel_get_stage:
 * @self: a #CtkToplevel object
 * 
 * Retrives the stage this toplevel element is attached to 
 *
 * Returns: A #ClutterStage object
 */
ClutterActor *
ctk_toplevel_get_stage (CtkToplevel     *self)
{
  g_return_val_if_fail (CTK_IS_TOPLEVEL (self), NULL);

  return self->priv->stage;
}
