/*
 * 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.h>
#include <glib/gi18n.h>

#include <gio/gio.h>
#include <glib/gstdio.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <gtk/gtk.h>
#include <gdk/gdkx.h>

#include <libwnck/libwnck.h>

#include <gconf/gconf.h>
#include <gconf/gconf-client.h>

#include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h>

#include <libgnomeui/libgnomeui.h>
#include <libgnome/gnome-desktop-item.h>

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

#define SYSTEM_FAV_MENU PKGDATADIR"/Favorites.menu"
#define LOCAL_FAV_DIR  ".config/menus/applications-merged"
#define LOCAL_FAV_MENU ".config/menus/applications-merged/Favorites.menu"

#define APP_NAME "Netbook Launcher"

/* Forwards */
static void     set_window_hints (ClutterStage *stage);
static void     size_changed     (GdkScreen *screen, ClutterActor *app);
static void     on_system_resume (LauncherConfig *config);
static gboolean on_delete_event  (ClutterActor *stage, ClutterEvent *event);

static gboolean check_old_config_before_running ();

static gboolean windowed = FALSE;
static gint     width    = 1024;
static gint     height   = 600;
static gboolean norestart= FALSE;
static gint     last_category = 0;
static gboolean check_run = FALSE;

static GOptionEntry entries[] =
{
  {
    "windowed",
    'w', 0,
    G_OPTION_ARG_NONE,
    &windowed,
    "Launch in windowed mode (for testing - 1024x600)",
    NULL
  },
  {
    "width",
    'd', 0,
    G_OPTION_ARG_INT,
    &width,
    "width",
    NULL
  },
  {
    "height",
    'h', 0,
    G_OPTION_ARG_INT,
    &height,
    "height",
    NULL
  },   
  {
    "no-restart",
    'r', 0,
    G_OPTION_ARG_NONE,
    &norestart,
    "Do not restart on VT changes",
    NULL
  },  
  {
    "last-category",
    'l', 0,
    G_OPTION_ARG_INT,
    &last_category,
    "The last active category before the launcher was restarted",
    NULL
  },
  {
    "check-run",
    'c', 0,
    G_OPTION_ARG_NONE,
    &check_run,
    "This option is available to facilitate the upgrade from ume-launcher to "
    "netbook-launcher. If enabled, it will check the existance of the "
    "ume-launcher.desktop autostart suppression file in ~/.config/autostart "
    "prior to starting, and replace it with one for netbook-launcher, so "
    "users that upgraded while in Classic mode do not have a launcher popup.",
    NULL
  },
  {
    NULL
  }
};

gint
main (gint argc, gchar *argv[])
{
  ClutterActor *stage, *app;
  ClutterColor black = { 0x00, 0x00, 0x00, 0xff };
  LauncherConfig *cfg;
  GdkScreen *screen;
  GError *error = NULL;
  gchar *local_apps;
  
  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);

  g_thread_init (NULL);
  g_set_application_name (APP_NAME);

  gtk_init (&argc, &argv);
  clutter_init_with_args (&argc, &argv,
                          " - " APP_NAME, entries,
                          NULL,
                          &error);
  if (error)
  {
      g_print ("Unable to run " APP_NAME ": %s", error->message);
      g_error_free (error);
      return EXIT_FAILURE;
  }

  /* Check the existance of the ume-launcher.desktop suppression file 
   * before starting */
  if (check_run)
  {
    if (check_old_config_before_running ())
      return EXIT_SUCCESS;
  }
  
  gnome_program_init ("netbook-launcher", "0.1.2", LIBGNOMEUI_MODULE, 
                      argc, argv, GNOME_PARAM_NONE, NULL);

  /* DO NOT REMOVE, that is, unless 
   * https://bugs.freedesktop.org/show_bug.cgi?id=17327 is fixed properly on 
   * Intel systems 
   */
  clutter_set_use_mipmapped_text(FALSE);

  wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);

  /* FIXME: Some tests that shouldn't be in here */
  local_apps = g_build_filename (g_get_home_dir (), 
                                 ".local", "share", "applications", NULL);
  if (!g_file_test (local_apps, G_FILE_TEST_EXISTS))
  {
    /* As the local application dir doesn't exist, we assume this is first
     * run
     */
    g_mkdir_with_parents (local_apps, 0700);
    g_debug ("Created local applications directory at %s", local_apps);
  }
  g_free (local_apps);
  
  local_apps = g_build_filename (g_get_home_dir (), 
                                 ".config", "netbook-launcher", "icons", NULL);
  if (!g_file_test (local_apps, G_FILE_TEST_EXISTS))
  {
    g_mkdir_with_parents (local_apps, 0700);
    g_debug ("Created local icons directory at %s", local_apps);
  }
  g_free (local_apps);

  local_apps = g_build_filename (g_get_home_dir (), LOCAL_FAV_MENU, NULL);
  if (!g_file_test (local_apps, G_FILE_TEST_EXISTS))
  {
    GFile *from, *to;
    gchar *temp = g_build_filename (g_get_home_dir (), LOCAL_FAV_DIR, NULL);
    g_mkdir_with_parents (temp, 0700);

    from = g_file_new_for_path (SYSTEM_FAV_MENU);
    to = g_file_new_for_path (local_apps);

    g_file_copy (from, to, 0, NULL, NULL, NULL, NULL);

    g_object_unref (from);
    g_object_unref (to);
  }

  /* This stuff does belong here */
  stage = clutter_stage_get_default ();
  screen = gdk_screen_get_default ();

  if (windowed)
  {
    clutter_actor_set_size (stage, width, height);
    clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
    g_setenv ("LAUNCHER_WINDOWED", "1", TRUE);
  }
  else
  {
    GdkRectangle rect;
    GConfClient *client;
    gint monitor;

    client = gconf_client_get_default ();
    monitor = gconf_client_get_int (client, "/apps/netbook-launcher/monitor",
                                    NULL);
    if (monitor >= gdk_screen_get_n_monitors (screen))
    {
      g_debug ("Monitor %d out-of-range, using monitor 0", monitor);
      monitor = 0;
    }

    gdk_screen_get_monitor_geometry (screen, monitor, &rect);
    clutter_actor_set_size (stage,
                          rect.width,
                          rect.height);    
    set_window_hints (CLUTTER_STAGE (stage));

    g_object_unref (client);
  }
  clutter_stage_set_color (CLUTTER_STAGE (stage), &black);
  clutter_stage_set_use_fog (CLUTTER_STAGE (stage), FALSE);
  
  if (!windowed)
    g_signal_connect (stage, "event", G_CALLBACK (on_delete_event), NULL);

  /* No restart */
  if (norestart)
    g_setenv ("LAUNCHER_NORESTART", "1", TRUE);
  else
    g_setenv ("LAUNCHER_NORESTART", "0", TRUE);

  /* Init() the main application */
  cfg = launcher_config_get_default ();  
  if (cfg->low_graphics)
    clutter_set_motion_events_enabled (FALSE);
  
  app = launcher_app_get_default ();
  launcher_catbar_set_active_category 
                            (LAUNCHER_CATBAR (launcher_catbar_get_default ()), 
                                       last_category);
  g_signal_connect (screen, "size-changed", 
                    G_CALLBACK (size_changed), app);
  g_signal_connect (cfg, "resume-event",
                    G_CALLBACK (on_system_resume), NULL);
 
  clutter_actor_show (stage);
  clutter_main ();
  
  if (windowed)
    g_setenv ("LAUNCHER_WINDOWED", "0", TRUE);
  
  if (norestart)
    g_setenv ("LAUNCHER_NORESTART", "0", TRUE);
  
  return EXIT_SUCCESS;
}

static gboolean
on_delete_event (ClutterActor *stage, ClutterEvent *event)
{
  if (event->type == CLUTTER_DELETE)
  {
    g_print ("Delete event\n");
    return TRUE;
  }
  return FALSE;
}

/*
 * Check if there is a ~/.config/autostart/ume-launcher.desktop autostart
 * suppression file present before starting (as we may be in classic mode).
 *
 */
static gboolean
check_old_config_before_running ()
{
#define AUTOSTART_ITEM "X-GNOME-Autostart-enabled"
  gchar *ume_desktop;
  
  ume_desktop = g_build_filename (g_get_home_dir (),
                                  ".config",
                                  "autostart",
                                  "ume-launcher.desktop",
                                  NULL);

  if (g_file_test (ume_desktop, G_FILE_TEST_EXISTS))
  {
    GError           *error = NULL;
    GnomeDesktopItem *item = NULL;
    gchar            *netbook_desktop;
    gboolean          autostart_enabled = TRUE;
    
    item = gnome_desktop_item_new_from_file (ume_desktop,
                                       GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS,
                                             &error);


    if (error || !item)
    {
      g_warning ("Unable to read ume-launcher.desktop at %s: %s", 
                  ume_desktop, error ? error->message: " ");
      
      g_error_free (error);
      g_free (ume_desktop);
      return FALSE;
    }

    /* Check if the autostart file was to autostart or to suppress autostart */
    if (gnome_desktop_item_attr_exists (item, AUTOSTART_ITEM))
    {
      autostart_enabled = gnome_desktop_item_get_boolean (item, AUTOSTART_ITEM);
    }
    
    /* Update the exec string */
    gnome_desktop_item_set_string (item, 
                                   GNOME_DESKTOP_ITEM_EXEC,
                                   "netbook-launcher");
    /* Save in new location */
    netbook_desktop = g_strdup_printf (
                  "file://%s/.config/autostart/netbook-launcher.desktop", 
                  g_get_home_dir ());
    gnome_desktop_item_save (item, netbook_desktop, TRUE, &error);

    if (error)
    {
      g_warning ("Unable to replace ume-launcher.desktop with netbook-launcher.desktop: %s", error->message);
      
      g_error_free (error);
      g_free (ume_desktop);
      g_free (netbook_desktop);
      gnome_desktop_item_unref (item);
      return FALSE;
    }
    gnome_desktop_item_unref (item);

    /* Remove of ume_desktop file */
    g_unlink (ume_desktop);

    g_free (ume_desktop);
    g_free (netbook_desktop);
    
    return !autostart_enabled;
  }

  g_free (ume_desktop);
  return FALSE;
}

/*
 * Apply the 'desktop' window type to the clutter-stage window. Also, set the
 * 'panel' hints, to stop the windows from maximising the entire way.
 */
static void
set_window_hints (ClutterStage *stage)
{
  GdkDisplay *display = gdk_display_get_default (); 
  GtkIconTheme *theme;
  Display *xdisplay;
  Window stage_win;
  Atom atom;
  GdkPixbuf *pixbuf;
  GdkWindow *window;
  GList *list = NULL;
    
  xdisplay = GDK_DISPLAY_XDISPLAY (display);
  stage_win = clutter_x11_get_stage_window (stage);

  /* 
   * Make the clutter window a 'desktop' window, i.e maximised, but behind 
   * everything else
   */
  atom = gdk_x11_get_xatom_by_name_for_display (display,
                                                "_NET_WM_WINDOW_TYPE_DESKTOP");
  XChangeProperty (xdisplay, stage_win,
                   gdk_x11_get_xatom_by_name_for_display (display,
                                                "_NET_WM_WINDOW_TYPE"),
                   XA_ATOM , 32, PropModeReplace, 
                   (guchar *)&atom, 1);

  /*
   * The window icon 
   */
  theme = gtk_icon_theme_get_default ();
  pixbuf = gtk_icon_theme_load_icon (theme, "distributor-logo", 48, 0, NULL);
  list = g_list_append (list, pixbuf);
  window = gdk_window_foreign_new (stage_win);
  gdk_window_set_icon_list (window, list);

  gdk_window_set_title (window, _("Home"));
}


static void
restart_launcher ()
{
  LauncherCatbar *bar;
  gchar *exec;
  
  bar = (LauncherCatbar *)launcher_catbar_get_default ();
  exec = g_strdup_printf ("netbook-launcher --no-restart --last-category=%d",
                          launcher_catbar_get_active_category (bar));
  gdk_spawn_command_line_on_screen (gdk_screen_get_default (),
                                    exec, NULL);
  g_free (exec);
  clutter_main_quit ();
}

static void
on_system_resume (LauncherConfig *config)
{
  if (!norestart)
    restart_launcher ();
}

/* What happens when the stage changes size
 * NOTE: Only send --no-restart if it's currently enabled, otherwise the
 * launcher will not react when RESIZE>SUSPEND>RESUME
 */
static void
restart_launcher_for_resize ()
{
  LauncherCatbar *bar;
  gchar *exec;
  
  bar = (LauncherCatbar *)launcher_catbar_get_default ();
  exec = g_strdup_printf ("netbook-launcher --last-category=%d",
                          launcher_catbar_get_active_category (bar));
  gdk_spawn_command_line_on_screen (gdk_screen_get_default (),
                                    exec, NULL);
  g_free (exec);
  clutter_main_quit ();
}

static void    
size_changed (GdkScreen    *screen,
              ClutterActor *app)
{
  static gboolean already_called = FALSE;

  if (CSW () == gdk_screen_get_width (screen) 
      && CSH () == gdk_screen_get_height (screen))
    return;

  if (already_called)
    return;

  already_called = TRUE;
  restart_launcher_for_resize ();
}
