/*
 * $Header: printer.c,v 1.2 91/05/13 09:18:24 billr Exp $
 */
/*
 * printer.c
 *
 * calentool - a year/month/week/day-at-a-glance calendar for Sun workstations.
 *
 * Author: Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>
 *
 * Copyright (C) 1991 Tektronix, Inc.
 *	All Rights Reserved
 * Permission is hereby granted to use and modify this file in source
 * or binary form as long as it is not sold for profit and this copyright
 * notice remains intact.
 *
 * Modified parse_date to allow +nnn and -nnn syntax for dates relative to the
 * current date.  Peter Marshall <peter.marshall@uwo.ca>. 1989-09-19.
 */
/********************************************
 *					    *
 *              Printing routines.	    *
 *					    *
 ********************************************/

#include <stdio.h>
/*	#include <X11/Xlib.h>
	#include <X11/Xutil.h>
	#include <X11/XWDFile.h>
	#include <X11/Intrinsic.h>
	#include <xview/xview.h>
	#include <xview/canvas.h>
	#include <xview/font.h>
*/
#include <time.h>
//	#include "xv_ct.h"
#include "ct.h"

extern struct tm current, today;
extern int n_slots;
extern struct dayslot *slots;
extern char apts_pathname[];
extern int nr_weekdays, n_tslots;
extern char *mailto;
extern int findex;
extern struct appt_entry future[];
extern char printer[];
//extern Canvas canvas;
//extern Xv_window cpwindow;
extern int mainsw_state;
//extern Xv_Font font, sfont;
extern int monday_first, hour24, day_first;
int print_to_file; /* AMIGA: former extern (orig in tool.c) */
extern int print_dev, week_ofs;
extern char *daynames[], *monthnames[];
extern char clockstr[], strbuf[];
extern void xv_pf_text();
//int format = ZPixmap;

char rasfile[] = "T:calentool.xwd";
char psfile[80] = "T:calentool.ps";


/*
 * convert appt entry to ASCII string for display with date, time and msg
 */
char *format_appt(appt)
struct appt_entry *appt;
{
	int e_hour, e_minutes, duration;
	struct tm Save;

	if (appt->arrows > 0) {
		duration = appt->arrows + 1;
		e_hour = appt->hour + duration/2;
		e_minutes = appt->minute + ((duration%2) * 30);
	} else {
		e_hour = appt->hour;
		e_minutes = appt->minute + 30;
	}
	if (e_minutes == 60) {
		e_minutes = 0;
		++e_hour;
	}
	/* get day of week */
	Save = current;
	current.tm_year = appt->year;
	current.tm_mon = appt->month;
	current.tm_mday = appt->day;
	fix_current_day();

	if (appt->flags & A_NOTE) {
		/* note */
		if (appt->flags & ALL_YEARS)
			if (day_first)
				sprintf(strbuf,"%3.3s %2d/%02d    --  %s",
					daynames[current.tm_wday], appt->day,
					appt->month+1, appt->str);
			else
				sprintf(strbuf,"%3.3s %2d/%02d    --  %s",
					daynames[current.tm_wday], appt->month+1,
					appt->day, appt->str);
		else if (appt->year > 99)
			if (day_first)
				sprintf(strbuf,"%3.3s %2d/%02d/%02d --  %s",
					daynames[current.tm_wday], appt->day,
					appt->month+1, appt->year-100, appt->str);
			else
				sprintf(strbuf,"%3.3s %2d/%02d/%02d --  %s",
					daynames[current.tm_wday], appt->month+1,
					appt->day, appt->year-100, appt->str);
		else
			if (day_first)
				sprintf(strbuf,"%3.3s %2d/%02d/%02d --  %s",
					daynames[current.tm_wday], appt->day,
					appt->month+1, appt->year, appt->str);
			else
				sprintf(strbuf,"%3.3s %2d/%02d/%02d --  %s",
					daynames[current.tm_wday], appt->month+1,
					appt->day, appt->year, appt->str);
	} else {
		/* standard appointment */
		if (hour24)
			if (day_first)
				sprintf(strbuf,"%3.3s %2d/%02d/%02d -- %2d:%02d to %2d:%02d   %s",
					daynames[current.tm_wday], appt->day,
					appt->month+1, appt->year, appt->hour, appt->minute,
					e_hour, e_minutes, appt->str);
			else
				sprintf(strbuf,"%3.3s %2d/%02d/%02d -- %2d:%02d to %2d:%02d   %s",
					daynames[current.tm_wday], appt->month+1,
					appt->day, appt->year, appt->hour, appt->minute,
					e_hour, e_minutes, appt->str);
		else
			if (day_first)
				sprintf(strbuf,"%3.3s %2d/%02d/%02d -- %2d:%02d%s to %2d:%02d%s   %s",
					daynames[current.tm_wday], appt->day,
					appt->month+1, appt->year, (appt->hour < 13 ? appt->hour : appt->hour-12), appt->minute,
					(appt->hour < 12 ? "am" : "pm"),
					(e_hour < 13 ? e_hour : e_hour-12), e_minutes,
					(e_hour < 12 ? "am" : "pm"),
					appt->str);
			else
				sprintf(strbuf,"%3.3s %2d/%02d/%02d -- %2d:%02d%s to %2d:%02d%s   %s",
					daynames[current.tm_wday], appt->month+1,
					appt->day, appt->year, (appt->hour < 13 ? appt->hour : appt->hour-12), appt->minute,
					(appt->hour < 12 ? "am" : "pm"),
					(e_hour < 13 ? e_hour : e_hour-12), e_minutes,
					(e_hour < 12 ? "am" : "pm"),
					appt->str);
	}
	current = Save;
	return(strbuf);
}

/*
 * convert appt entry to ASCII string for display with time and msg
 *	if <esc_parens> is true then put '\' in front of parens (for Ps)
 */
char *format_appt_nd(appt, esc_parens)
struct appt_entry *appt;
int	esc_parens;
{
	int e_hour, e_minutes, duration;
	char *p, *q;
	struct tm Save;

	if (appt->arrows > 0) {
		duration = appt->arrows + 1;
		e_hour = appt->hour + duration/2;
		e_minutes = appt->minute + ((duration%2) * 30);
	} else {
		e_hour = appt->hour;
		e_minutes = appt->minute + 30;
	}
	if (e_minutes == 60) {
		e_minutes = 0;
		++e_hour;
	}

	strbuf[0] = '\0';
	if (!(appt->flags & A_NOTE)) {
		/* standard appointment */
		if (hour24)
			sprintf(strbuf,"%2d:%02d to %2d:%02d  ",
				appt->hour, appt->minute, e_hour, e_minutes);
		else
			sprintf(strbuf,"%2d:%02d%s to %2d:%02d%s  ",
				(appt->hour < 13 ? appt->hour : appt->hour-12), appt->minute,
				(appt->hour < 12 ? "am" : "pm"),
				(e_hour < 13 ? e_hour : e_hour-12), e_minutes,
				(e_hour < 12 ? "am" : "pm"));
	}
	p = appt->str;
	q = strbuf + strlen(strbuf);
	while (*p) {
		if (esc_parens)
			switch (*p) {
				/* ignore these */
				case '\b':
				case '\f':
				case '\n':
				case '\r':
				case '\t':
					break;
				/* escape these for PostScript */
				case '\\':
				case '(':
				case ')':
					*q++ = '\\';
					break;
			}
		*q++ = *p++;
	}
	*q = '\0';

	return(strbuf);
}

/*
 * Print today's appointments to stdout or mail (useful if we only have an ASCII
 * terminal connected to our Sun). Invoked by the "-p", "-P", "-m" or
 * "-M" options. The -T option is used to select print device
 * (PostScript or ASCII).
 * Month information is only printed as PostScript output.
 */
print_apts(which, dest)
int which, dest;
{
	int i, gd_rtn, target, ndays;
	FILE *output, *pfp/*, *popen()*/;
	char cmd[80], *name /*, *cuserid()*/, *mail_subj(), *getenv();
	struct tm Save;

	fix_current_day();
	gd_rtn = get_day_appts();
	if (which == PRI_DAY && !gd_rtn)
		return;	/* nothing to show */
	if (which == PRI_DAY_XNOTES && gd_rtn == SOME_MKNOTES)
		/* all we have is marked notes */
		return;	/* nothing to show */
	if (dest == DST_MAIL) {
		if (mailto != NULL) {
			name = mailto;
		} else if ((name = getenv("USER")) == NULL) {
			err_rpt("nobody to mail to", FATAL);
		}
		sprintf(cmd, "%s -s \"Appointments for %s\" %s", MAILPROG, mail_subj(), name);
		if ((output = fopen("PIPE:calentoolmail", "w")) == NULL)
			err_rpt("Couldn't pipe to 'mail'", FATAL);
	} else {
		output = stdout;
	}
	
	if (which == PRI_DAY || which == PRI_DAY_XNOTES) {
		if (print_dev == PR_POSTSCRIPT)
#ifdef RASTER_ONLY
			fprintf(output, "PostScript output option not compiled in\n");
#else
			print_psday(output, (which == PRI_DAY_XNOTES ? TRUE : FALSE));
#endif
		else
			print_one_day(which, output, gd_rtn);
	} else if (which == PRI_WEEK || which == PRI_WEEK_XNOTES) {
		Save = current;
		if (!week_ofs) {
			/* start printing on first dow */
			if (nr_weekdays == 7 && !monday_first)
				target = SUN;
			else
				target = MON;
			if (current.tm_wday >= target)
				while (current.tm_wday-- > target)
					current.tm_mday--;
			else
				/* looking at Sun */
				current.tm_mday++;
			fix_current_day();
			ndays = nr_weekdays;
		} else {
			ndays = 7;
		}
		if (print_dev == PR_POSTSCRIPT)
#ifdef RASTER_ONLY
			fprintf(output, "PostScript output option not compiled in\n");
#else
			print_psweek(output, (which == PRI_WEEK_XNOTES ? TRUE : FALSE));
#endif
		else
			for (i=0;i<ndays;i++) {
				gd_rtn = get_day_appts();
				if ((gd_rtn && which == PRI_WEEK) ||
				    (gd_rtn & ~SOME_MKNOTES && which == PRI_WEEK_XNOTES))
					print_one_day(which, output, gd_rtn);
				current.tm_mday++;
				fix_current_day();
			}
		current = Save;
	} else if (which == PRI_MONTH || which == PRI_MONTH_XNOTES) {
		if (print_dev == PR_POSTSCRIPT)
#ifdef RASTER_ONLY
			fprintf(output, "PostScript output option not compiled in\n");
#else
			print_psmonth(output, (which == PRI_MONTH_XNOTES ? TRUE : FALSE));
#endif
		else
			fprintf(output, "\nNo ASCII month printout is available\n");
	}
	fflush(output);
	if (dest == DST_MAIL)
		fclose(output);
}

print_one_day(which, output, gdrtn)
int which;
FILE *output;
int gdrtn;
{
	int i;
	struct appt_entry tmp_apt, *aptr;
	char *format_appt();

	if (day_first)
		fprintf(output,"\n\t*** Appointments for %s %d %s %d ***\n\n", 
			daynames[current.tm_wday], current.tm_mday,
			monthnames[current.tm_mon], current.tm_year+1900);
	else
		fprintf(output,"\n\t*** Appointments for %s %s %d, %d ***\n\n", 
			daynames[current.tm_wday], monthnames[current.tm_mon],
			current.tm_mday, current.tm_year+1900);

	for (i=0; i<n_slots; i++) {
		if (i == n_tslots)
			/* start of notes section */
			if ((gdrtn & SOME_NOTES) ||
			   (!(which & PRI_XNOTES) && (gdrtn & SOME_MKNOTES)))
				fprintf(output,"\n\t\t     ===== Notes =====\n");
		if (slots[i].first != NULL && slots[i].active > 0) {
			/* at least one appt here */
			aptr = slots[i].first;
			do {
				if ((which & PRI_XNOTES) && ((aptr->flags & MARKED_NOTE) == MARKED_NOTE))
					continue;
				if (chk_deleted(&slots[i], aptr))
					continue;
				tmp_apt = *aptr;
				tmp_apt.year = current.tm_year;
				tmp_apt.month = current.tm_mon;
				tmp_apt.day = current.tm_mday;
				fprintf(output, "%s\n", format_appt(&tmp_apt));
			} while ((aptr = aptr->next) != NULL);
		}
	}
	if (findex) {
		/* print out future appointments */
		fprintf(output, "\n\t\t===== Future Reminders =====\n");
		for (i=0; i<findex; i++)
			fprintf(output, "%s\n", format_appt(&future[i]));
	}
	fprintf(output,"\n------------------------------------------------------------------\n");
}

/*
 * mail_subj() - make subject line for appointment mail. Use "today"
 * or "tomorrow" if appropriate, otherwise use the actual date.
 */
char *mail_subj(void)
{
	struct tm Save;

	if (!ymd_compare(current, today))
		sprintf(strbuf, "today");
	else {
		Save = current;
		current.tm_mday--;
		fix_current_day();
		if (!ymd_compare(current, today))
			sprintf(strbuf, "tomorrow");
		else if (day_first)
			sprintf(strbuf, "%s %d %s %d.",
				daynames[current.tm_wday], current.tm_mday,
				monthnames[current.tm_mon], current.tm_year+1900);
		else
			sprintf(strbuf, "%s %s %d, %d",
				daynames[current.tm_wday], monthnames[current.tm_mon],
				current.tm_mday, current.tm_year+1900);
		current = Save;
	}
	return (strbuf);
}

#ifndef NO_PRINTER
/*
 * Print to Postscript compatable printer.  If we are displaying
 * the year page, then create a raster file of the canvas and
 * feed it to a raster->ps filter (sun2ps).  If on any other page,
 * then print a pretty PostScript calendar with appts written in
 * (as best can be).
 */
print_calendar(file_type)
int file_type;
{
	char prntcmd[256];
	FILE *fp, *pfp;
	struct tm Save;
	int target;

//	lock_cursors();
	working(TRUE);
#ifndef RASTER_ONLY
	if (file_type == PR_POSTSCRIPT) {
		if ((pfp = fopen(psfile, "w")) == NULL) {
			err_rpt("can't open tmp ps file", NON_FATAL);
			return;
		}
		switch (mainsw_state) {
			case DISPLAYING_DAY:
				print_psday(pfp, FALSE);
				break;
			case DISPLAYING_WEEK:
				/* start printing on first dow */
				Save = current;
				if (nr_weekdays == 7 && !monday_first)
					target = SUN;
				else
					target = MON;
				if (current.tm_wday >= target)
					while (current.tm_wday-- > target)
						current.tm_mday--;
				else
					/* looking at Sun */
					current.tm_mday++;
				fix_current_day();
				print_psweek(pfp, FALSE);
				current = Save;
				break;
			case DISPLAYING_MONTH:
				print_psmonth(pfp, TRUE);
				break;
			case DISPLAYING_YEAR:
				if (dorasfile()) {
				    sprintf(prntcmd, "xpr -device ps -trailer \"Appointments file '%s' printed for %s on %s\" -compact %s > %s",
					apts_pathname, getenv("USER"),
					clockstr, rasfile, psfile);
				    system(prntcmd);
				    unlink(rasfile);
				}
				break;
		}
		fclose(pfp);
		if (!print_to_file) {
			sprintf(prntcmd, "%s %s", printer, psfile);
			system(prntcmd);
			unlink(psfile);
		}
	} else {
#else
	{
#endif /* RASTER_ONLY */
		if (dorasfile() && !print_to_file) {
			sprintf(prntcmd, "%s -v %s", printer, rasfile);
			system(prntcmd);
			unlink(rasfile);
		}
	}
	working(FALSE);
//	unlock_cursors();
}

/*
 * convert screen display to X Window Dump format
 */
/*
 *	excerpted from xwd.c:
 * Copyright 1987 Massachusetts Institute of Technology
 *
 */
int dorasfile()
{
    FILE *fp;
    unsigned long swaptest = 1;
//    XColor *colors;
    unsigned buffer_size;
    int win_name_size;
    int header_size;
    int ncolors, i;
    char *win_name;
/*    XWindowAttributes win_info;
    XImage *image;
    XWDFileHeader header;
*/
    if ((fp = fopen(rasfile, "w")) == NULL) {
		err_rpt("can't open tmp raster file", NON_FATAL);
		return (0);
    }

    /*
     * Get the parameters of the window being dumped.
     */
//    drawable = (Drawable)xv_get(cpwindow, XV_XID);
//    if(!XGetWindowAttributes(mydisplay, drawable, &win_info))
//	err_rpt("Can't get target window attributes.", FATAL);
//    (void)XGetGeometry(mydisplay, drawable, &m_root, &m_x, &m_y,
//	    &g_width, &g_height, &m_border, &m_depth);

    win_name = "calentool";
    /* sizeof(char) is included for the null string terminator. */
    win_name_size = strlen(win_name) + sizeof(char);

    /*
     * Snarf the pixmap with XGetImage.
     */
//    image = XGetImage (mydisplay, drawable, 0, 0, g_width, g_height, AllPlanes, format);
//    if (!image)
//	err_rpt("Unable to get image.", FATAL);

    /*
     * Determine the pixmap size.
     */
//    buffer_size = Image_Size(image);

//    ncolors = Get_XColors(&win_info, &colors);

    /*
     * Calculate header size.
     */
//    header_size = sizeof(header) + win_name_size;

    /*
     * Write out header information.
     */
//    header.header_size = (CARD32) header_size;
//    header.file_version = (CARD32) XWD_FILE_VERSION;
//    header.pixmap_format = (CARD32) format;
//    header.pixmap_depth = (CARD32) image->depth;
//    header.pixmap_width = (CARD32) image->width;
//    header.pixmap_height = (CARD32) image->height;
//    header.xoffset = (CARD32) image->xoffset;
//    header.byte_order = (CARD32) image->byte_order;
//    header.bitmap_unit = (CARD32) image->bitmap_unit;
//    header.bitmap_bit_order = (CARD32) image->bitmap_bit_order;
//    header.bitmap_pad = (CARD32) image->bitmap_pad;
//    header.bits_per_pixel = (CARD32) image->bits_per_pixel;
//    header.bytes_per_line = (CARD32) image->bytes_per_line;
//    header.visual_class = (CARD32) win_info.visual->class;
//    header.red_mask = (CARD32) win_info.visual->red_mask;
//    header.green_mask = (CARD32) win_info.visual->green_mask;
//    header.blue_mask = (CARD32) win_info.visual->blue_mask;
//    header.bits_per_rgb = (CARD32) win_info.visual->bits_per_rgb;
//    header.colormap_entries = (CARD32) win_info.visual->map_entries;
//    header.ncolors = ncolors;
//    header.window_width = (CARD32) win_info.width;
//    header.window_height = (CARD32) win_info.height;
//    header.window_x = 0;
//    header.window_y = 0;
//    header.window_bdrwidth = (CARD32) win_info.border_width;
//
//    if (*(char *) &swaptest) {
//	_swaplong((char *) &header, sizeof(header));
//	for (i = 0; i < ncolors; i++) {
//	    _swaplong((char *) &colors[i].pixel, sizeof(long));
//	    _swapshort((char *) &colors[i].red, 3 * sizeof(short));
//	}
//    }
//
//    (void) fwrite((char *)&header, sizeof(header), 1, fp);
//    (void) fwrite(win_name, win_name_size, 1, fp);
//
//    /*
//     * Write out the color maps, if any
//     */
//    (void) fwrite((char *) colors, sizeof(XColor), ncolors, fp);
//
//    /*
//     * Write out the buffer.
//     */
//    /*
//     *    This copying of the bit stream (data) to a file is to be replaced
//     *  by an Xlib call which hasn't been written yet.  It is not clear
//     *  what other functions of xwd will be taken over by this (as yet)
//     *  non-existant X function.
//     */
//    (void) fwrite(image->data, (int) buffer_size, 1, fp);
//    fclose(fp);
//
//    /*
//     * free the color buffer.
//     */
//    if(ncolors > 0) free(colors);
//
//    /*
//     * Free image
//     */
//    XDestroyImage(image);
    return (1);
}

/*
 * Determine the pixmap size.
 */

//int Image_Size(image)
//     XImage *image;
//{
//    if (format != ZPixmap)
//      return(image->bytes_per_line * image->height * image->depth);
//
//    return(image->bytes_per_line * image->height);
//}
//
#define lowbit(x) ((x) & (~(x) + 1))

/*
 * Get the XColors of all pixels in image - returns # of colors
 */
//int Get_XColors(win_info, colors)
//     XWindowAttributes *win_info;
//     XColor **colors;
//{
//    int i, ncolors;
//
//    if (!win_info->colormap)
//	return(0);
//
//    if (win_info->visual->class == TrueColor)
//	return(0);    /* colormap is not needed */
//
//    ncolors = win_info->visual->map_entries;
//    if (!(*colors = (XColor *) malloc (sizeof(XColor) * ncolors)))
//      err_rpt("Out of memory!", FATAL);
//
//    if (win_info->visual->class == DirectColor) {
//	Pixel red, green, blue, red1, green1, blue1;
//
//	red = green = blue = 0;
//	red1 = lowbit(win_info->visual->red_mask);
//	green1 = lowbit(win_info->visual->green_mask);
//	blue1 = lowbit(win_info->visual->blue_mask);
//	for (i=0; i<ncolors; i++) {
//	  (*colors)[i].pixel = red|green|blue;
//	  (*colors)[i].pad = 0;
//	  red += red1;
//	  if (red > win_info->visual->red_mask)
//	    red = 0;
//	  green += green1;
//	  if (green > win_info->visual->green_mask)
//	    green = 0;
//	  blue += blue1;
//	  if (blue > win_info->visual->blue_mask)
//	    blue = 0;
//	}
//    } else {
//	for (i=0; i<ncolors; i++) {
//	  (*colors)[i].pixel = i;
//	  (*colors)[i].pad = 0;
//	}
//    }
//
//    XQueryColors(mydisplay, win_info->colormap, *colors, ncolors);
//    
//    return(ncolors);
//}

_swapshort (bp, n)
    register char *bp;
    register unsigned n;
{
    register char c;
    register char *ep = bp + n;

    while (bp < ep) {
	c = *bp;
	*bp = *(bp + 1);
	bp++;
	*bp++ = c;
    }
}

_swaplong (bp, n)
    register char *bp;
    register unsigned n;
{
    register char c;
    register char *ep = bp + n;
    register char *sp;

    while (bp < ep) {
	sp = bp + 3;
	c = *sp;
	*sp = *bp;
	*bp++ = c;
	sp = bp + 1;
	c = *sp;
	*sp = *bp;
	*bp++ = c;
	bp += 2;
    }
}
#endif	/* NO_PRINTER */
