/* -*- Mode: C; indent-tabs-mode: nil; tab-width: 2 -*-
 *
 * Copyright (C) 2010 Canonical Ltd.
 * Authors:
 *  Florian Boucault <florian.boucault@canonical.com>
 *
 * This file is part of Netbook Launcher EFL.
 *
 * Netbook Launcher EFL is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Netbook Launcher EFL 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 Netbook Launcher EFL.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "netbook-launcher.h"

#include <Elementary.h>
#include <glib/gi18n.h>
#include <gio/gdesktopappinfo.h>
#include <gconf/gconf-client.h>

static const char _EDJE_GROUP_LAYOUT[] = "e/netbook/launcher/main/add_item/layout";
static const char _EDJE_GROUP_ITEM[] = "e/netbook/launcher/main/add_item/item";
static const char _EDJE_PART_TYPES_LIST[] = "types_list";
static const char _EDJE_PART_ICON[] = "e.swallow.icon";
static const char _EDJE_PART_LABEL[] = "e.text.label";

static const char _EDJE_SIG_SRC[] = "e";
static const char _EDJE_SIG_ADD_ITEM_CANCEL[] = "gui,action,add_item,cancel";
static const char _EDJE_SIG_EXECUTED[] = "gui,action,executed";

static const char _context_key[] = "_nl_add_item";

struct add_item_context
{
  Evas_Object *add_item;
  Evas_Object *edje;
  Evas_Object *parent;
  struct item_size item;
};


/* Signal handlers */

static void
_add_item_cancel(void *data, Evas_Object *obj, const char *signal __UNUSED__, const char *source __UNUSED__)
{
  struct add_item_context *ctxt = data;

  win_apps_show_favorites(ctxt->parent);
}

static void
_add_item_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
{
  struct add_item_context *ctxt = data;
  free(ctxt);
}


static void
_add_glib_item_select(void *data)
{
  const char *desktop_file_path = data;
  LauncherApplication *app;
  gboolean running;
  GError *err = NULL;

  app = launcher_application_new_from_desktop_file(desktop_file_path);

  running = launcher_application_get_running(app);
  g_debug("app %s (%p, %s)\n",
          launcher_application_get_name(app), app,
          launcher_application_get_unique_string(app));
  if (running)
  {
    g_debug("application %s is already running",
            launcher_application_get_name(app));
    launcher_application_show(app);
    return;
  }

  launcher_application_launch(app, &err);
  if (err)
  {
    g_warning("could not execute '%s': %s", desktop_file_path, err->message);
    g_error_free(err);
  }
}

static void
_add_item_select(void *data, Evas_Object *obj __UNUSED__, const char *signal __UNUSED__, const char *source __UNUSED__)
{
  const char *desktop_file_path = data;

  gstuff_glib_run_simple(_add_glib_item_select, desktop_file_path);
}



/* Private functions */


static inline void
_add_item_context_set(Evas_Object *add_item, const struct add_item_context *ctxt)
{
  evas_object_data_set(add_item, _context_key, ctxt);
}

static inline struct add_item_context *
_add_item_context_get(const Evas_Object *add_item)
{
  return evas_object_data_get(add_item, _context_key);
}


/*
 * Compute and store in context the size of items.
 */
static void
_add_item_calc_sizes(struct add_item_context *ctxt)
{
  ctxt->item.icon_size = 32;
  ctxt->item.w = 50;
  ctxt->item.h = 50;
  _nl_edje_item_size_calc(&ctxt->item, ctxt->parent, _EDJE_GROUP_ITEM);
}

/*
 * Append a type of item that can be added to the main menu.
 *
 * That will append an item to the BOX e/netbook/launcher/main/add_item/layout:types_list
 *
 */
static void
_add_item_append_type(struct add_item_context *ctxt, const char *desktop_file_name)
{
  Evas_Object *item, *icon, *item_edje;
  const char *label;
  const char *icon_path;
  GIcon* gicon;
  const char* icon_name;
  GAppInfo* desktop_app_info;

  /* Retrieve icon path and label from desktop file */
  desktop_app_info = (GAppInfo*) g_desktop_app_info_new(desktop_file_name);
  const char *path = g_desktop_app_info_get_filename(desktop_app_info);
  gicon = g_app_info_get_icon(desktop_app_info);
  icon_name = g_icon_to_string(gicon);
  icon_path = icon_path_get(icon_name, ctxt->item.icon_size);
  label = g_app_info_get_display_name(desktop_app_info);
  // FIXME: unref unused variables

  /* UI part: insert the item in the canvas and set its icon and label */
  item = elm_layout_add(ctxt->add_item);
  if (!item)
    goto error;
  if (!elm_layout_file_set(item, _nl_prefs.theme, _EDJE_GROUP_ITEM))
    goto error;

  icon = _nl_icon_load_sized(ctxt->add_item, icon_path, ctxt->item.icon_size);

  if (icon)
    elm_layout_content_set(item, _EDJE_PART_ICON, icon);

  item_edje = elm_layout_edje_get(item);
  edje_object_part_text_set(item_edje, _EDJE_PART_LABEL, label);

  evas_object_resize(item, ctxt->item.w, ctxt->item.h);
  evas_object_show(item);

  edje_object_signal_callback_add
    (item_edje, _EDJE_SIG_EXECUTED, _EDJE_SIG_SRC, _add_item_select, path);
  // FIXME: activate keyboard support
  //evas_object_event_callback_add
  //  (parent, EVAS_CALLBACK_KEY_DOWN, _app_item_common_key_down, common);


  edje_object_part_box_append(ctxt->edje, _EDJE_PART_TYPES_LIST, item);
  return;

error:
  if (item)
    evas_object_del(item);
  if (icon)
    evas_object_del(icon);
}


/*
 * Initialization in the GLib thread.
 */
static void
_add_item_glib_start(void *data)
{
  struct add_item_context *ctxt = data;
  GConfClient* gconf;
  GSList* types_desktop_files;
  const char* ITEM_TYPES_GCONF_KEY = "/apps/netbook-launcher-efl/available_item_types";
  GError* error = NULL;

  gconf = gconf_client_get_default();
  types_desktop_files = gconf_client_get_list
    (gconf, ITEM_TYPES_GCONF_KEY, GCONF_VALUE_STRING, &error);
  g_object_unref(gconf);

  if(error != NULL)
  {
    g_error_free(error);
    error = NULL;
    return;
  }
  const GSList *n;
  for(n = types_desktop_files; n != NULL; n = n->next)
    _add_item_append_type(ctxt, (const char*)n->data);

  g_slist_foreach(types_desktop_files, (GFunc)g_free, NULL);
  g_slist_free(types_desktop_files);
}


/* Public API */

Evas_Object *
add_item_add(Evas_Object *parent)
{
  struct add_item_context *ctxt;
  Evas_Object *add_item;

  /* create the edje object where we'll load the layout */
  add_item = elm_layout_add(parent);
  if (!add_item)
  {
    ERR("could not create add_item layout widget.\n");
    return NULL;
  }

   /* load the layout */
  if (!elm_layout_file_set(add_item, _nl_prefs.theme, _EDJE_GROUP_LAYOUT))
  {
    int err = edje_object_load_error_get(add_item);
    const char *errmsg = edje_load_error_str(err);
    ERR("cannot load theme '%s', group '%s': %s\n",
        _nl_prefs.theme, _EDJE_GROUP_LAYOUT, errmsg);
    goto error;
  }

  /* Keep references of important variables defining the context */
  ctxt = calloc(1, sizeof(*ctxt));
  if (!ctxt)
  {
    ERR("could not allocate add_item context.\n");
    goto error;
  }
  ctxt->add_item = add_item;
  ctxt->edje = elm_layout_edje_get(add_item);
  ctxt->parent = parent;

  _add_item_context_set(add_item, ctxt);

  /* Connect various callbacks */
  evas_object_event_callback_add
    (add_item, EVAS_CALLBACK_FREE, _add_item_del, ctxt);
  edje_object_signal_callback_add
    (ctxt->edje, _EDJE_SIG_ADD_ITEM_CANCEL, _EDJE_SIG_SRC, _add_item_cancel, ctxt);

  _add_item_calc_sizes(ctxt);

  gstuff_glib_run_simple(_add_item_glib_start, ctxt);

  return add_item;
error:
  evas_object_del(add_item);
  return NULL;
}

Eina_Bool
add_item_load(Evas_Object *add_item)
{
  struct add_item_context *ctxt = _add_item_context_get(add_item);

  if (!ctxt)
    return 0;

  return 0;
}
