/*
 *  Printer - the OffiX print manager
 *  Copyright (c) 1996 Andr Hentz
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/AsciiText.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>

#include "Main.h"
#include "Icon.h"
#include "List.h"
#include "Error.h"
#include "pipe.h"
/*------------------ Public funtions -------------*/
void UpdateJobsList(char *PrinterName);
int IsJobLine(char *line);
int IsTopLine(char *line);
int GetJobNumber(char *header, char *line);
void SelectPrinter(char *name);
void GetPrinters(List *Printers);
void RemoveTimer();
void ResetTimer();
void ShowWarnings();
void ShowError();
void PrintSingleFile(char *name);
void PrintData(char *data, unsigned long size);
void ShowErrorPopup(char *error);
void RemoveJob(char *Printer, int JobNumber);
void RetrieveQueue(char *name, List *jobs); 

/*------------------ Private funtions -------------*/
static char* PreparseTopLine(char *jobline);
static char* PreparseJobLine(char *jobline);
static int IsThereAnyJob();
static void TimeoutProc(XtPointer data, XtIntervalId *id);
static void ErrorPopupCb(Widget w, XtPointer client_data, XtPointer call_data);
static int FakeStdin(char *data, int size);
static void SolarisCollectList(const char* data, int i);
static void SolarisGetPrinters(List *Printers);
static void SolarisRetrieveQueue(char*name, List *Jobs);


static XtIntervalId UpdateTimer;

void UpdateJobsList(char *PrinterName)
{
	int i;
	ListEntry *CurrentJob;
			
	RemoveTimer();
	XtVaSetValues(JobsList,XtNresizable,False,NULL);
	
	/* Get rid of previous list */
	if (JobsArray)
	{
		i = 0;
		while(JobsArray[i])
		    free(JobsArray[i++]);		
		free(JobsArray);
	}
	FreeList(Jobs);
	/* reselect printer */
	SelectPrinter(PrinterName);
	/* start new list of jobs */
	Jobs = NewList();
	ClearErrorMessages(0);
	RetrieveQueue(CurrentPrinter->string, Jobs); 
	ShowWarnings();
	if (IsThereError())
	{
		FreeList(Jobs);
		ShowError();
		return;
	}
	/* compute size of new list */
	i = 0;
	CurrentJob = Jobs->first;
	while(CurrentJob)
	{
		i++;
		CurrentJob = CurrentJob->next;
	}
	/* fill in the list */
	JobsArray = (char **) calloc( (i + 1), sizeof(char*));
	i = 0;
	CurrentJob = Jobs->first;
	while(CurrentJob)
	{
		if(IsJobLine(CurrentJob->string))
			JobsArray[i++] = PreparseJobLine(CurrentJob->string);  
		else if(IsTopLine(CurrentJob->string))
		  	JobsArray[i++] = PreparseTopLine(CurrentJob->string);
		else
		  	JobsArray[i++] = strdup(CurrentJob->string);
		CurrentJob = CurrentJob->next;
	}	
	JobsArray[i] = NULL;
		
	XawListChange(JobsList, JobsArray, 0, 0, 1);
	UpdateIcon(IsThereAnyJob());
	ResetTimer();
}

static char* PreparseJobLine(char *jobline)
{
	char tmp[200];
	strncpy(tmp, jobline, 18);
	tmp[18] = 0;
	strcat(tmp, jobline+23);
	tmp[strlen(tmp)-5] = '\0';
	return(strdup(tmp));
}

static char* PreparseTopLine(char *jobline)
{
	char tmp[200];
	strncpy(tmp, jobline, 18);
	tmp[18] = 0;
	strcat(tmp, jobline+23);
	tmp[strlen(tmp)-10] = '\0';
	strcat(tmp, "Size"); 
	return(strdup(tmp));	
}


int IsJobLine(char *line)
{		  
	return(!strncmp(line, "active", 6) ||
	   (line[0]>'0' && line[0]<='9'));
}


int IsTopLine(char *line)
{	
	return (!strncmp(line, "Rank", 4));
}

static int IsThereAnyJob()
{
	ListEntry *job;
	
	job = Jobs->first;
	while(job)
	{
		if(IsJobLine(job->string))
		  	return 1;
		job = job->next;
	}
	return 0;	
}

int GetJobNumber(char *header, char *line)
{
	char tmp[200], *p;
	int i = strlen(header)+1;
	while(--i)
	  	tmp[i] = toupper(header[i]);
	tmp[0] = header[0];
	
	p = strstr(tmp, "JOB");
	i = p-tmp; /* offset */
	p = line + i;  /* corresponding position in line */
	return atoi(p);
}

void SelectPrinter(char *name)
{
	ListEntry *tmp = CurrentPrinter;
	CurrentPrinter = Printers->first;
	while(CurrentPrinter)
	{  		
	  	if(!strcmp(CurrentPrinter->string,name))
		{
		    XtVaSetValues(toplevel, XtNtitle, name, NULL);
		    XSetIconName(XtDisplay(toplevel), 
				 XtWindow(toplevel), name);
		    return;
		}		
		CurrentPrinter = CurrentPrinter->next;
	}	
	CurrentPrinter = tmp;
}

/* Solaris compatibility functions */
List *aGlobalList;
void GetPrinters(List *Printers)
{
    ListEntry *printer;
    String argv[] = {"lpc", "status", "all", NULL};
    aGlobalList = NewList();    
    pipe_command("Printer", "lpc", argv, NULL,SolarisCollectList,NULL);
    printer = aGlobalList->first;	
    while(printer)
    {
	/* remove garbage */
	char *ptr;	
	if (printer->string[0]=='\t')
	{
	    printer = printer->next;	    
	    continue;
	}	
	ptr = printer->string + strlen(printer->string)-1;
	*ptr = '\0';
	ptr = printer->string;
	NewListEntry(Printers, ptr);	
	printer = printer->next;
    }
    FreeList(aGlobalList);
}

void CollectList(const char* data, int i)
{
    static int FlagNewLine = 1;
    int pos=0;
    static char superstring[2000];
    while(i--)
    {
	if(data[pos] == '\n')
	{
	    char tmp[2000];
	    strncpy(tmp, data, pos);
	    tmp[pos] = '\0';
	    tmp[pos+1] = '\0';
	    if (!FlagNewLine)
	    {
		strcat(superstring, tmp);
	    }
	    else
	    {
		superstring[0] = '\0';
		strcpy(superstring, tmp);
	    }
	    data = data + pos + 1;
	    pos = 0;
	    FlagNewLine = 1;
	    NewListEntry(aGlobalList, superstring);
	}
	else
	    pos++;
    }
    if (pos)
    {
	if (!FlagNewLine)
	    strcat(superstring, data);
	else
	{
	    superstring[0] = '\0';
	    strcpy(superstring, data);
	}
	FlagNewLine = 0;
    }

}
void RetrieveQueue(char *name, List *jobs)
{
    String argv[3];
    char tmp[1024];
    argv[0] = XtNewString("lpq");
    sprintf(tmp, "-P%s", CurrentPrinter->string);
    argv[1] = XtNewString(tmp);	
    argv[2] = NULL;
    
    aGlobalList = jobs;    
    pipe_command("Printer", "lpq", argv, NULL, 
		 SolarisCollectList, CollectWarnings);
    
    free(argv[0]);
    free(argv[1]);
}

/* End of Solaris compatibility functions */


static void TimeoutProc(XtPointer data, XtIntervalId *id)
{
	UpdateJobsList(CurrentPrinter->string);
	ResetTimer();
}

void RemoveTimer()
{
	XtRemoveTimeOut(UpdateTimer);
}

void ResetTimer()
{
	UpdateTimer = XtAppAddTimeOut(app, 60000, TimeoutProc, NULL);
}


void ShowWarnings()
{
	XawTextPosition fim;
	XawTextBlock text;
	ListEntry *entry;
	List *warnings = GetWarningList();

	XtVaSetValues(WarningArea, XtNeditType, XawtextEdit, NULL);
	XtVaSetValues(WarningArea, XtNstring, NULL, NULL);
	fim = 0;
	if (warnings) 
	{		
		entry = warnings->first;
		while(entry)
		{
			text.firstPos = 0;
			text.length = strlen(entry->string);
			text.ptr = entry->string;
			text.format = XawFmt8Bit;
			XawTextReplace(WarningArea, fim, fim, &text);
			fim += text.length;
	 		entry = entry->next;
		}	
	}
	
	XawTextSetInsertionPoint(WarningArea, fim-1);
	XtVaSetValues(WarningArea, XtNeditType, XawtextRead, NULL);
/*	XawTextDisplay(WarningArea); */
	
}

void ShowError()
{
	ShowErrorPopup(GetErrorMsg());		
}

static Widget ErrorPopup;

void ShowErrorPopup(char *error)
{
	int x,y,x_win,y_win;
	unsigned int mask;
	Window root,child;
	Widget Dialog;
	Display 	*dpy=XtDisplay(toplevel);

	XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child, &x, &y, 
				  &x_win, &y_win, &mask);

    
    ErrorPopup=XtVaCreatePopupShell("popup",transientShellWidgetClass,
			   toplevel, XtNtitle, "Error", XtNx, x, XtNy, y, 0);
    Dialog=XtVaCreateManagedWidget("transient",dialogWidgetClass,
			       ErrorPopup, XtNlabel, error, NULL);
    XawDialogAddButton(Dialog, "OK", ErrorPopupCb, Dialog);

	XtPopup(ErrorPopup,XtGrabNone);
}

static void ErrorPopupCb(Widget w, XtPointer client_data, XtPointer call_data)
{
	XtPopdown(ErrorPopup);
	XtDestroyWidget(ErrorPopup);
}

void PrintSingleFile(char *name)
{
	String argv[4];
	char tmp[1024];
	argv[0] = XtNewString("lpr");
	sprintf(tmp, "-P%s", CurrentPrinter->string);
	argv[1] = XtNewString(tmp);	
	argv[2] = XtNewString(name);
	argv[3] = NULL;
	
	pipe_command("Printer", "lpr", argv, NULL, CollectWarnings, CollectWarnings);
	
	free(argv[0]);
	free(argv[1]);
	free(argv[2]);
}

char *DataToPrint;
unsigned long DataSize;
void PrintData(char *data, unsigned long size)
{
	String argv[3];
	char tmp[1024];
	argv[0] = XtNewString("lpr");
	sprintf(tmp, "-P%s", CurrentPrinter->string);
	argv[1] = XtNewString(tmp);	
	argv[2] = NULL;
	
	DataToPrint = data;
	DataSize = size;
	pipe_command("Printer", "lpr", argv, FakeStdin, CollectWarnings, CollectWarnings);

	free(argv[0]);
	free(argv[1]);
}

int FakeStdin(char *data, int size)
{
	static j = 0;
	int i = 0;
	if (j>=DataSize)
	{
		j = 0;
		return 0;
	}	
	while(i<size && j<DataSize)
	  data[i++] = DataToPrint[j++];
	return i;
}

void RemoveJob(char *Printer, int JobNumber)
{	
	String argv[4];
	char tmp[1024];
	argv[0] = XtNewString("lprm");
	sprintf(tmp, "-P%s", CurrentPrinter->string);
	argv[1] = XtNewString(tmp);	
	sprintf(tmp, "%d", JobNumber);
	argv[2] = XtNewString(tmp);
	argv[3] = NULL;
	
	pipe_command("Printer", "lprm", argv, NULL, CollectWarnings, CollectWarnings);
	
	free(argv[0]);
	free(argv[1]);
	free(argv[2]);
}


