/*
 * 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 <config.h>

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

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

#include <gtk/gtk.h>

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

#define LAUNCHER_NAME    "netbook-launcher"
#define LAUNCHER_DESKTOP LAUNCHER_NAME".desktop"

#define OLD_LAUNCHER_NAME "ume-launcher"
#define OLD_LAUNCHER_DESKTOP OLD_LAUNCHER_NAME".desktop"

#define CLASSIC_PANEL_CONFIG       "/classic-panel-config.xml"
#define NETBOOK_PANEL_CONFIG       "/netbook-panel-config.xml"

#define SHARE_CLASSIC_PANEL_CONFIG PKGDATADIR CLASSIC_PANEL_CONFIG
#define SHARE_NETBOOK_PANEL_CONFIG PKGDATADIR NETBOOK_PANEL_CONFIG

#define SAVED_PANEL_CONF "/.config/desktop-switcher/last-panel-configuration.xml"

#define GNOME_SWITCH_USER_DISABLED "/desktop/gnome/lockdown/disable_user_switching"
#define SCREENSAVER_SWITCH_USER_ENABLED "/apps/gnome-screensaver/user_switch_enabled"
#define NAUTILUS_SHOW_DESKTOP "/apps/nautilus/preferences/show_desktop"
#define THEME "/desktop/gnome/interface/gtk_theme"
#define MAXIMUS "/apps/maximus/undecorate"

#define GCONF_STOP  "gconftool-2 --shutdown"
#define GCONF_UNSET "gconftool-2 --recursive-unset /apps/panel"
#define GCONF_LOAD  "gconftool-2 --load "

#define GCONF_DUMP_CLASSIC_PANEL PREFIX"/bin/gconf-panel-saving.sh "CLASSIC_PANEL_CONFIG
 #define GCONF_DUMP_NETBOOK_PANEL PREFIX"/bin/gconf-panel-saving.sh "NETBOOK_PANEL_CONFIG
 
#define SESSION_COMPONENTS "/desktop/gnome/session/required_components_list"
enum
{
  NETBOOK_MODE = 0,
  CLASSIC_MODE
};

static gboolean create_dir            (const gchar *dir);
static void     enable_netbook        ();
static void     enable_classic        ();
static gboolean check_in_classic_mode ();


static gint    current_mode = NETBOOK_MODE;
static gint    selected_mode = NETBOOK_MODE;

static gchar *switch_to = NULL;

static GOptionEntry entries[] =
{
  {
    "set-mode", 'm', 
    0,
    G_OPTION_ARG_STRING,  &switch_to,
    "Switch to mode. Where mode equals \"netbook\" or \"classic\"",
    NULL
  },
  {
    NULL
  }
};

gint
main (gint argc, gchar *argv[])
{
  GtkBuilder *builder;
  GError     *error = NULL;
  GtkWidget  *dialog;
  GtkWidget  *netbook_radio;
  GtkWidget  *classic_radio;
  gchar      *autostart; 
  
  bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);

  g_thread_init (NULL);
  g_type_init ();
  g_set_application_name ("Desktop Switcher");

  gtk_init_with_args (&argc, &argv, 
                      "Desktop Switcher", entries, 
                      GETTEXT_PACKAGE, NULL);

  /* Load the user interface */
  builder = gtk_builder_new ();
  gtk_builder_add_from_file (builder, PKGDATADIR"/ui.xml", &error);
  if (error)
  {
    g_warning ("Unable to load ui: %s\n", error->message);
    g_error_free (error);
    return EXIT_FAILURE;
  }
  gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);

  g_print ("In classic mode: %s\n", check_in_classic_mode () ? "true":"false");
  
  /* Make sure the autostart directory exists */
  autostart = g_build_filename (g_get_home_dir (), ".config","autostart", NULL);
  create_dir (autostart);
  g_free (autostart);

  /* User config directory */
  autostart = g_build_filename (g_get_home_dir (), ".config", 
                                "desktop-switcher", NULL);
  create_dir (autostart);
  g_free (autostart);

  if (switch_to)
  {
    gboolean in_classic;

    in_classic = check_in_classic_mode ();
    if (strcmp (switch_to, "netbook") == 0)
    {
      if (in_classic)
      {
        current_mode = CLASSIC_MODE;
        selected_mode = NETBOOK_MODE;
        enable_netbook ();
      }
      else
      {
        g_warning ("You are already in netbook mode");
        return EXIT_SUCCESS;
      }
    }
    else if (strcmp (switch_to, "classic") == 0)
    {
      if (!in_classic)
      {
        current_mode = NETBOOK_MODE;
        selected_mode = CLASSIC_MODE;
        enable_classic ();
      }
      else
      {
        g_warning ("You are already in classic mode");
        return EXIT_SUCCESS;
      }
    }
    else
    {
      g_warning ("%s mode does not exist", switch_to);
      return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
  }

  /* Get all the widgets */
  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "dialog1"));
  netbook_radio = GTK_WIDGET (gtk_builder_get_object (builder, "netbookradio"));
  classic_radio = GTK_WIDGET (gtk_builder_get_object (builder, "classicradio"));

  /* Check which mode we're in */
  if (check_in_classic_mode ())
  {
    g_object_set (classic_radio, "active", TRUE, NULL);
    current_mode = selected_mode = CLASSIC_MODE;
  }
  else
  {
    g_object_set (netbook_radio, "active", TRUE, NULL);  
  }

  /* Connect up the signals & show the window */
  gtk_builder_connect_signals (builder, NULL);
  gtk_widget_show_all (dialog);

  gtk_main ();

  return EXIT_SUCCESS;
}

static gboolean
check_in_classic_mode (void)
{
  gchar    *argv[] = { "pgrep", "-lu", NULL, "netbook", NULL };
  gchar    *output = NULL;
  gchar    *error = NULL;
  gint      exit_status = 0;
  gboolean  retval = TRUE;
    
  argv[2] = (gchar*)g_get_user_name ();

  g_spawn_sync (NULL, argv, NULL, 
                G_SPAWN_SEARCH_PATH, NULL, NULL, 
                &output, &error, &exit_status, NULL);
  if (output)
  {
    if (g_strstr_len (output, strlen (output), "launch"))
      retval = FALSE;
  }

  /* Check if the old version of the launcher, ume-launcher, is running */
  if (retval == TRUE)
  {
    argv[3] = "ume";
    
    g_spawn_sync (NULL, argv, NULL, 
                  G_SPAWN_SEARCH_PATH, NULL, NULL, 
                  &output, &error, &exit_status, NULL);
    if (output)
    {
      if (g_strstr_len (output, strlen (output), "launch"))
      {
        retval = FALSE;
      }
    }
  }

  return retval;
}

static gboolean
create_dir (const gchar *dir)
{
  if (!g_file_test (dir, G_FILE_TEST_EXISTS))
  {
    g_mkdir_with_parents (dir, 0700);
    return TRUE;
  }
  return FALSE;
}

void
on_netbookradio_toggled (GtkToggleButton *button)
{
  if (gtk_toggle_button_get_active (button))
    selected_mode = NETBOOK_MODE;
}

void
on_classicradio_toggled (GtkToggleButton *button)
{
  if (gtk_toggle_button_get_active (button))
    selected_mode = CLASSIC_MODE;
}

static gchar *
launcher_autostart_file (const gchar *autostart_name)
{
  return g_build_filename (g_get_home_dir (),
                               ".config", "autostart",
                               autostart_name,
                               NULL);
}

static void
delete_launcher_autostart_file (const gchar *autostart_name)
{
  gchar *filename;
  GFile *file;
  GError *error = NULL;

  filename = launcher_autostart_file (autostart_name);
  file = g_file_new_for_path (filename);
  g_file_delete (file, NULL, &error);
  if (error)
  { 
    g_warning ("Unable to remove launcher autostart suppression file: %s",
               error->message);
    g_error_free (error);
  }
  g_object_unref (file);
  g_free (filename);
}

static void
create_launcher_autostart_file (const gchar *autostart_name)
{
  GFile *src, *dest;
  gchar *filename;
  GError *error = NULL;

  filename = g_strdup_printf ("%s/%s", PKGDATADIR, autostart_name);
  src = g_file_new_for_path (filename);
  g_free (filename);

  filename = launcher_autostart_file (autostart_name);
  dest = g_file_new_for_path (filename);

  g_file_copy (src, dest, 0, NULL, NULL, NULL, &error);
  if (error)
  {
    g_debug ("Unable to suppress launcher autostart: %s", error->message);
    g_error_free (error);
  }
  g_object_unref (dest);
  g_object_unref (src);
  g_free (filename);
}

static void
enable_netbook (void)
{
  gchar *filename;
  GError *error = NULL;
  GConfClient *client = gconf_client_get_default ();
  GdkScreen *screen = gdk_screen_get_default ();

  g_debug ("Enabling netbook mode");
  
  /* Make sure the launcher autostarts.
     We do both because we can't be sure which launcher user is using.  We
     could check which is running, but that might not be the same as what is
     installed, if the user just did an upgrade.  No harm in handling both. */
  g_debug ("Enabling launcher autostart");
  delete_launcher_autostart_file (LAUNCHER_DESKTOP);
  delete_launcher_autostart_file (OLD_LAUNCHER_DESKTOP);

  /* Tell GNOME to disallow user switching */
  error = NULL;
  gconf_client_set_bool (client, GNOME_SWITCH_USER_DISABLED, TRUE, &error);
  if (error)
  {
    g_warning ("Can't make GNOME disallow user switching: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Tell screensaver to disallow user switching */
  error = NULL;
  gconf_client_set_bool (client, SCREENSAVER_SWITCH_USER_ENABLED, FALSE, &error);
  if (error)
  {
    g_warning ("Can't make screensaver disallow user switching: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Tell nautilus not to draw the desktop */
  error = NULL;
  gconf_client_set_bool (client, NAUTILUS_SHOW_DESKTOP, FALSE, &error);
  if (error)
  {
    g_warning ("Can't stop Nautilus from drawing the desktop: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Set the theme */
  error = NULL;
  gconf_client_set_string (client, THEME, "Human-Murrine-Netbook", &error);
  if (error)
  {
    g_warning ("Can't change the theme: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Set maximus */
  error = NULL;
  gconf_client_set_bool (client, MAXIMUS, TRUE, &error);
  if (error)
  {
    g_warning ("Can't change Maximus's undecorate setting: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Launch the launcher */
  g_debug ("Launching the, er, Launcher");
  filename = g_find_program_in_path (LAUNCHER_NAME);
  if (filename)
    gdk_spawn_command_line_on_screen (screen, LAUNCHER_NAME, NULL);
  else
    gdk_spawn_command_line_on_screen (screen, OLD_LAUNCHER_NAME, NULL);
  g_free (filename);

  sleep (1);

  /* Save current panel configuration */
  filename = g_build_filename (g_get_home_dir (), ".config/desktop-switcher",
                               NETBOOK_PANEL_CONFIG, NULL);
  g_spawn_command_line_sync (GCONF_DUMP_CLASSIC_PANEL, NULL, NULL, NULL, NULL);
      
  /* Set the panel to the netbook layout */
  g_debug ("Restoring panel settings");
  gdk_spawn_command_line_on_screen (screen, GCONF_STOP, NULL);
  gdk_spawn_command_line_on_screen (screen, GCONF_UNSET, NULL);
  if (g_file_test (filename, G_FILE_TEST_EXISTS))
  {
    gchar *exec;
    exec = g_strdup_printf ("%s %s", GCONF_LOAD, filename);
    g_spawn_command_line_sync (exec, NULL, NULL, NULL, NULL);
    g_free (exec);

    g_debug ("\nRestored panel configuration from: %s\n", filename);
  }
  else
  {
    gdk_spawn_command_line_on_screen (screen, 
                                      GCONF_LOAD SHARE_NETBOOK_PANEL_CONFIG,
                                      NULL);
    g_debug ("\nRestored panel configuration from defaults\n");
  }
  gdk_spawn_command_line_on_screen (screen, "killall gnome-panel", NULL);
  gdk_spawn_command_line_on_screen (screen, "gnome-panel", NULL);

  /* Remove nautilus from the session required components list */
  g_debug ("Removing nautilus from gnome session startup");
  GSList *comps = NULL;
  comps = g_slist_append (comps, g_strdup ("windowmanager"));
  comps = g_slist_append (comps, g_strdup ("panel"));
  gconf_client_set_list (client, SESSION_COMPONENTS, GCONF_VALUE_STRING,
                         comps, NULL);
  g_slist_foreach (comps, (GFunc)g_free, NULL);
  g_slist_free (comps);
 
  g_object_unref (client);
  g_free (filename);
}
  
static void
enable_classic ()
{
  GError *error = NULL;
  gchar *filename;
  GConfClient *client = gconf_client_get_default ();
  GdkScreen *screen = gdk_screen_get_default ();

  g_debug ("Enabling classic mode");

  /* Stop the launcher from autostarting.
     We do both because we can't be sure which launcher user is using.  We
     could check which is running, but that might not be the same as what is
     installed, if the user just did an upgrade.  No harm in handling both. */
  g_debug ("Suppressing Launcher autostart");
  create_launcher_autostart_file (LAUNCHER_DESKTOP);
  create_launcher_autostart_file (OLD_LAUNCHER_DESKTOP);

  /* Tell GNOME to disallow user switching */
  error = NULL;
  gconf_client_set_bool (client, GNOME_SWITCH_USER_DISABLED, TRUE, &error);
  if (error)
  {
    g_warning ("Can't make GNOME allow user switching: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Tell screensaver to disallow user switching */
  error = NULL;
  gconf_client_set_bool (client, SCREENSAVER_SWITCH_USER_ENABLED, FALSE, &error);
  if (error)
  {
    g_warning ("Can't make screensaver allow user switching: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Tell nautilus to draw the desktop */
  error = NULL;
  gconf_client_set_bool (client, NAUTILUS_SHOW_DESKTOP, TRUE, &error);
  if (error)
  {
    g_warning ("Can't make Nautilus draw the desktop: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }
  gdk_spawn_command_line_on_screen (screen, "nautilus -n", NULL);

  /* Set the theme */
  error = NULL;
  gconf_client_set_string (client, THEME, "Human", &error);
  if (error)
  {
    g_warning ("Can't change the theme: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Set Maximus */
  error = NULL;
  gconf_client_set_bool (client, MAXIMUS, FALSE, &error);
  if (error)
  {
    g_warning ("Can't change Maximus's undecorate setting: %s", 
               error->message);
    g_error_free (error);
    error = NULL;
  }

  /* Kill any version of the launcher. */
  g_debug ("Killing the launcher");
  gdk_spawn_command_line_on_screen (screen, "killall "LAUNCHER_NAME, NULL);
  gdk_spawn_command_line_on_screen (screen, "killall "OLD_LAUNCHER_NAME, NULL);

  sleep (1);

  /* Save current panel configuration */
  filename = g_build_filename (g_get_home_dir (), ".config/desktop-switcher",
                               CLASSIC_PANEL_CONFIG, NULL);
  g_spawn_command_line_sync (GCONF_DUMP_NETBOOK_PANEL, NULL, NULL, NULL, NULL);
      
  /* Set the panel to the netbook layout */
  g_debug ("Restoring panel settings");
  gdk_spawn_command_line_on_screen (screen, GCONF_STOP, NULL);
  gdk_spawn_command_line_on_screen (screen, GCONF_UNSET, NULL);
  if (g_file_test (filename, G_FILE_TEST_EXISTS))
  {
    gchar *exec;
    exec = g_strdup_printf ("%s %s", GCONF_LOAD, filename);
    g_spawn_command_line_sync (exec, NULL, NULL, NULL, NULL);
    g_free (exec);
    g_debug ("\nRestored panel configuration from: %s\n", filename);
  }
  else
  {
    gdk_spawn_command_line_on_screen (screen, 
                                      GCONF_LOAD SHARE_CLASSIC_PANEL_CONFIG,
                                      NULL);
    g_debug ("\nRestored panel configuration from defaults\n");
  }

  gdk_spawn_command_line_on_screen (screen, "killall gnome-panel", NULL);
  gdk_spawn_command_line_on_screen (screen, "gnome-panel", NULL);

  /* Add nautilus back to the required components in the session */
  GSList *comps = NULL;
  comps = g_slist_append (comps, g_strdup ("panel"));
  comps = g_slist_append (comps, g_strdup ("filemanager"));
  comps = g_slist_append (comps, g_strdup ("windowmanager"));
  gconf_client_set_list (client, SESSION_COMPONENTS, GCONF_VALUE_STRING,
                         comps, NULL);
  g_slist_foreach (comps, (GFunc)g_free, NULL);
  g_slist_free (comps);
  
  gdk_spawn_command_line_on_screen (screen, "metacity --replace", NULL);
  gdk_spawn_command_line_on_screen (screen, "nautilus", NULL);

  g_free (filename);
  g_object_unref (client);
}

void
on_apply_clicked (GtkButton *button)
{
  if (current_mode == selected_mode)
    gtk_main_quit ();
  else if (selected_mode == NETBOOK_MODE)
    enable_netbook ();
  else
    enable_classic ();

  gtk_main_quit ();
}
