/*
 * 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>
 *
 */

#include "launcher-shortcut.h"

#include <string.h>
#include <pango/pango.h>

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

G_DEFINE_TYPE (LauncherShortcut, launcher_shortcut, CLUTTER_TYPE_DRAG_DEST);

#define LAUNCHER_SHORTCUT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
  LAUNCHER_TYPE_SHORTCUT, \
  LauncherShortcutPrivate))

struct _LauncherShortcutPrivate
{
  gboolean active;

  ClutterActor *sep;
  ClutterActor *icon;
  ClutterActor *label;
  ClutterActor *eject;
  ClutterActor *bg;

  ClutterTimeline *timeline;
  ClutterEffectTemplate *temp;
  ClutterTimeline *scale_time;

  GdkPixbuf *pixbuf;
  gchar *icon_name;
};

enum
{
  CLICKED,
  EJECT,

  LAST_SIGNAL
};
static guint _shortcut_signals[LAST_SIGNAL] = { 0 };

static ClutterColor orange = { 221, 119, 27, 255 };
static ClutterColor white  = { 0xff, 0xff, 0xff, 0xff };

static void
make_bold (ClutterLabel *label, gboolean bold)
{
  PangoAttrList *list = clutter_label_get_attributes (label);
  PangoAttribute *attr;

  if (!list)
    list = pango_attr_list_new ();

  if (bold)
    attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
  else
    attr = pango_attr_weight_new (PANGO_WEIGHT_NORMAL);

  attr->start_index = 0;
  attr->end_index = strlen (clutter_label_get_text (label));

  pango_attr_list_change (list, attr);

  clutter_label_set_attributes (label, list);
}

static gboolean
on_enter_event (LauncherShortcut *shortcut,
                ClutterMotionEvent *event, 
                gpointer null)
{
  LauncherShortcutPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  
  g_return_val_if_fail (LAUNCHER_IS_SHORTCUT (shortcut), FALSE);
  priv = shortcut->priv;

  if (CLUTTER_IS_TIMELINE (priv->scale_time)
      && clutter_timeline_is_playing (priv->scale_time))
  {
    clutter_timeline_stop (priv->scale_time);
    if (G_IS_OBJECT (priv->scale_time)) 
      g_object_unref (priv->scale_time);
  }

  clutter_label_set_color (CLUTTER_LABEL (priv->label), &orange);
  make_bold (CLUTTER_LABEL (priv->label), TRUE);
  
  if (cfg->low_graphics)
  {
    clutter_actor_set_opacity (priv->bg, 255);
  }
  else
  {
    clutter_effect_fade (priv->temp, priv->bg, 255, NULL, NULL);
    priv->scale_time = clutter_effect_scale (priv->temp, priv->icon, 
                                             1.2, 1.2, NULL, NULL);
  }

  return TRUE;
}

static gboolean
on_leave_event (LauncherShortcut *shortcut,
                ClutterMotionEvent *event, 
                gpointer null)
{
  LauncherShortcutPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  
  g_return_val_if_fail (LAUNCHER_IS_SHORTCUT (shortcut), FALSE);
  priv = shortcut->priv;

  if (priv->active)
    return TRUE;

  if (CLUTTER_IS_TIMELINE (priv->scale_time) 
      && clutter_timeline_is_playing (priv->scale_time))
  {
    clutter_timeline_stop (priv->scale_time);
    if (G_IS_OBJECT (priv->scale_time)) 
      g_object_unref (priv->scale_time);
  } 
  
  clutter_label_set_color (CLUTTER_LABEL (priv->label), &white);
  make_bold (CLUTTER_LABEL (priv->label), FALSE);  
  
  if (cfg->low_graphics)
  {
    clutter_actor_set_opacity (priv->bg, 0);
  }
  else
  {
    clutter_effect_fade (priv->temp, priv->bg, 0, NULL, NULL);
    priv->scale_time = clutter_effect_scale (priv->temp, priv->icon, 
                                             1.0, 1.0, NULL, NULL);
  }

  return TRUE;
}

static gboolean
on_shortcut_clicked (LauncherShortcut   *shortcut,
                     ClutterButtonEvent *event,
                     gpointer            data)
{
  LauncherShortcutPrivate *priv;

  g_return_val_if_fail (LAUNCHER_IS_SHORTCUT (shortcut), FALSE);
  priv = shortcut->priv;

  if (event->button != 1)
    return FALSE;

  priv->active = TRUE;
  make_bold (CLUTTER_LABEL (priv->label), TRUE);
  
  g_signal_emit (shortcut, _shortcut_signals[CLICKED], 0);

  return TRUE;
}

static gboolean
on_eject_clicked (ClutterActor       *eject,
                  ClutterButtonEvent *event,
                  LauncherShortcut   *shortcut)
{
  LauncherShortcutPrivate *priv;

  g_return_val_if_fail (LAUNCHER_IS_SHORTCUT (shortcut), FALSE);
  priv = shortcut->priv;

  if (event->button != 1)
    return FALSE;

  g_signal_emit (shortcut, _shortcut_signals[EJECT], 0);

  return TRUE;
}

void   
launcher_shortcut_set_active (LauncherShortcut *shortcut,
                              gboolean          active)
{
  LauncherShortcutPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  ClutterColor color = { 0xff, 0xff, 0xff, 0xff };
  gint fade = 0;
  gboolean bold = FALSE;
  gdouble scale = 1.0;

  g_return_if_fail (LAUNCHER_IS_SHORTCUT (shortcut));
  priv = shortcut->priv;

  priv->active = active;
  if (active)
  {
    fade = 255;
    color.red = 221;
    color.green = 119;
    color.blue = 27;
    color.alpha = 255;
    bold = TRUE;
    scale = 1.2;
  }

  clutter_label_set_color (CLUTTER_LABEL (priv->label), &color);
  make_bold (CLUTTER_LABEL (priv->label), bold); 
  
  if (cfg->low_graphics)
  {
    clutter_actor_set_opacity (priv->bg, fade);
  }
  else
  {
    clutter_effect_fade (priv->temp, priv->bg, fade, NULL, NULL);
    clutter_effect_scale (priv->temp, priv->icon, scale, scale, NULL, NULL);
  }
}

void   
launcher_shortcut_set_can_eject (LauncherShortcut *shortcut,
                                gboolean          can_eject)
{
  LauncherShortcutPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  gint bar_width = cfg->bar_width - 2;
  gint bar_height = cfg->shortcut_height;

  g_return_if_fail (LAUNCHER_IS_SHORTCUT (shortcut));
  priv = shortcut->priv;

  if (can_eject && !CLUTTER_IS_ACTOR (priv->eject))
  {
    priv->eject=launcher_util_texture_new_from_file (PKGDATADIR"/eject.svg");
    clutter_container_add_actor (CLUTTER_CONTAINER (shortcut), priv->eject);
    clutter_actor_set_anchor_point_from_gravity (priv->eject,
                                                 CLUTTER_GRAVITY_WEST);
    clutter_actor_set_position (priv->eject, 
                                bar_width-(CAW(priv->eject)), 
                                bar_height/2);
    clutter_actor_show (priv->eject);

    clutter_actor_set_reactive (CLUTTER_ACTOR (priv->eject), TRUE);
    g_signal_connect (priv->eject, "button-release-event", 
                      G_CALLBACK (on_eject_clicked), shortcut);
  }
  else if (!can_eject && CLUTTER_IS_ACTOR (priv->eject))
  {
    clutter_actor_destroy (priv->eject);
  }
}

void  
launcher_shortcut_update_icon (LauncherShortcut *shortcut,
                               const gchar      *icon_name)
{
  LauncherShortcutPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  gint bar_height = cfg->shortcut_height;

  g_return_if_fail (LAUNCHER_IS_SHORTCUT (shortcut));
  priv = shortcut->priv;

  clutter_actor_destroy (priv->icon);
  priv->icon = launcher_util_texture_new_from_named_icon (icon_name);
  clutter_container_add_actor (CLUTTER_CONTAINER (shortcut), priv->icon);
  clutter_actor_set_size (priv->icon, 
                          bar_height-(CAT_PADDING*2), 
                          bar_height-(CAT_PADDING*2));
  clutter_actor_set_anchor_point_from_gravity (priv->icon, 
                                               CLUTTER_GRAVITY_CENTER);
  clutter_actor_set_position (priv->icon, 
                              CAT_PADDING + CAW (priv->icon)/2, 
                              CAT_PADDING + CAH (priv->icon)/2);
  clutter_actor_show (priv->icon);
}

static void
launcher_shortcut_set_info (LauncherShortcut *shortcut,
                            const gchar      *icon_name,
                            const gchar      *label,
                            gboolean          can_eject)
{
  LauncherShortcutPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  ClutterColor color = { 0xff, 0xff, 0xff, 0xff };
  gint bar_width = cfg->bar_width - 2;
  gint bar_height = cfg->shortcut_height;
  gchar *text;

  g_return_if_fail (LAUNCHER_IS_SHORTCUT (shortcut));
  priv = shortcut->priv;

  priv->bg = launcher_util_texture_new_from_file 
                                          (PKGDATADIR"/shortcuthilight.svg");
  clutter_container_add_actor (CLUTTER_CONTAINER (shortcut), priv->bg);
  clutter_actor_set_size (priv->bg, bar_width, bar_height-1);
  clutter_actor_set_position (priv->bg, 0, 1);
  clutter_actor_set_opacity (priv->bg, 0);
  clutter_actor_show (priv->bg);
  
  priv->sep = launcher_util_texture_new_from_file (PKGDATADIR"/shortcutbg.svg");
  clutter_container_add_actor (CLUTTER_CONTAINER (shortcut), priv->sep);
  clutter_actor_set_size (priv->sep, bar_width-1, 2);
  clutter_actor_set_position (priv->sep, 0, bar_height-1);
  clutter_actor_show (priv->sep);

  priv->icon = launcher_util_texture_new_from_named_icon (icon_name);
  priv->icon_name = g_strdup (icon_name);
  clutter_container_add_actor (CLUTTER_CONTAINER (shortcut), priv->icon);
  clutter_actor_set_size (priv->icon, 
                          bar_height-(CAT_PADDING*2), 
                          bar_height-(CAT_PADDING*2));
  clutter_actor_set_anchor_point_from_gravity (priv->icon, 
                                               CLUTTER_GRAVITY_CENTER);
  clutter_actor_set_position (priv->icon, 
                              CAT_PADDING + CAW (priv->icon)/2, 
                              CAT_PADDING + CAH (priv->icon)/2);
  clutter_actor_show (priv->icon);
 
  text = g_uri_unescape_string (label, "");
  priv->label = clutter_label_new_full (cfg->font_name, text, &color);
  clutter_container_add_actor (CLUTTER_CONTAINER (shortcut), priv->label);

  if (pango_find_base_dir (text, -1) != PANGO_DIRECTION_RTL)
  {
    clutter_label_set_ellipsize (CLUTTER_LABEL (priv->label), 
                                 PANGO_ELLIPSIZE_END);
    clutter_actor_set_width (priv->label, bar_width-CAW(priv->icon)-(CAT_PADDING*2));
    clutter_actor_set_position (priv->label, 
                                (gint)(CAW(priv->icon) + (CAT_PADDING*2)),
                                (gint)((bar_height/2) - (CAH(priv->label)/2)));
    clutter_actor_show (priv->label);
  }
  else
  {
    clutter_label_set_alignment (CLUTTER_LABEL (priv->label), 
                                 PANGO_ALIGN_LEFT);
    clutter_actor_set_width (priv->label, 
                             bar_width - (can_eject ? 40 : 20));
    clutter_actor_set_position (priv->label, 
                                (gint)(CAW (priv->icon) + (CAT_PADDING*2)),
                                (gint)((bar_height/2) - (CAH(priv->label)/2)));
    clutter_actor_show (priv->label);
  }

  launcher_shortcut_set_can_eject (shortcut, can_eject);

  priv->timeline = clutter_timeline_new_for_duration (SLOW_TIME);
  priv->temp = clutter_effect_template_new (priv->timeline,
                                            clutter_sine_inc_func);  

  clutter_actor_set_reactive (CLUTTER_ACTOR (shortcut), TRUE);
  g_signal_connect (shortcut, "button-release-event", 
                    G_CALLBACK (on_shortcut_clicked), shortcut);
  g_signal_connect (shortcut, "enter-event", 
                    G_CALLBACK (on_enter_event), shortcut);
  g_signal_connect (shortcut, "leave-event", 
                    G_CALLBACK (on_leave_event), shortcut);
}

const gchar *
launcher_shortcut_get_label (LauncherShortcut *shortcut)
{
  g_return_val_if_fail (LAUNCHER_IS_SHORTCUT (shortcut), NULL);

  return clutter_label_get_text (CLUTTER_LABEL (shortcut->priv->label));
}


GdkPixbuf *
launcher_shortcut_get_icon (LauncherShortcut *shortcut)
{
  LauncherShortcutPrivate *priv;

  g_return_val_if_fail (LAUNCHER_IS_SHORTCUT (shortcut), NULL);
  priv = shortcut->priv;

  if (GDK_IS_PIXBUF (priv->pixbuf))
    return priv->pixbuf;

  priv->pixbuf = get_icon (priv->icon_name, 48);

  return priv->pixbuf;
}

ClutterTexture * 
launcher_shortcut_get_texture (LauncherShortcut *shortcut)
{
  g_return_val_if_fail (LAUNCHER_IS_SHORTCUT (shortcut), NULL);

  return CLUTTER_TEXTURE (shortcut->priv->icon);
}

void         
launcher_shortcut_clicked (LauncherShortcut *shortcut)
{
  g_return_if_fail (LAUNCHER_IS_SHORTCUT (shortcut));

  g_signal_emit (shortcut, _shortcut_signals[CLICKED], 0);
}

/* GObject stuff */
static void
launcher_shortcut_finalize (GObject *object)
{
  LauncherShortcutPrivate *priv;

  g_return_if_fail (LAUNCHER_IS_SHORTCUT (object));
  priv = LAUNCHER_SHORTCUT (object)->priv;

  G_OBJECT_CLASS (launcher_shortcut_parent_class)->finalize (object);
}

static void
launcher_shortcut_class_init (LauncherShortcutClass *klass)
{
  GObjectClass        *obj_class = G_OBJECT_CLASS (klass);

  obj_class->finalize = launcher_shortcut_finalize;

	_shortcut_signals[CLICKED] =
		g_signal_new ("clicked",
			      G_OBJECT_CLASS_TYPE (obj_class),
			      G_SIGNAL_RUN_LAST,
			      G_STRUCT_OFFSET (LauncherShortcutClass, clicked),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__VOID, 
			      G_TYPE_NONE, 0);

	_shortcut_signals[EJECT] =
		g_signal_new ("eject",
			      G_OBJECT_CLASS_TYPE (obj_class),
			      G_SIGNAL_RUN_LAST,
			      G_STRUCT_OFFSET (LauncherShortcutClass, eject),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__VOID, 
			      G_TYPE_NONE, 0);

  g_type_class_add_private (obj_class, sizeof (LauncherShortcutPrivate));
}
      
static void
launcher_shortcut_init (LauncherShortcut *shortcut)
{
  LauncherShortcutPrivate *priv;
  priv = shortcut->priv = LAUNCHER_SHORTCUT_GET_PRIVATE (shortcut);

  priv->active = FALSE;
}


ClutterActor * 
launcher_shortcut_new (const gchar *icon,
                       const gchar *label,
                       gboolean     can_unmount)
{
  ClutterActor *shortcut = NULL;

  shortcut = g_object_new (LAUNCHER_TYPE_SHORTCUT, 
                       NULL);
  launcher_shortcut_set_info (LAUNCHER_SHORTCUT (shortcut),
                              icon, label, can_unmount);
  return shortcut;
}
