/*
 * Copyright (c) 2003 Benedikt Meurer (benedikt.meurer@unix-ag.uni-siegen.de)
 *               2004-2006 Jean-François Wauthy (pollux@xfce.org)
 *
 * This program 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; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * 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 Library General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef	HAVE_CONFIG_H
#include <config.h>
#endif /* !HAVE_CONFIG_H */

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include <gtk/gtk.h>
#include <libxfce4util/libxfce4util.h>
#include <libxfcegui4/libxfcegui4.h>

#include <libxfprint/common.h>
#include <libxfprint/printing-system.h>
#include <libxfprint/printer-queue-window.h>
#include <libxfprint/printer-list-window.h>

#define PRINTER_LIST_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
                                              PRINTER_LIST_WINDOW_TYPE, PrinterListWindowPrivate))

#define STATUS_IDLE_FORMAT "<span style='italic' color='dark green'>%s</span>"
#define STATUS_PROCESSING_FORMAT "<span style='italic' color='blue'>%s</span>"
#define STATUS_STOPPED_FORMAT "<span color='red'>%s</span>"
#define STATUS_UNKNOWN_FORMAT "<span color='grey'>%s</span>"

struct _PrinterListWindowPrivate
{
  PrintingSystem *ps;

  GtkIconTheme *icontheme;
  GtkUIManager *ui_manager;

  GtkWidget *treeview;

  guint timeout_id;
};

/* prototypes */
static void printer_list_window_class_init (PrinterListWindowClass * klass);
static void printer_list_window_init (PrinterListWindow * obj);

static void load_printer_list_in_treeview (PrinterListWindow * win);
static void icon_theme_changed_cb (GtkIconTheme * icon_theme, PrinterListWindow * win);

static void tree_view_row_activated_cb (GtkWidget * widget, GtkTreePath * path, GtkTreeViewColumn * col,
                                        PrinterListWindow * win);

static gboolean update_jobs_and_states (PrinterListWindow * win);

static void action_quit_cb (GtkAction * action, PrinterListWindow * win);
static void action_about_cb (GtkAction * action, PrinterListWindow * win);

/* globals */
static GtkWindowClass *parent_class = NULL;
static GtkActionEntry action_entries[] = {
  {"printer-menu", NULL, N_("Printer"), NULL,},
  {"quit", GTK_STOCK_QUIT, N_("Quit"), NULL, N_("Quit xfprint4-manager"), G_CALLBACK (action_quit_cb),},
  {"about-menu", NULL, N_("About"), NULL,},
  {"about", GTK_STOCK_ABOUT, N_("About xfprint4-manager"), NULL,
   N_("Display informations about xfprint4-manager"), G_CALLBACK (action_about_cb),},
};


/*********/
/* class */
/*********/
GType
printer_list_window_get_type ()
{
  static GType type = 0;

  if (type == 0) {
    static const GTypeInfo our_info = {
      sizeof (PrinterListWindowClass),
      NULL,
      NULL,
      (GClassInitFunc) printer_list_window_class_init,
      NULL,
      NULL,
      sizeof (PrinterListWindow),
      0,
      (GInstanceInitFunc) printer_list_window_init,
    };

    type = g_type_register_static (GTK_TYPE_WINDOW, "PrinterListWindow", &our_info, 0);
  }

  return type;
}

static void
printer_list_window_init (PrinterListWindow * win)
{
  PrinterListWindowPrivate *priv;
  GError *error = NULL;
  GtkActionGroup *action_group;
  GtkAccelGroup *accel_group;

  GtkTreeSelection *selection;
  GtkWidget *menubar;

  GtkWidget *scrollwin;
  GtkWidget *vbox;
  GtkListStore *store;
  GtkCellRenderer *cell;
  GtkTreeViewColumn *column;

  priv = win->priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);

  priv->icontheme = gtk_icon_theme_get_default ();
  g_signal_connect (G_OBJECT (priv->icontheme), "changed", G_CALLBACK (icon_theme_changed_cb), win);

  gtk_window_set_icon_name (GTK_WINDOW (win), "printer");
  gtk_window_set_default_size (GTK_WINDOW (win), 450, 250);
  gtk_window_set_title (GTK_WINDOW (win), _("Printer manager"));

  /* ui manager */
  action_group = gtk_action_group_new ("printer-list-default");
  gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
  gtk_action_group_add_actions (action_group, action_entries, G_N_ELEMENTS (action_entries), GTK_WIDGET (win));

  priv->ui_manager = gtk_ui_manager_new ();
  gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, 0);

  if (gtk_ui_manager_add_ui_from_string (priv->ui_manager,
                                         "<ui>"
                                         "<menubar name=\"main-menu\">"
                                         " <menu action=\"printer-menu\">"
                                         "   <placeholder name=\"printer-menu-additions\"/>"
                                         "   <separator/>"
                                         "   <menuitem action=\"quit\"/>"
                                         " </menu>"
                                         " <menu action=\"about-menu\">"
                                         "   <menuitem action=\"about\"/>"
                                         " </menu>" "</menubar>" "</ui>", -1, &error) == 0) {
    g_warning ("Unable to build the user interface correctly : %s", error->message);
    g_error_free (error);
  }
  gtk_ui_manager_ensure_update (priv->ui_manager);

  accel_group = gtk_ui_manager_get_accel_group (priv->ui_manager);
  gtk_window_add_accel_group (GTK_WINDOW (win), accel_group);

  /* contents */
  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (win), vbox);

  /* menubar */
  menubar = gtk_ui_manager_get_widget (priv->ui_manager, "/main-menu");
  if (G_LIKELY (menubar != NULL)) {
    gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
    gtk_widget_show (menubar);
  }

  /* the printer list store */
  store = gtk_list_store_new (PRINTERS_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
                              G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);

  /* The printer list view */
  scrollwin = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_box_pack_start (GTK_BOX (vbox), scrollwin, TRUE, TRUE, 0);

  priv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
  gtk_container_add (GTK_CONTAINER (scrollwin), priv->treeview);

  /* configure the tree selection for the printer list */
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);

  cell = gtk_cell_renderer_pixbuf_new ();
  column = gtk_tree_view_column_new ();
  gtk_tree_view_column_pack_start (column, cell, FALSE);
  gtk_tree_view_column_set_attributes (column, cell, "pixbuf", PRINTERS_ICON_COLUMN, NULL);
  g_object_set (cell, "xalign", 0.0, "ypad", 0, NULL);

  cell = gtk_cell_renderer_text_new ();
  gtk_tree_view_column_pack_start (column, cell, TRUE);
  gtk_tree_view_column_set_attributes (column, cell, "markup", PRINTERS_ALIAS_COLUMN, NULL);
  g_object_set (cell, "ypad", 0, "yalign", 0.5, NULL);
  gtk_tree_view_column_set_title (column, _("Alias name"));
  gtk_tree_view_append_column (GTK_TREE_VIEW (priv->treeview), column);

  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->treeview), PRINTERS_STATE_COLUMN,
                                               _("State"), gtk_cell_renderer_text_new (), "markup",
                                               PRINTERS_STATE_COLUMN, NULL);

  /* the view now holds a reference of the store */
  g_object_unref (G_OBJECT (store));

  gtk_widget_show_all (vbox);

  /* Select nothing in the list */
  gtk_tree_selection_unselect_all (selection);
}

static void
printer_list_window_finalize (GObject * object)
{
  PrinterListWindow *cobj;
  PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (object);

  cobj = PRINTER_LIST_WINDOW (object);

  if (priv->timeout_id > 0)
    g_source_remove (priv->timeout_id);

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

static void
printer_list_window_class_init (PrinterListWindowClass * klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  g_type_class_add_private (klass, sizeof (PrinterListWindowPrivate));

  parent_class = g_type_class_peek_parent (klass);

  object_class->finalize = printer_list_window_finalize;
}

/* actions */
static void
action_quit_cb (GtkAction * action, PrinterListWindow * win)
{
  gtk_widget_destroy (GTK_WIDGET (win));
  gtk_main_quit ();
}

static void
action_about_cb (GtkAction * action, PrinterListWindow * win)
{
  XfceAboutInfo *info;
  PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);
  GtkWidget *dialog;
  GdkPixbuf *icon;

  info = xfce_about_info_new ("xfprint-manager", VERSION, _("Xfprint printers manager"),
                              XFCE_COPYRIGHT_TEXT ("2003-2006", "Xfce4 Team"), XFCE_LICENSE_GPL);
  xfce_about_info_set_homepage (info, "http://www.xfce.org/");

  /* Credits */
  xfce_about_info_add_credit (info, "Benedikt Meurer", "benny@xfce.org", _("Former maintainer"));
  xfce_about_info_add_credit (info, "Jean-Francois Wauthy", "pollux@xfce.org", _("Maintainer"));

  icon = gtk_icon_theme_load_icon (priv->icontheme, "printer", 48, 0, NULL);

  dialog = xfce_about_dialog_new_with_values (GTK_WINDOW (win), info, icon);

  gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
  xfce_about_info_free (info);

  gtk_dialog_run (GTK_DIALOG (dialog));

  gtk_widget_destroy (dialog);

  g_object_unref (icon);
}

static void
load_printer_list_in_treeview (PrinterListWindow * win)
{
  PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);
  GtkListStore *store;
  GtkTreeIter iter;
  GList *printers = NULL, *printer_el = NULL;
  Printer *printer = NULL;
  GtkTreeSelection *selection;
  gchar *default_printer;

  store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview)));
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
  printer = printing_system_get_default_printer (priv->ps);
  if (printer)
    default_printer = g_strdup (printer->name);
  else
    default_printer = g_strdup ("");

  printers = printer_el = printing_system_get_printers (priv->ps);
  while (printer_el) {
    GdkPixbuf *icon = NULL;
    gint num_jobs = 0;
    gchar *num_jobs_str = NULL;
    gint state;
    gchar *state_str = NULL;
    gint x, y;

    if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &x, &y))
      x = 48;

    printer = printer_el->data;
    if (g_strrstr (printer->name, "/")) {       /* instance ? */
      printer_el = g_list_next (printer_el);
      continue;
    }
    if (printer->type == PRINTER_TYPE_CLASS)
      icon = gtk_icon_theme_load_icon (priv->icontheme, "printer-class", x, 0, NULL);
    if (!icon || printer->type == PRINTER_TYPE_PRINTER)
      icon = gtk_icon_theme_load_icon (priv->icontheme, "printer", x, 0, NULL);

    num_jobs = printing_system_get_jobs_count (priv->ps, printer->name);
    num_jobs_str = g_strdup_printf ("%d", num_jobs);

    state = printing_system_get_printer_state (priv->ps, printer->name);
    switch (state) {
    case PRINTER_STATE_UNKNOWN:
      state_str = g_strdup_printf (STATUS_UNKNOWN_FORMAT, _("Unknown"));
      break;
    case PRINTER_STATE_IDLE:
      state_str = g_strdup_printf (STATUS_IDLE_FORMAT, _("Idle"));
      break;
    case PRINTER_STATE_PROCESSING:
      state_str = g_strdup_printf (STATUS_PROCESSING_FORMAT, _("Processing"));
      break;
    case PRINTER_STATE_STOPPED:
      state_str = g_strdup_printf (STATUS_STOPPED_FORMAT, _("Stopped"));
    }

    gtk_list_store_append (store, &iter);
    gtk_list_store_set (store, &iter,
                        PRINTERS_ICON_COLUMN, icon,
                        PRINTERS_ALIAS_COLUMN, printer->alias, PRINTERS_NAME_COLUMN, printer->name,
                        PRINTERS_JOBS_COLUMN, num_jobs_str, PRINTERS_STATE_COLUMN, state_str, -1);
    g_free (num_jobs_str);
    g_free (state_str);

    if (strcmp (default_printer, printer->name) == 0)
      gtk_tree_selection_select_iter (selection, &iter);

    if (icon)
      g_object_unref (G_OBJECT (icon));

    printer_el = g_list_next (printer_el);
  }
  printers_free (printers);
  g_free (default_printer);
}

/**********************/
/* Icontheme callback */
/**********************/
static gboolean
icon_theme_update_foreach_func (GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, PrinterListWindow * win)
{
  PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);
  GdkPixbuf *icon = NULL;
  gchar *name = NULL;
  Printer *printer = NULL;

  gtk_tree_model_get (model, iter, PRINTERS_ICON_COLUMN, &icon, PRINTERS_NAME_COLUMN, &name, -1);

  if (model) {
    gtk_list_store_clear (GTK_LIST_STORE (model));
    load_printer_list_in_treeview (win);
  }

  if (icon)
    g_object_unref (icon);

  // FIXME
  //printer = printer_lookup_byname (printers_list, name);

  if (printer->type == PRINTER_TYPE_CLASS)
    icon = gtk_icon_theme_load_icon (priv->icontheme, "printer-class", 48, 0, NULL);
  if (!icon || printer->type == PRINTER_TYPE_PRINTER)
    icon = gtk_icon_theme_load_icon (priv->icontheme, "printer", 48, 0, NULL);

  gtk_list_store_set (GTK_LIST_STORE (model), iter, PRINTERS_ICON_COLUMN, icon, -1);

  g_object_unref (icon);
  g_free (name);
  return FALSE;
}

/***********************/
/* Mainwindow callback */
/***********************/
/* Callbacks */

static void
icon_theme_changed_cb (GtkIconTheme * icon_theme, PrinterListWindow * win)
{
  GtkTreeModel *model;
  PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);

  model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));

  if (model)
    gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) & icon_theme_update_foreach_func, win);
}

/**********************/
/* Treeview callbacks */
/**********************/
static void
tree_view_row_activated_cb (GtkWidget * widget, GtkTreePath * path, GtkTreeViewColumn * col, PrinterListWindow * win)
{
  gchar *printer = NULL;

  printer = printer_list_window_get_selected_printer (win);

  if (printer) {
    PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);
    GtkWidget *dialog;

    dialog = printer_queue_window_new (priv->ps, printer);
    gtk_widget_show (dialog);
  }

  g_free (printer);
}

/**************************/
/* Update jobs and states */
/**************************/
static gboolean
update_jobs_and_states (PrinterListWindow * win)
{
  PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);
  GtkTreeModel *model;

  //TODO memoriser selection
  model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));

  if (model) {
    gtk_list_store_clear (GTK_LIST_STORE (model));
    load_printer_list_in_treeview (win);

    return TRUE;
  }

  return FALSE;
}

/********************/
/* public functions */
/********************/
gchar *
printer_list_window_get_selected_printer (PrinterListWindow * win)
{
  PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);
  GtkTreeSelection *selection;
  GtkTreeModel *model;
  GtkTreeIter iter;
  gchar *printer = NULL;

  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
  if (selection && gtk_tree_selection_get_selected (selection, &model, &iter))
    gtk_tree_model_get (model, &iter, PRINTERS_NAME_COLUMN, &printer, -1);

  return printer;
}

GtkUIManager *
printer_list_window_get_ui_manager (PrinterListWindow * win)
{
  return PRINTER_LIST_WINDOW_GET_PRIVATE (win)->ui_manager;
}

void
printer_list_window_hide_column (PrinterListWindow * win, PrinterListWindowColumn column)
{
  PrinterListWindowPrivate *priv = PRINTER_LIST_WINDOW_GET_PRIVATE (win);
  GtkTreeViewColumn *tree_column;

  tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), column);

  gtk_tree_view_column_set_visible (tree_column, FALSE);
}

GtkWidget *
printer_list_window_new (PrintingSystem * ps)
{
  GObject *obj;
  PrinterListWindowPrivate *priv;

  obj = g_object_new (PRINTER_LIST_WINDOW_TYPE, NULL);
  priv = PRINTER_LIST_WINDOW_GET_PRIVATE (obj);

  if (ps) {
    priv->ps = ps;

    /* load the printer list in the treeview */
    load_printer_list_in_treeview (PRINTER_LIST_WINDOW (obj));

    g_signal_connect (G_OBJECT (priv->treeview), "row-activated", G_CALLBACK (tree_view_row_activated_cb), obj);

    /* Refresh job list every 3 sec */
    priv->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 3000, (GSourceFunc) update_jobs_and_states,
                                           PRINTER_LIST_WINDOW (obj), NULL);

    /* customize the dialog for the printing system */
    printing_system_customize_printer_list_window (ps, PRINTER_LIST_WINDOW (obj));
  }
  else {
    gtk_widget_set_sensitive (priv->treeview, FALSE);
  }

  return GTK_WIDGET (obj);
}
