/* -*- Mode: C; indent-tabs-mode: nil; tab-width: 2 -*-
 *
 * Copyright (C) 2008 Canonical Ltd.
 * Authors:
 *  Neil Jagdish Patel <neil.patel@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/>.
 */

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

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

#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-bindings.h>

#include <libgnomeui/gnome-client.h>

#include "nl-quit.h"

#include "gdm-queue.h"

#define GDM_FLEXISERVER_COMMAND "gdmflexiserver"
#define GDM_FLEXISERVER_ARGS    "--startnew Standard"

#define DIALOG_MAX_WIDTH_SCALE 0.9
#define DIALOG_MAX_HEIGHT_SCALE 0.9

static void
gdm_restart_state_cb (GdmResultState  is_ok,
                      const gchar    *answer,
                      gpointer        data)
{
  GnomeClient *client;

  if (is_ok != GDM_RESULT_OK)
    {
      g_warning ("GDM Command Failed: %s", answer ? answer : "ERROR");
      return;
    }

  if (!(client = gnome_master_client ()))
    return;

  gnome_client_request_save (client, GNOME_SAVE_GLOBAL, TRUE,
                             GNOME_INTERACT_ANY, TRUE, TRUE);
  return;
}

static void
activate_session (gchar *command)
{
  queue_authentication (gdk_screen_get_default ());
  ask_gdm (gdm_restart_state_cb, NULL, command);
}

static void
_logout (GtkButton *button, GtkDialog *dialog)
{
  g_debug ("Log out");
  activate_session (GDM_CMD_SET_SAFE_LOGOUT_ACTION " " GDM_CMD_LOGOUT_ACTION_NONE);
  gtk_dialog_response (dialog, 1);
}

static void
_switchuser (GtkButton *button, GtkDialog *dialog)
{
  gchar *command;

  g_debug ("Switch user");

  command = g_strdup_printf ("%s %s",
                             GDM_FLEXISERVER_COMMAND,
                             GDM_FLEXISERVER_ARGS);
  g_spawn_command_line_async (command, NULL);

  g_free (command);

  gtk_dialog_response (dialog, 1);
}

static void
_shutdown (GtkButton *button, GtkDialog *dialog)
{
  g_debug ("Shutdown");
  activate_session (GDM_CMD_SET_SAFE_LOGOUT_ACTION " " GDM_CMD_LOGOUT_ACTION_HALT);
  gtk_dialog_response (dialog, 1);
}

static void
_restart (GtkButton *button, GtkDialog *dialog)
{
  g_debug ("Restart");
  activate_session (GDM_CMD_SET_SAFE_LOGOUT_ACTION  " " GDM_CMD_LOGOUT_ACTION_REBOOT);
  gtk_dialog_response (dialog, 1);
}

static void
_lockscreen (GtkButton *button, GtkDialog *dialog)
{
  g_debug ("Lock screen");
  g_spawn_command_line_async ("gnome-screensaver-command --lock", NULL);
  gtk_dialog_response (dialog, 1);
}

static void
power_manager_call (const gchar *function)
{
  DBusGConnection *conn;
  DBusGProxy      *proxy;

  conn = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);

  proxy = dbus_g_proxy_new_for_name_owner (conn,
          "org.freedesktop.PowerManagement",
          "/org/freedesktop/PowerManagement",
          "org.freedesktop.PowerManagement",
          NULL);

  dbus_g_proxy_call_no_reply (proxy, function, G_TYPE_INVALID, G_TYPE_INVALID);

  g_object_unref (proxy);
}

static void
_suspend (GtkButton *button, GtkDialog *dialog)
{
  g_debug ("Suspend");
  power_manager_call ("Suspend");
  gtk_dialog_response (dialog, 1);
}

static void
_hibernate (GtkButton *button, GtkDialog *dialog)
{
  g_debug ("Hibernate");
  power_manager_call ("Hibernate");
  gtk_dialog_response (dialog, 1);
}

static GtkWidget *
make_dialog (gboolean can_suspend, gboolean can_hibernate)
{
  GtkBuilder *builder;
  GError     *error = NULL;
  GtkWidget  *window;
  GdkScreen  *screen;
  GdkGeometry geo;
  builder = gtk_builder_new ();
  gtk_builder_add_from_file (builder, PKGDATADIR"/logout-dialog.xml", &error);

  if (!builder)
    {
      if (error)
        {
          g_warning ("%s", error->message);
          g_error_free (error);
        }
      else
        {
          g_warning ("Unable to open logout dialog UI file");
        }
      return NULL;
    }

  gtk_builder_connect_signals (builder, NULL);

  window = GTK_WIDGET (gtk_builder_get_object (builder, "dialog1"));

  g_signal_connect (gtk_builder_get_object (builder, "logoutbutton"),
                    "clicked",
                    G_CALLBACK (_logout), window);

  g_signal_connect (gtk_builder_get_object (builder, "switchuserbutton"),
                    "clicked",
                    G_CALLBACK (_switchuser), window);

  g_signal_connect (gtk_builder_get_object (builder, "lockscreenbutton"),
                    "clicked",
                    G_CALLBACK (_lockscreen), window);

  g_signal_connect (gtk_builder_get_object (builder, "shutdownbutton"),
                    "clicked",
                    G_CALLBACK (_shutdown), window);

  g_signal_connect (gtk_builder_get_object (builder, "restartbutton"),
                    "clicked",
                    G_CALLBACK (_restart), window);

  g_signal_connect (gtk_builder_get_object (builder, "suspendbutton"),
                    "clicked",
                    G_CALLBACK (_suspend), window);

  g_signal_connect (gtk_builder_get_object (builder, "hibernatebutton"),
                    "clicked",
                    G_CALLBACK (_hibernate), window);

  g_signal_connect_swapped (gtk_builder_get_object (builder, "button1"),
                            "clicked",
                            G_CALLBACK (gtk_widget_destroy), window);

  g_signal_connect (window, "focus_out_event", G_CALLBACK (gtk_widget_destroy),
                    window);

  if (!can_suspend)
    gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder,
                                 "suspendbutton")));

  if (!can_hibernate)
    gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder,
                                 "hibernatebutton")));

  screen = gtk_window_get_screen (GTK_WINDOW (window));
  geo.max_width = DIALOG_MAX_WIDTH_SCALE * gdk_screen_get_width (screen);
  geo.max_height = DIALOG_MAX_HEIGHT_SCALE * gdk_screen_get_height (screen);
  gtk_window_set_geometry_hints (GTK_WINDOW (window), NULL, &geo, GDK_HINT_MAX_SIZE);

  return window;
}

GtkWidget *
nl_quit_new (void)
{
  DBusGConnection *conn;
  DBusGProxy      *proxy;
  gboolean         can_suspend;
  gboolean         can_hibernate;
  GError          *error = NULL;

  can_suspend = FALSE;
  can_hibernate = FALSE;

  conn = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
  if (conn == NULL)
    {
      g_warning ("Unable to retrieve D-Bus Session Bus");
      return NULL;
    }

  proxy = dbus_g_proxy_new_for_name_owner (conn,
          "org.freedesktop.PowerManagement",
          "/org/freedesktop/PowerManagement",
          "org.freedesktop.PowerManagement",
          NULL);
  if (proxy == NULL)
    {
      g_warning ("Unable to connect to power manangement interface");
      return make_dialog (FALSE, FALSE);
    }

  dbus_g_proxy_call (proxy, "CanHibernate", &error,
                     G_TYPE_INVALID,
                     G_TYPE_BOOLEAN, &can_hibernate,
                     G_TYPE_INVALID);
  if (error)
    {
      g_warning ("%s", error->message);
      g_error_free (error);
      error = NULL;
    }

  dbus_g_proxy_call (proxy, "CanSuspend", &error,
                     G_TYPE_INVALID,
                     G_TYPE_BOOLEAN, &can_suspend,
                     G_TYPE_INVALID);
  if (error)
    {
      g_warning ("%s", error->message);
      g_error_free (error);
      error = NULL;
    }

  g_object_unref (proxy);

  g_debug ("Computer %s suspend and %s hibernate",
           can_suspend ? "can" : "can't",
           can_hibernate ? "can" : "can't");

  return make_dialog (can_suspend, can_hibernate);
}
