/*  GFAX - Gnome fax application
 *  Copyright (C) 1999 George A. Farris
 *
 *  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 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.
 */


#include <config.h>
#include <gnome.h>
#include <glade/glade.h>
#include <errno.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>

#include "gfax.h"
#include "setup.h"

#include "ftplib.h"

#include "hylafax_sendfax.h"

/**********************************************************************
 * PROTOTYPES
 **********************************************************************/
int redrawWindow(gpointer data);
void refreshSpoollist(GladeXML *xml);

void on_scheduleButton_clicked(GtkButton *button,
			       gpointer user_data);
void on_select_row(GtkCList *clist,
		   gint row,
		   gint column,
		   GdkEventButton *event,
		   gpointer user_data);
void on_unselect_row(GtkCList *clist,
		     gint row,
		     gint column,
		     GdkEventButton *event,
		     gpointer user_data);
void on_closeButton_clicked(GtkButton *button,
			    gpointer user_data);
gchar *searchJob(gchar *id);
void on_deleteButton_clicked(GtkButton *button,
			     gpointer user_data);
void showSpoolDialog(void);

/**********************************************************************
 * GLOBAL VARIABLES
 **********************************************************************/
GladeXML   *xml;	/* The main window */
GPtrArray  *selectedJobs = NULL;
gboolean   refreshRunning = FALSE;
guint      refreshTimer;




/**********************************************************************
 * Connect the fax server and ask for the contents of a fax
 * queue. Display the result in a CList with the name "widgetName".
 *
 * @param xml              the glade xml file to ask for the widget clist
 * @param widgetName       the name of the list to fill
 * @param con              the control connection to the fax server
 * @param hylafaxQueueName the name of the queue to show
 * @param hylafaxJobFmt    the format used to tokenize a job. See hfaxd(1).
 ***********************************************************************/
static enum hylafax_errno fillQueue(GladeXML *xml, gchar *widgetName, 
				    netbuf *con,
				    gchar *hylafaxQueueName,
				    gchar *hylafaxJobFmt)
{
	GtkCList  *queueList;
	GPtrArray *queue;
	enum hylafax_errno herrno;
	gchar **row;
	int i,j, ret;
	gchar *item;
	gboolean changed;

	queueList = (GtkCList *)glade_xml_get_widget(xml, widgetName);

	queue  = g_ptr_array_new();
	herrno = hylafax_faxstat(con, 
				 hylafaxQueueName, hylafaxJobFmt,
				 queue);
	
	/* check if anything changed and display only in this case: */
	changed = FALSE;
	for ( i = 0; i < queue->len; i++ ) {
		row = g_ptr_array_index(queue, i);
		for ( j = 0; row[j] != NULL; j++ ) {
			ret = gtk_clist_get_text(queueList, i, j, &item);
			if ( ret == 0 || strcmp(row[j], item ) != 0 ) {
				changed = TRUE;
				goto break_loop;
			}
		}
	}
 break_loop:

	/* has anything changed since the last time? */
	if ( changed ) {
		gtk_clist_clear(queueList);
		for ( i = 0; i < queueList->columns; i++) {
			gtk_clist_set_column_auto_resize(queueList, i, TRUE);
		}
		if ( herrno == EOK ) {
			for ( i = 0; i < queue->len; i++ ) {
				row = g_ptr_array_index(queue, i);
				gtk_clist_append(queueList, row);
				g_strfreev(row);
				
			}
		}

		/* free old selectedJobs array and allocate new one */
		if ( selectedJobs != NULL ) {
			g_ptr_array_free(selectedJobs, TRUE);
		}
		selectedJobs = g_ptr_array_new();
	}
	g_ptr_array_free(queue, FALSE);

	return herrno;
}

/**********************************************************************
 * Refresh the contents of the queues by calling
 * reshreshSpoollist. This routine is a callback for a GtkTimer.
 **********************************************************************/
int redrawWindow(gpointer data) 
{
	refreshSpoollist(xml);

	return TRUE;
}

/**********************************************************************
 * Main entry point. Show the spooling window and register any event
 * listener.
 **********************************************************************/
void showSpoolDialog(void) 
{
	GtkWindow *spoollistWindow;

	xml = glade_xml_new(GLADEDIR "/spool.glade", "spoollist");
	spoollistWindow = GTK_WINDOW(glade_xml_get_widget(xml, "spoollist"));
	refreshSpoollist(xml);

	/* connect the signals */		
	glade_xml_signal_autoconnect(xml);

	/* refresh the contents of the queue every 10 secs */
	refreshTimer = gtk_timeout_add(1000 * 10, redrawWindow, NULL);
}

/**********************************************************************
 * Refresh all queues on the GUI.
 **********************************************************************/
void refreshSpoollist(GladeXML *xml) 
{
	enum hylafax_errno herrno, herrno1, herrno2, herrno3;
	GString *state;
	GnomeAppBar *statusBar;
	netbuf *con;

	/* is there already a refresh running? If so -> abort */
	if ( refreshRunning ) {
		return;
	}

	refreshRunning = TRUE;

	statusBar = GNOME_APPBAR(glade_xml_get_widget(xml, "jobCountStatusBar"));

	gnome_appbar_set_status(statusBar, _("Refreshing..."));
	/*
	 * GNOME is event triggered but we are already in an event
	 * routine. So no further events during the time of the upload
	 * will be processed. Make GNOME take all pending actions
	 * (otherwise the GUI will not be updated and e.g. the
	 * status will never show.
	 */
	while (gtk_events_pending())
		gtk_main_iteration();

	/* connect to hylafax server */
	herrno = hylafax_connect(&con);
	if ( herrno == EOK ) {

		state = g_string_new(NULL);
		herrno = hylafax_server_state(con, state);
		if ( herrno == EOK ) {
			gnome_appbar_set_status(statusBar, state->str);
		}

		herrno1 = fillQueue(xml, "sendQueueList",    con, 
				    "sendq", "%z;%j;%e;%y;%o");
		herrno2 = fillQueue(xml, "receiveQueueList", con, 
				    "recvq", "%z;%j;%e;%y;%o");
		herrno3 = fillQueue(xml, "doneQueueList",    con, 
				    "doneq", "%z;%j;%e;%y;%o");
	}

	if ( herrno == EOK &&
	     herrno1 == EOK &&
	     herrno2 == EOK &&
	     herrno3 == EOK) {
		hylafax_disconnect(con, FALSE, EOK);
	} else {
		/* there was an error -> show log file */
		hylafax_disconnect(con, TRUE, EERROR);
	}

	refreshRunning = FALSE;
}

/**********************************************************************
 * Callback function for clicking on scheduleButton. Does a refresh at
 * the moment.
 **********************************************************************/
void on_scheduleButton_clicked(GtkButton *button,
			       gpointer user_data)
{
	refreshSpoollist(xml);
}

/**********************************************************************
 * Callback function for clicking on deleteButton. Calls
 * hylafax_faxrm for any selected job in any queue.
 **********************************************************************/
void on_deleteButton_clicked(GtkButton *button,
			     gpointer user_data)
{
	int i;
	gchar *storedId;
	enum hylafax_errno herrno, error = EOK;
	netbuf *con;

	if ( selectedJobs->len > 0 ) {
		/* connect to hylafax server */
		herrno = hylafax_connect(&con);
		if ( herrno == EOK ) {
			for ( i = 0; i < selectedJobs->len; i++) {
				storedId = (gchar *)g_ptr_array_index(selectedJobs, i);
				herrno = hylafax_faxrm(con, storedId);
				if ( herrno != EOK ) {
					error = herrno;
				}
			}
		}
		hylafax_disconnect(con, TRUE, error);
	}
}

/**********************************************************************
 * Callback function for clicking on closeButton. Closes the window.
 **********************************************************************/
void on_closeButton_clicked(GtkButton *button,
			    gpointer user_data)
{
	GtkWindow *spoollistWindow;

	gtk_timeout_remove(refreshTimer);

	spoollistWindow = GTK_WINDOW(glade_xml_get_widget(xml, "spoollist"));
	gtk_widget_hide(GTK_WIDGET(spoollistWindow));
	gtk_object_destroy(GTK_OBJECT(spoollistWindow));
}

/**********************************************************************
 * Search for a job with the given fax id in the list of selected
 * jobs. This function is used by the function "on_select_row" and
 * "on_unselect_row" to search for already selected jobs.
 *
 * @param id the job id to search for
 *
 * @return a pointer to the found entry or NULL if nothing was found.
 **********************************************************************/
gchar *searchJob(gchar *id) 
{
	int i;
	gchar *storedId;

	for ( i = 0; i < selectedJobs->len; i++) {
		storedId = (gchar *)g_ptr_array_index(selectedJobs, i);
		if ( strcmp(storedId, id) == 0 ) {
			return storedId;
		}
	}
	return NULL;
}


/**********************************************************************
 * Callback function for selecting a row. Stores the corresponding fax
 * id in the selection list.
 **********************************************************************/
void on_select_row(GtkCList *clist,
	       gint row,
	       gint column,
	       GdkEventButton *event,
	       gpointer user_data)
{
	gchar *id, *storedId;

	// column "1" is JOB id
	gtk_clist_get_text(clist, row, 1, &id);
	storedId = searchJob(id);
	if ( storedId == NULL ) {
		g_ptr_array_add(selectedJobs, g_strdup(id));
	}
}

/**********************************************************************
 * Callback function for unselecting a row. Removes the corresponding
 * fax id from the selection list.
 **********************************************************************/
void on_unselect_row(GtkCList *clist,
	       gint row,
	       gint column,
	       GdkEventButton *event,
	       gpointer user_data)
{
	gchar *id, *storedId;

	// column "1" is JOB id
	gtk_clist_get_text(clist, row, 1, &id);
	storedId = searchJob(id);
	if ( storedId != NULL ) {
		g_free(storedId);
		g_ptr_array_remove(selectedJobs, storedId);
	}
}



/* These are Emacs variables to use a common "Gfax" coding style:
 * ;;; Local Variables: ***
 * ;;; mode:C ***
 * ;;; c-basic-offset:8 ***
 * ;;; indent-tabs-mode:t ***
 * ;;; End: *** */
