/*
 * GULP: The Gnome printer controller
 *
 * Authors: Elliot Lee (sopwith@cuc.edu)
 *          Federico Mena (federico@nuclecu.unam.mx)
 *
 */
#include <config.h>
#include <objc/Object.h>
#include "gPrint.h"
#include <stdio.h>
#include "yes.xpm"
#include "no.xpm"

#include "gulp.h"

#ifndef GNOMELOCALEDIR
#define GNOMELOCALEDIR "/usr/share/locale"
#endif

#include <libgnome/gnome-i18n.h>

void
do_message(char *msg)
{
	GtkWidget *msgbox = gnome_message_box_new(msg,
				GNOME_MESSAGE_BOX_WARNING, _("Close"), NULL);
	gnome_dialog_run(GNOME_DIALOG(msgbox));
}

@implementation GULPMainWin
- menu_help_about:(id) anobj
{
	GtkWidget *about;
	static const char *authors[] = {
		N_("Elliot Lee (sopwith@cuc.edu)"),
		N_("Federico Mena (quartic@gimp.org)"),
		NULL
	};
	
	about = gnome_about_new ( _("GULP"), VERSION,
				  /* copyright notice */
				  _("(C) 1998 the Free Software Foundation"),
				  authors,
			 /* another comments */
				  _("GNOME Unified Link to Printers program."),
				  NULL);
	gtk_widget_show (about);
	
	return self;
}

- menu_file_exit:(id) anobj
{
  [app quit];

  return self;
}

- delete_event:(id) anobj :(GdkEvent *) event
{
  [app quit];
  return (id)TRUE;
}

@end

@implementation GULPApp

- destroy:(id) obj
{
  gtk_main_quit();
  return self;
}

- toggled:(id) obj
{
  int opstatus = 0;
  id curprinter = nil;

  if (!dotogglehandler)
    return self;

  if (printer_list->gtkclist->selection)
    curprinter = [printer_list get_row_data:GPOINTER_TO_INT(printer_list->gtkclist->selection->data)];
  
  if (curprinter == nil)
    {
	do_message(_("You must select a printer"));
      return self;
    }
    
  if (obj == queueing)
    {
      [self set_wait_cursor:TRUE];
      
      if (((Gtk_CheckButton *) obj)->gtktogglebutton->active)
	opstatus = [curprinter up];
      else
	opstatus = [curprinter down];

      [self set_wait_cursor:FALSE];
    }
  else if (obj == printing)
    {
      [self set_wait_cursor:TRUE];
      
      if (((Gtk_CheckButton *) obj)->gtktogglebutton->active)
	opstatus = [curprinter start];
      else
	opstatus = [curprinter stop];

      [self set_wait_cursor:FALSE];
    }

  /* Let user know about any errors that happened */
  if (opstatus)
    {
	do_message(_("Operation failed"));
      dotogglehandler = 0;
      [(Gtk_CheckButton *) obj
			   set_state:!((Gtk_CheckButton *) obj)->gtktogglebutton->active];
      dotogglehandler = 1;
    }

  [self do_printer_list];

  return self;
}

- clicked:(id) obj
{
  id curprinter = nil, tmp;
  int opstatus = 0;

  if (printer_list->gtkclist->selection)
    curprinter = [printer_list get_row_data:GPOINTER_TO_INT(printer_list->gtkclist->selection->data)];

  if (curprinter == nil)
    {
	do_message(_("You must select a printer"));
      return self;
    }
	
  if (obj == cancel_job)
    {
      if (job_list->gtkclist->selection)
	{
	  GList *anitem;
	  for (anitem = job_list->gtkclist->selection; anitem; anitem = anitem->next)
	    {
	      tmp = [job_list get_row_data:GPOINTER_TO_INT(anitem->data)];
	      [self set_wait_cursor:TRUE];
	      [tmp cancel];
	      [self set_wait_cursor:FALSE];
	    }
	}
      else
	do_message(_("You must select a job"));
    }
  else if (obj == clear_queue)
    {
      [self set_wait_cursor:TRUE];
      opstatus = [curprinter clean];
      [self set_wait_cursor:FALSE];
    }
  else if (obj == restart)
    {
      [self set_wait_cursor:TRUE];
      opstatus = [curprinter restart];
      [self set_wait_cursor:FALSE];
    }
  else
    printf(_("Click on unknown widget\n"));
	
  if (opstatus)
	do_message(_("Operation failed"));

  [[self do_printer_list] do_job_list];

  dotogglehandler = 0;
  [self set_wait_cursor:TRUE];
  [queueing set_state:[curprinter isUp]];
  [printing set_state:[curprinter isStarted]];
  [self set_wait_cursor:FALSE];
  dotogglehandler = 1;

  return self;
}

- select_row:(id) obj :(gint) row :(gint) column :(GdkEventButton *) event
{
  if (obj == printer_list && doselecthandler)
    [self do_job_list];
  if (obj == job_list)
    [cancel_job set_sensitive:TRUE];
  return self;
}

- do_job_list
{
  int i;
  Printer *newprt;
  char idbuf[30], sizebuf[10];
  gchar *vals[4];
  static const char *collist[] = {
    N_("Job ID"),
    N_("Filenames"),
    N_("Size"),
    N_("Owner")
  };
  int oldoffset = -1;
  GList *anitem;

  [self set_wait_cursor:TRUE];

  if (job_list)
    {
      if (job_list->gtkclist->selection)
	{
	  for (i = 0, anitem = job_list->gtkclist->row_list; anitem; i++, anitem = anitem->next)
	    if (anitem->data == job_list->gtkclist->selection->data)
	      {
		oldoffset = i;
		break;
	      }
	}
      
      [[job_list freeze] clear];
    }
  else
    {
      job_list = [[[[Gtk_CList alloc] initWithCListInfoTitles:4 Titles:collist] show] freeze];
      [job_list set_selection_mode:GTK_SELECTION_BROWSE];
      [job_list set_column_width:0 :40];
      [job_list set_column_width:1 :200];
      [job_list set_column_width:2 :40];
    }

  if (printer_list->gtkclist->selection)
    {
      newprt = [printer_list get_row_data:GPOINTER_TO_INT(printer_list->gtkclist->selection->data)];
      [newprt getJobs];
    }
  else
    newprt = nil;

  dotogglehandler = FALSE;
  [queueing set_state:[newprt isUp]];
  [printing set_state:[newprt isStarted]];
  dotogglehandler = TRUE;

  vals[0] = idbuf;
  vals[2] = sizebuf;

  [cancel_job set_sensitive:FALSE];

  if(newprt)
    {
      if (newprt->numjobs > 0)
	[cancel_job set_sensitive:TRUE];

      for (i = 0; i < newprt->numjobs; i++)
	{
	  sprintf(vals[0], "%d", [newprt->jobs[i] getJobID]);
	  vals[1] = (char *) [newprt->jobs[i] getJobFilenames];
	  sprintf(vals[2], "%d", [newprt->jobs[i] getJobSize]);
	  vals[3] = (char *) [newprt->jobs[i] getJobOwner];
	  [job_list set_row_data:[job_list appendCListRow:(const char **)vals] rowData:newprt->jobs[i]];
	}
      if (oldoffset >= 0)
	[job_list select_row:oldoffset :0];
    }

  [job_list thaw];

  [self set_wait_cursor:FALSE];

  return self;
}

- do_printer_list
{
  gchar *columns[] = {
    N_("Printer"),
    N_("Jobs"),
    N_("Queueing"),
    N_("Printing")
  };
  gchar *tmp;
  Printer *cp;
  int i, cnt;
  int oldoffset = -1;
  GList *anitem;
  id printer;

  [self set_wait_cursor:TRUE];

  doselecthandler = FALSE;
  if (printer_list)
    {
      if (printer_list->gtkclist->selection)
	{
	  for (i = 0, anitem = printer_list->gtkclist->row_list; anitem; i++, anitem = anitem->next)
	    if (anitem->data == [printer_list get_row_data:GPOINTER_TO_INT(printer_list->gtkclist->selection->data)])
	      {
		oldoffset = i;
		g_print(_("oldoffset for printer_list is %d\n"),
			oldoffset);
		break;
	      }
	}
      
      [[printer_list freeze] clear];
    }
  else
    {
      printer_list = [[[[Gtk_CList alloc] initWithCListInfoTitles:4 Titles:(const char **)columns] show] freeze];
      [printer_list set_selection_mode:GTK_SELECTION_BROWSE];
      [printer_list connectObj:"select_row" :self];
      [printer_list set_column_width:0 :60];
      [printer_list set_column_width:1 :30];
      [printer_list set_column_width:2 :60];
    }

  tmp = g_malloc(10);

  for (cnt = 0; cnt < printsys->numprinters; cnt++)
    {
      i = [printer_list appendCListRow:(const char **)columns];
      g_print(_("Doing row %d\n"), i);
      cp = printsys->printers[cnt];

      [printer_list set_text:i :0 :(char *) [[cp getJobs] getQueueName]];
      g_snprintf(tmp, 10, "%d", cp->numjobs);
      [printer_list set_text:i :1 :tmp];

      if ([cp isUp])
	[printer_list set_pixmap:i :2 :yes_pixmap :yes_mask];
      else
	[printer_list set_pixmap:i :2 :no_pixmap :no_mask];

      if ([cp isStarted])
	[printer_list set_pixmap:i :3 :yes_pixmap :yes_mask];
      else
	[printer_list set_pixmap:i :3 :no_pixmap :no_mask];
      g_print(_("Setting row data %d to %#lx\n"), i, (long) cp);
      [printer_list set_row_data:i rowData:cp];
    }
  g_free(tmp);

  if (oldoffset >= 0)
    {
      [printer_list select_row:oldoffset :0];

      printer = [printer_list get_row_data:GPOINTER_TO_INT(printer_list->gtkclist->selection->data)];

      dotogglehandler = FALSE;
      [queueing set_state:[printer isUp]];
      [printing set_state:[printer isStarted]];
      dotogglehandler = TRUE;
    }

  [printer_list thaw];
  doselecthandler = TRUE;

  [self set_wait_cursor:FALSE];

  return self;
}

/* Probably should have subclassed the Gnome_AppWin widget and
   done everything in there, so sue me */
- initGULP:(char *)app_id
	 :(int)argc
	 :(char **)argv
{
  id  table;
  id  label;
  id  vbox;

  GnomeUIInfo filemenu[] = {
    { GNOME_APP_UI_ITEM, N_("E_xit"), NULL, "menu_file_exit", NULL, NULL, 
	GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_EXIT, 'x', GDK_CONTROL_MASK, NULL},
    { GNOME_APP_UI_ENDOFINFO, NULL, NULL, NULL, NULL, NULL,
	GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL}
  };
  GnomeUIInfo helpmenu[] = {
    { GNOME_APP_UI_HELP, NULL, NULL, "gulp", NULL, NULL,
	GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL},
    { GNOME_APP_UI_ITEM, N_("_About..."), NULL, "menu_help_about", NULL, NULL,
	GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 0, 0, NULL},
    { GNOME_APP_UI_ENDOFINFO, NULL, NULL, NULL, NULL, NULL,
	GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL}
  };
  GnomeUIInfo mainmenu[] = {
    { GNOME_APP_UI_SUBTREE, N_("_Program"), NULL, &filemenu, NULL, NULL,
	GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL},
    { GNOME_APP_UI_SUBTREE, N_("_Help"), NULL, &helpmenu, NULL, NULL,
	GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL},
    { GNOME_APP_UI_ENDOFINFO, NULL, NULL, NULL, NULL, NULL,
	GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL}
  };
	
  self = [super initApp:app_id :VERSION :argc :argv];

  dotogglehandler = doselecthandler = TRUE;
  printer_list = nil;
  job_list = nil;
  printsys = [PrintSystem new];

  if (![printsys exists])
    {
	do_message(_("Printing system not installed/configured."));
      g_print("Printing system not installed\n");
      [printsys free];
      [super free];
      return nil;
    }

  wait_cursor = gdk_cursor_new(GDK_WATCH);

  mainwin = [[GULPMainWin alloc] initWithAppWinInfo:"gulp" : _("GNOME Unified Link to Printers")];

  [mainwin set_usize:550 height:400];
  mainwin->app = self;

  /* Pixmaps */

  [mainwin realize];

  yes_pixmap = gdk_pixmap_create_from_xpm_d(mainwin->gtkwidget->window,
					    &yes_mask,
					    &mainwin->gtkwidget->style->white,
					    yes_xpm);
  no_pixmap = gdk_pixmap_create_from_xpm_d(mainwin->gtkwidget->window,
					   &no_mask,
					   &mainwin->gtkwidget->style->white,
					   no_xpm);

  /* Printer queues */

  table = [[[Gtk_Table alloc] initWithTableInfo:4 cntCols:2 isHomo:FALSE] set_border_width:6];
  [table set_col_spacing:0 Spacing:4];
  [table set_row_spacing:1 Spacing:4];
  [table show];
  [mainwin set_contents:table];

  label = [[[[Gtk_Label alloc] initWithLabel:_("Printer queues")]
	     set_alignment:0.0 alignY:0.5] show];
  [table attach:label
	 attachLeft:0 attachRight:1 attachTop:0 attachBottom:1
	 optionsX:(GTK_EXPAND | GTK_FILL) optionsY:0
	 paddingX:0 paddingY:0];

  [self do_printer_list];
  [table attach:printer_list
	 attachLeft:0 attachRight:1 attachTop:1 attachBottom:2
	 optionsX:(GTK_EXPAND | GTK_FILL) optionsY:(GTK_EXPAND | GTK_FILL)
	 paddingX:0 paddingY:0];

  vbox = [[[Gtk_VBox alloc] initWithBoxInfo:FALSE setSpacing:4] show];
  [table attach:vbox
	 attachLeft:1 attachRight:2 attachTop:1 attachBottom:2
	 optionsX:(GTK_FILL | GTK_SHRINK) optionsY:(GTK_EXPAND | GTK_FILL)
	 paddingX:0 paddingY:0];

  queueing    = [[[[Gtk_CheckButton alloc] initWithLabel:_("Queueing")] show] connectObj:"toggled" :self];
  printing    = [[[[Gtk_CheckButton alloc] initWithLabel:_("Printing")] show] connectObj:"toggled" :self];
  clear_queue = [[[[Gtk_Button alloc]      initWithLabel:_("Clear queue")] show] connectObj:"clicked" :self];
  restart     = [[[[Gtk_Button alloc]      initWithLabel:_("Restart daemon")] show] connectObj:"clicked" :self];

  [vbox pack_start:queueing doExpand:FALSE doFill:FALSE doPadding:0];
  [vbox pack_start:printing doExpand:FALSE doFill:FALSE doPadding:0];
  [vbox pack_start:clear_queue doExpand:FALSE doFill:FALSE doPadding:0];
  [vbox pack_start:restart doExpand:FALSE doFill:FALSE doPadding:0];

  /* Disable these buttons if we are not root */

  if (getuid() != 0)
    [vbox set_sensitive:FALSE];

  /* Jobs */

  label = [[[[Gtk_Label alloc] initWithLabel:_("Jobs for selected printer")]
	     set_alignment:0.0 alignY:0.5] show];
  [table attach:label
	 attachLeft:0 attachRight:1 attachTop:2 attachBottom:3
	 optionsX:(GTK_EXPAND | GTK_FILL) optionsY:0
	 paddingX:0 paddingY:0];

  vbox = [[[Gtk_VBox alloc] initWithBoxInfo:FALSE setSpacing:4] show];
  [table attach:vbox
	 attachLeft:1 attachRight:2 attachTop:3 attachBottom:4
	 optionsX:(GTK_FILL | GTK_SHRINK) optionsY:(GTK_EXPAND | GTK_FILL)
	 paddingX:0 paddingY:0];

  cancel_job = [[[[[Gtk_Button alloc] initWithLabel:_("Cancel job")] show] connectObj:"clicked" :self] set_sensitive:FALSE];

  [self do_job_list];
  [table attach:job_list
	 attachLeft:0 attachRight:1 attachTop:3 attachBottom:4
	 optionsX:(GTK_EXPAND | GTK_FILL) optionsY:(GTK_EXPAND | GTK_FILL)
	 paddingX:0 paddingY:0];

  [vbox pack_start:cancel_job doExpand:FALSE doFill:FALSE doPadding:0];

  [mainwin create_menus:mainmenu];
  gtk_menu_item_right_justify(GTK_MENU_ITEM(mainmenu[1].widget));

  [mainwin connect:"delete_event"];
  [mainwin show];

  return self;
}

- free
{
  [mainwin free];
  [printsys free];

  gdk_cursor_destroy(wait_cursor);
  
  return [super free];
}

- set_wait_cursor:(gint) wait
{
  if (GTK_WIDGET_REALIZED(mainwin->gtkwidget))
    {
      if (wait)
	gdk_window_set_cursor(mainwin->gtkwidget->window, wait_cursor);
      else
	gdk_window_set_cursor(mainwin->gtkwidget->window, NULL);

      gdk_flush();
    }

  return self;
}

@end

int main(int argc, char *argv[])
{
  id myapp = [GULPApp alloc];

  bindtextdomain(PACKAGE, GNOMELOCALEDIR);
  textdomain(PACKAGE);

  if([myapp initGULP:"gulp" :argc :argv] == nil) return 1;
  [myapp run];
  [myapp free];
  return 0;
}

