/*
 * Copyright (C) 2008 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>
 *
 */

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <glib/gi18n.h>
#include <clutter-gtk/gtk-clutter-util.h>
#include "launcher-notify.h"

#include <tidy/tidy-texture-frame.h>

#include "launcher-app.h"
#include "launcher-config.h"
#include "launcher-defines.h"
#include "launcher-util.h"

G_DEFINE_TYPE (LauncherNotify, launcher_notify, CLUTTER_TYPE_GROUP);

#define LAUNCHER_NOTIFY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
  LAUNCHER_TYPE_NOTIFY, \
  LauncherNotifyPrivate))

struct _LauncherNotifyPrivate
{
  WnckScreen *screen;

  ClutterActor *bg;
  ClutterActor *win;
  ClutterActor *tex;
  ClutterActor *label;

  gint pid;
  gint tag;

  ClutterTimeline *time;
  ClutterEffectTemplate *temp;
};

static gboolean
_timeout (LauncherNotify *notify)
{
  LauncherNotifyPrivate *priv = LAUNCHER_NOTIFY_GET_PRIVATE (notify);
  LauncherConfig *cfg = launcher_config_get_default ();

  clutter_ungrab_pointer ();

  if (cfg->low_graphics)
  {
    clutter_actor_set_opacity (CLUTTER_ACTOR (notify), 0);
    clutter_actor_hide (CLUTTER_ACTOR (notify));
  }
  else
  {
    clutter_effect_fade (priv->temp, CLUTTER_ACTOR (notify), 0, 
                         (ClutterEffectCompleteFunc)clutter_actor_hide, NULL);
  }
  return FALSE;
}

void    
launcher_notify_popup (LauncherNotify *notify,
                       const gchar    *label,
                       ClutterTexture *texture,
                       gint            pid)
{
  LauncherNotifyPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  gint height = CSH()*0.1;
  gint padding = height * 0.1;

  g_return_if_fail (LAUNCHER_IS_NOTIFY (notify));
  priv = notify->priv;

  priv->pid = pid;

  clutter_actor_raise_top (CLUTTER_ACTOR (notify));
  clutter_actor_show (CLUTTER_ACTOR (notify));

  clutter_clone_texture_set_parent_texture (CLUTTER_CLONE_TEXTURE (priv->tex),
                                            texture);
  clutter_actor_set_size (priv->tex, height, height);
  clutter_actor_set_anchor_point_from_gravity (priv->tex, 
                                               CLUTTER_GRAVITY_WEST);
  clutter_actor_set_position (priv->tex, 
                              clutter_actor_get_x (priv->win)+padding,
                              CSH()/2);
  
  if (pango_find_base_dir (label, -1) != PANGO_DIRECTION_RTL)
  {
    clutter_label_set_line_wrap (CLUTTER_LABEL (priv->label), TRUE);
    clutter_label_set_line_wrap_mode (CLUTTER_LABEL (priv->label), 
                                      PANGO_WRAP_WORD_CHAR);
    clutter_actor_set_width (priv->label, 
                            CSW () * (cfg->is_portrait ? 0.5 : 0.2)
                            -CAW (priv->tex)-(padding*2));
    clutter_label_set_text (CLUTTER_LABEL (priv->label), label);
    clutter_actor_set_position (priv->label,
                        clutter_actor_get_x (priv->tex)+CAW(priv->tex)+padding,
                              (CSH()/2)-(CAH(priv->label)/2));  
  }
  else
  {
    clutter_label_set_text (CLUTTER_LABEL (priv->label), label);
    clutter_actor_set_position (priv->label,
                        clutter_actor_get_x (priv->tex) - padding*1.3,
                              (CSH()/2)-(CAH(priv->label)/2));
  }
  
  if (cfg->low_graphics)
    clutter_actor_set_opacity (CLUTTER_ACTOR (notify), 255);
  else
    clutter_effect_fade (priv->temp, CLUTTER_ACTOR (notify), 255, NULL, NULL);
  
  clutter_grab_pointer (CLUTTER_ACTOR (notify));

  priv->tag = g_timeout_add (4000, (GSourceFunc)_timeout, notify);
}

static void
on_window_opened (WnckScreen     *screen, 
                  WnckWindow     *window, 
                  LauncherNotify *notify)
{
  LauncherNotifyPrivate *priv;
  gint pid;

  g_return_if_fail (LAUNCHER_IS_NOTIFY (notify));
  priv = notify->priv;

  pid = wnck_window_get_pid (window);

  g_source_remove (priv->tag);
  _timeout (notify);
}

/* GObject stuff */
static void
launcher_notify_class_init (LauncherNotifyClass *klass)
{
  GObjectClass        *obj_class = G_OBJECT_CLASS (klass);

  g_type_class_add_private (obj_class, sizeof (LauncherNotifyPrivate));
}

static void
launcher_notify_init (LauncherNotify *notify)
{
  LauncherNotifyPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  ClutterActor *stage = clutter_stage_get_default ();
  ClutterColor color = { 0xff, 0xff, 0xff, 0xff };
  ClutterColor black = { 0x00, 0x00, 0x00, 0x66 };
  gint padding = CSH()*0.01;
  gfloat width_factor;
	
  priv = notify->priv = LAUNCHER_NOTIFY_GET_PRIVATE (notify);

  priv->screen = wnck_screen_get_default ();

  if (cfg->is_portrait)
    width_factor = 0.5;
  else
    width_factor = 0.2;

  clutter_container_add_actor (CLUTTER_CONTAINER (stage), 
                               CLUTTER_ACTOR (notify));
  clutter_actor_set_size (CLUTTER_ACTOR (notify), CSW(), CSH());
  clutter_actor_set_position (CLUTTER_ACTOR (notify), 0, 0);
  clutter_actor_set_opacity (CLUTTER_ACTOR (notify), 0);
  clutter_actor_show (CLUTTER_ACTOR (notify));

  priv->bg = clutter_rectangle_new_with_color (&black);
  clutter_container_add_actor (CLUTTER_CONTAINER (notify), priv->bg);
  clutter_actor_set_size (priv->bg, CSW(), CSH());
  clutter_actor_set_position (priv->bg, 0, 0);
  clutter_actor_show (priv->bg);

  priv->win = launcher_util_texture_new_from_file (PKGDATADIR"/window.svg");
  clutter_actor_set_opacity (priv->win, 0);
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->win);
  clutter_actor_realize (priv->win);
  priv->win = tidy_texture_frame_new (CLUTTER_TEXTURE (priv->win), 
                                      25, 25, 25, 25);
  clutter_container_add_actor (CLUTTER_CONTAINER (notify), priv->win);
  clutter_actor_set_size (priv->win, CSW()*width_factor, CSH()*0.2);
  clutter_actor_set_position (priv->win, 
                              (CSW()/2)-(CAW(priv->win)/2), 
                              (CSH()/2)-(CAH(priv->win)/2));
  clutter_actor_show (priv->win);

  priv->tex = clutter_clone_texture_new (NULL);
  clutter_container_add_actor (CLUTTER_CONTAINER (notify), priv->tex);
  clutter_actor_show (priv->tex);

  priv->label = clutter_label_new_full (CAT_FONT, _("Loading"), &color);
  clutter_container_add_actor (CLUTTER_CONTAINER (notify), priv->label);
  clutter_label_set_alignment (CLUTTER_LABEL (priv->label),   
                               PANGO_ALIGN_CENTER);
  clutter_actor_set_anchor_point_from_gravity (priv->label,
                                               CLUTTER_GRAVITY_NORTH);
  clutter_actor_set_position (priv->label, CSW()/2, 
                              clutter_actor_get_y (priv->win)+padding);
  clutter_actor_show (priv->label);

  priv->label = clutter_label_new_full (CAT_FONT, _("Loading"), &color);
  clutter_container_add_actor (CLUTTER_CONTAINER (notify), priv->label);
  clutter_actor_set_width (priv->label, CSW()*width_factor);
  clutter_actor_show (priv->label);

  clutter_actor_set_clip (priv->label, 0, 0, CSW()*width_factor, CSH()*0.2);

  g_signal_connect (priv->screen, "window-opened",
                    G_CALLBACK (on_window_opened), (gpointer)notify);

  priv->time = clutter_timeline_new_for_duration (MID_TIME);
  priv->temp = clutter_effect_template_new (priv->time,
                                            clutter_sine_inc_func);
}

LauncherNotify *
launcher_notify_get_default (void)

{
  static LauncherNotify *notify = NULL;

  if (!notify)
    notify = g_object_new (LAUNCHER_TYPE_NOTIFY, 
                           NULL);

  return notify;
}
