/*
 * Copyright (C) 2009 Canonical Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 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 warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authored by Neil Jagdish Patel <neil.patel@canonical.com>
 *
 */

#include <glib.h>
#include <stdlib.h>
#include <clutk/clutk.h>

/*
 * EFFECT IMPLEMENTATION
 */

#define CTK_TYPE_EFFECT_TEST (ctk_effect_test_get_type ())

#define CTK_EFFECT_TEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
	CTK_TYPE_EFFECT_TEST, CtkEffectTest))

#define CTK_EFFECT_TEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
	CTK_TYPE_EFFECT_TEST, CtkEffectTestClass))

#define CTK_IS_EFFECT_TEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
	CTK_TYPE_EFFECT_TEST))

#define CTK_IS_EFFECT_TEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
	CTK_TYPE_EFFECT_TEST))

#define CTK_EFFECT_TEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
	CTK_TYPE_EFFECT_TEST, CtkEffectTestClass))

typedef struct _CtkEffectTest        CtkEffectTest;
typedef struct _CtkEffectTestClass   CtkEffectTestClass;
typedef struct _CtkEffectTestPrivate CtkEffectTestPrivate;

struct _CtkEffectTest
{
  CtkEffect parent;	
};

struct _CtkEffectTestClass
{
  /*< private >*/
  CtkEffectClass parent_class;
  
  void (*_test_padding1) (void);
  void (*_test_padding2) (void);
  void (*_test_padding3) (void);
  void (*_test_padding4) (void);
  void (*_test_padding5) (void);
  void (*_test_padding6) (void);
};

GType       ctk_effect_test_get_type (void) G_GNUC_CONST;


G_DEFINE_TYPE (CtkEffectTest, ctk_effect_test, CTK_TYPE_EFFECT);

/* Forwards */
static void ctk_effect_test_paint (CtkEffect *effect, CtkEffectPaintFunc func, gboolean is_last_effect);
/*
 * GObject stuff
 */
static void
ctk_effect_test_class_init (CtkEffectTestClass *klass)
{
  CtkEffectClass *eff_class = CTK_EFFECT_CLASS (klass);

  eff_class->paint = ctk_effect_test_paint;
}


static void
ctk_effect_test_init (CtkEffectTest *self)
{
  ;
}

/*
 * Private Methods
 */
static void
ctk_effect_test_paint (CtkEffect *effect, CtkEffectPaintFunc func, gboolean is_last_effect)
{
  ClutterActor *actor;

  actor = ctk_effect_get_actor (effect);
  g_return_if_fail (CLUTTER_IS_ACTOR (actor));

  /* Just paint as normal for now */
  func (actor);
}

/*
 * TEST
 */
static void test_allocation          (void);
static void test_properties          (void);
static void test_effect_properties   (void);
static void test_paint               (void);
static void test_paint_through_actor (void);
static void test_effect_dirty_flag   (void);

void
test_effect_create_suite (void)
{
#define DOMAIN "/Effect"

  g_test_add_func (DOMAIN"/Allocation", test_allocation);
  g_test_add_func (DOMAIN"/Properties", test_properties);
  g_test_add_func (DOMAIN"/EffectProperties", test_effect_properties);  
  g_test_add_func (DOMAIN"/Paint", test_paint);
  g_test_add_func (DOMAIN"/PaintThroughActor", test_paint_through_actor);
  g_test_add_func (DOMAIN"/EffectDirtyFlag", test_effect_dirty_flag);
}

static void
test_allocation (void)
{
  CtkEffect    *effect;

  /* Check it allocates */
  effect = g_object_new (CTK_TYPE_EFFECT_TEST, NULL);
  g_assert (CTK_IS_EFFECT_TEST (effect) && CTK_IS_EFFECT (effect));

  /* Check default actor == NULL */
  g_assert (ctk_effect_get_actor (effect) == NULL);

  /* Make sure it unallocates */
  g_object_unref (effect);
  g_assert (CTK_IS_EFFECT (effect) == FALSE);
}

static void
test_properties (void)
{
  CtkEffect    *effect;
  ClutterActor *actor;

  effect = g_object_new (CTK_TYPE_EFFECT_TEST, NULL);
  g_assert (CTK_IS_EFFECT_TEST (effect));

  /* Check set/get actor works */
  actor = clutter_rectangle_new ();

  ctk_effect_set_actor (effect, actor);
  g_assert (ctk_effect_get_actor (effect) == actor);

  g_object_unref (actor);
  g_object_set (effect, "actor", NULL, NULL);
  g_object_get (effect, "actor", &actor, NULL);
  g_assert (actor == NULL);

  g_object_unref (effect);
  g_assert (CTK_IS_EFFECT (effect) == FALSE);
}


static void
test_effect_properties (void)
{
  CtkEffect    *effect;
  ClutterActor *actor;

  effect = g_object_new (CTK_TYPE_EFFECT_TEST, NULL);
  g_assert (CTK_IS_EFFECT_TEST (effect));

  /* Check set/get actor works */
  actor = clutter_rectangle_new ();

  ctk_effect_set_actor (effect, actor);
  ctk_effect_set_margin (effect, 11);
  ctk_effect_set_opacity (effect, 0.5f);
  ctk_effect_set_strength (effect, 4);
  
  g_assert (ctk_effect_get_margin (effect) == 11);
  g_assert (ctk_effect_get_opacity (effect) == 0.5f);
  g_assert (ctk_effect_get_strength (effect) == 4);
  
  g_object_unref (effect);
  g_object_unref (actor);
}

static void
test_paint (void)
{
  CtkEffect    *effect;
  
  effect = g_object_new (CTK_TYPE_EFFECT_TEST, NULL);
  g_assert (CTK_IS_EFFECT_TEST (effect));

  /* Make sure our test paint function is called (will warn if actor == NULL) */
  if (g_test_trap_fork (0,
                         G_TEST_TRAP_SILENCE_STDOUT|G_TEST_TRAP_SILENCE_STDERR))
    ctk_effect_paint (effect, clutter_actor_paint, TRUE);
  g_test_trap_assert_failed ();

  g_object_unref (effect);
  g_assert (CTK_IS_EFFECT (effect) == FALSE);
}

static void
test_paint_through_actor (void)
{
  ClutterActor *stage;
  CtkActor     *actor;
  CtkEffect    *effect;

  stage = clutter_stage_get_default ();

  actor = (CtkActor *)ctk_button_new (CTK_ORIENTATION_VERTICAL);
  clutter_container_add_actor (CLUTTER_CONTAINER (stage),
                               CLUTTER_ACTOR (actor));
  
  effect = g_object_new (CTK_TYPE_EFFECT_TEST, NULL);
  ctk_actor_add_effect (actor, effect);
  /* Will call clutter_actor_paint, which should paint the effect. If there is
   * an error, then we'll bail
   */
  clutter_actor_show_all (stage);

  clutter_actor_hide (stage);
  clutter_container_remove_actor (CLUTTER_CONTAINER (stage),
                                  CLUTTER_ACTOR (actor));
  g_assert (CLUTTER_IS_ACTOR (actor) == FALSE);
}

static void
test_effect_dirty_flag   (void)
{
  CtkEffect    *effect;
  ClutterActor *actor;

  effect = g_object_new (CTK_TYPE_EFFECT_TEST, NULL);
  g_assert (CTK_IS_EFFECT_TEST (effect));

  /* Check set/get actor works */
  actor = clutter_rectangle_new ();

  ctk_effect_set_actor (effect, actor);

  ctk_effect_set_invalidate_effect_cache(effect, FALSE);
  g_assert (ctk_effect_is_effect_cache_dirty (effect) == FALSE);

  ctk_effect_set_invalidate_effect_cache(effect, TRUE);
  g_assert (ctk_effect_is_effect_cache_dirty (effect) == TRUE);

  g_object_unref (effect);
  g_object_unref (actor);
}

