/*   praytimer.c
 *
 * Program to compute Islamic prayer hour schedules.
 *   It generates a file which should be processed by TeX. 
 *
 * Copyright (c) 1987--1992 Kamal Abdali
 *
 * Permission for nonprofit use of this software and its documentation 
 * is hereby granted without fee, provided that the above copyright notice 
 * appear in all copies and that both that copyright notice and this 
 * permission notice appear in supporting documentation, and that the name 
 * of Kamal Abdali not be used in advertising or publicity pertaining to 
 * distribution of the software without specific, written prior permission.  
 *
 * Author:
 *  Kamal Abdali
 *  P.O. Box 65207
 *  Washington, DC 20035
 *
 */

#include 	<math.h>
#include 	<stdio.h>
#include	"praytimer.h"
#ifdef	THINK_C
#include 	<console.h>
#endif

/*
 * The program takes geographical and time data from standard input
 * and produces TeX code for the schedule on the standard output.
 * The following command line arguments control the calculation method:
 *
 * -i	        Interactive mode. User prompted for data at the terminal.
 * -a angle     Sun's angle of depression at Fajr in degrees (usually 15 or 18)
 * -t time    	Time interval from Fajr to sunrise in minutes (usually 90)
 * -f fiqh      Value should be S(hafii) or H(anafi)
 * -r ratio     Shadow ratio at Asr. (Usually 2 for Hanafi, 1 for others)
 *
 * NOTE: It is an error to specify both -a and -t or both -f and -r.
 * DEFAULT is as if called with "-a 15 -r 1"
 *
 * Data on standard input must contain (in given order)
 *   Name of location (upto 30 caharacters) 
 *   Latitude degrees and minutes, and N or S to specify north or south
 *   Longitude degrees and minutes, and E or W to specify east or west
 *   Time Zone in hours (Decimal for fractional hour zones, negative if
 *       West of Greenwich)
 *   Y or 1 if Daylight Saving Time adjustment needed.  N or 0, otherwise.
 *   Year in the range 1900..2200, or 0 for a perpetual schedule
 * Data items should be separated by whitespace, but the name must be on
 * a separate line by itself because it may contain spaces or punctuation.
 *
 * Input may contain data for more than one location.
 * An interactive session may be ended by typing the End-of-File character
 *   (e.g. CTRL-D in UNIX) when prompted for Name. 
 */

main(argc, argv)
	short	argc;
	char*	argv[];
{
	register char *cp;
	short	optA = 0, optF = 0, optR = 0, optT = 0, interactive = 0;
	char	fiqh = 'S';
	double	ratio = 1.0, depr = 15.0, intvl = 90.0;
	extern double	atof(/* const char* s */); /* In case not declared in math.h */
	
	fajrByInterval = 0; fajrInterval = 90.0; fajrDepr = 15.0; asrShadowRatio = 1.0;
#ifdef	THINK_C
	argc = ccommand(&argv);
#endif
	while(--argc){
		cp = *++argv;
		if (*cp++ == '-' && *cp) {
			while (*cp) {
				switch(*cp++) {
				case 'i': /* Interactive data */
					interactive = 1;
					break;
				case 'a': /* Sun's depression angle at Fajr in degrees */
					depr = atof(*cp ? cp : *++argv); optA = 1;
					if (*cp) {*cp = '\0';} else {--argc;}
					break;
				case 't': /* Time interval from Fajr to Sunrise */
					intvl = atof(*cp ? cp : *++argv); optT = 1;
					if (*cp) {*cp = '\0';} else {--argc;}
					break;
				case 'r':  /* Shadow ratio at 'Asr */
					ratio = atof(*cp ? cp : *++argv); optR = 1;
					if (*cp) {*cp = '\0';} else {--argc;}
					break;
				case 'f': /* Fiqh for 'Asr. Value to be H(anafi) or S(hafii) */
					if (*cp) {
						fiqh = *cp; *cp = '\0';
					} else {fiqh = **++argv; --argc;}
					if (fiqh != 'H' && fiqh != 'S') {
						fprintf(stderr, "praytimer: command line arg -f must have value H(anafi) or S(hafii)\n");
						exit(1);
					}
					/* Set 'Asr shadow ratio according to the chosen fiqh: 1 for S, 2 for H */
					ratio = (fiqh == 'S' ? 1.0 : 2.0); optF = 1;
					break;
				default:
					fprintf(stderr, "Usage: praytimer [-i] [-f fiqh] [-r ratio] [-a angle] [-t time]\n");
					exit(1);
				}
			}
		}
	}
	if (optF && optR) {
		fprintf(stderr, "praytimer: invalid command line arg combination (can't have both -f and -r)\n");
		exit(1);
	}  
	if (optF || optR) asrShadowRatio = ratio;
	if (optA && optT) {
		fprintf(stderr, "praytimer: invalid command line arg combination (can't have both -a and -t)\n");
		exit(1);
	}
	if (optT) {
		fajrByInterval = 1; fajrInterval = intvl;
	} 
	if (optA) {
		fajrByInterval = 0; fajrDepr = depr;
	} 
	while (getData(interactive)) {
		/* For perpetual, use 1994. (Need middle year of 4-year leap cycle */
    	computeConstants(year==0 ? 1994 : year);  
		/*  find beginning and ending days for daylight saving time */
	  	dayLight(&leap, hasDayLt, &beginDayLight, &endDayLight);
      	makeSchedule();
   }
   exit(0);
}

/*
 *  Obtain name and geographical data for the location for which
 *  the schedule is desired.  If INTERACTIVE is true, then
 *  the user is prompted for the info at the terminal.
 *  Otherwise, the info is obtained from the standard input.
 *  Note: the values to control the calculation method are
 *  to be given as command line arguments, not as input.
 */

short getData(interactive)
	short	interactive;
{
	short	maxNameLength, chCount, badData;
	char	ch, str[10];
	
	if (interactive)
		/* Data to be read from terminal */
		fprintf(stderr, "Location name (30 chars or less)? ");
	maxNameLength = 30;  /* ARBITRARY */
	chCount = 0;
	/* Read Name.  First skip over leading whitespaces */
	while ((ch = getchar()) != EOF && 
				(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'));
	if (ch == EOF) return(0);
	name[chCount++] = ch;
	while (--maxNameLength > 0 && (ch = getchar()) != EOF && ch != '\n') {
		name[chCount++] = ch;
	}
	if (ch == EOF) return(0);
	name[chCount++] = '\0';
	do {
		if (interactive) fprintf(stderr, "Latitude (degrees, minutes, N/S)? ");
		if (badData = (scanf("%hd%hd%s", &latd, &latm, str) != 3 ||
			   	  latd < 0 || latd > 90 || latm < 0 || latm > 59 ||
			      ((ch = str[0]) != 'N' && ch != 'n' &&
			   	  	ch != 'S' && ch != 's'))) {
			fprintf(stderr, "Illegal data for geographical latitude!\n");
			if (!interactive) return(0);
		}
	} while (badData && interactive);
	latIsS = ch == 'S' || ch == 's';
	do {
		if (interactive) fprintf(stderr, "Longitude (degrees, minutes, E/W)? ");
		if (badData = (scanf("%hd%hd%s", &longd, &longm, str) != 3 ||
			   	  longd < 0 || longd > 180 || longm < 0 || longm > 59 ||
			      ((ch = str[0]) != 'E' && ch != 'e' &&
			   	  	ch != 'W' && ch != 'w'))) {
			fprintf(stderr, "Illegal data for geographical longitude!\n");
			if (!interactive) return(0);
		}
	} while (badData && interactive);
	longIsW = ch == 'W' || ch == 'w';
	do {
		if (interactive)
			fprintf(stderr,
				"Time Zone in decimal hours (negative if West of Greenwich)? ");
		if (badData = (scanf("%lf", &timeZone) != 1 ||
			   	  timeZone <= -12.0 || timeZone > 12.0)) {
			fprintf(stderr, "Illegal data for time zone!\n");
			if (!interactive) return(0);
		}
	} while (badData && interactive);
	if (interactive) fprintf(stderr, "Adjust for daylight saving time (Y/N)? ");
	/* ch = getchar(); */
	/* Following works with terminal I/O without special settings*/ 
	scanf("%s", str); ch = str[0];
	hasDayLt = ch == 'Y' || ch == 'y' || ch == '1';
	do {
		if (interactive)
			fprintf(stderr,
				"Year (1900 thru 2200, or 0 for a perpetual schedule)? ");
		if (badData = (scanf("%hd", &year) != 1 ||
			   	       (year != 0 && (year < 1900 || year > 2200)))) {
			fprintf(stderr, "Illegal data for year!  Try again\n");
			if (!interactive) return(0);
		}
	} while (badData && interactive);
	latitude = deg2rad(dm2deg(latd,latm));
	if (latIsS) latitude = -latitude;
	longitude = deg2rad(dm2deg(longd,longm));
	if (!longIsW) longitude = -longitude;
	direc = qibla() * DPR;
	return(1);
}

/*
 * Schedule computation section.
 * Prayer hours are computed basically following the algorithms given in
 * "Prayer Schedules for North America", American Trust Publications, 
 * Indianapolis, Indiana, 1978, Appendices A and B.
 *
 */

void makeSchedule ()
{
	register short	i;
	short	ndays0, ndays1;
	
	ndmnth[1] = 28+leap;
	computeHours(0,365+leap);
	/* schedule computed. now print it out */
	ndays0 = 0;
	texDcl(1);
	for (i=0; i<12; i++) {
		if (i%4 == 0) titleTex();
		ndays1 = ndays0+ndmnth[i];
		displayTex(ndays0,ndays1,1);
		headrTex(i);
			/* One page has four monthly tables. */
				/* Start new page on months 0, 4, 8  */
				/* Odd months underneath even months */
			if (i%2 == 0) printf("&\n"); 
			if (i%2 != 0 && (i+1)%4 != 0) printf("\\cr\\noalign{\\hskip0.5in}\n");
			if ((i+1)%4 == 0) printf("\\cr}\\vfill\\eject\n");
			ndays0 = ndays1;
	}
	printf("\\bye\n");
}

/* 
 * Computes times for range of days first..last-1.
 */ 

void computeHours(first, last) 
	short	first;
	short	last;
{
	double	coaltn,time0[6],coalt[6];
	register double	t;
	register short	i,k,l;
    
	/* Approximate times of fajr,shuruq,asr,maghrib,isha */
	time0[0] = 4.0;
	time0[1] = 6.0;
	time0[3] = 15.0;
	time0[4] = 18.0;
	time0[5] = 20.0;
	/* Coaltitudes of sun at fajr,shuruq,maghrib,isha */
	coalt[0] = deg2rad((double)(90+fajrDepr));
	coalt[1] = deg2rad(90.83);
	coalt[4] = coalt[1];
	coalt[5] = coalt[0];
	/* Get approximate times for the first day specified. */
	/* Later on, each day's times used as approximate times for next day */
	t = noontime(first,&coaltn);
	coalt[3] = atan(asrShadowRatio+tan(coaltn));
	time0[1] = (((t = tempus(first,coalt[1],time0[1])) < 24.0) ? t : 6.0);  
	time0[3] = (((t = tempus(first,coalt[3],time0[3])) < 24.0) ? t : 15.0);  
	time0[4] = (((t = tempus(first,coalt[4],time0[4])) < 24.0) ? t : 18.0);
	if (fajrByInterval) {
		time0[0] = time0[1] - fajrInterval/60.0;  
		time0[5] = time0[4] + fajrInterval/60.0;
	} else {  
		time0[0] = (((t = tempus(first,coalt[0],time0[0])) < 24.0) ? t : 4.0);  
		time0[5] = (((t = tempus(first,coalt[5],time0[5])) < 24.0) ? t : 20.0);
	}  	  
/*  compute times for the whole range of days */
	for (l=first, i=1; l<last; i++, l++) {
/*  for perpetual calendar, february 29 and march 1 have same times */
		k = l;  
		if (l>59 && year==0) k = l-1;
		tim[l][2] = noontime(k+1,&coaltn);
		coalt[3] = atan(asrShadowRatio+tan(coaltn));
		time0[1] = (((tim[l][1] = t = tempus(k+1,coalt[1],time0[1]))
		            < 24.0) ? t : 6.0);
		time0[3] = (((tim[l][3] = t = tempus(k+1,coalt[3],time0[3]))
				   	< 24.0) ? t : 15.0);  
		time0[4] = (((tim[l][4] = t = tempus(k+1,coalt[4],time0[4]))
					< 24.0) ? t : 18.0);
		if (fajrByInterval) {
			tim[l][0] = time0[0] = time0[1] - fajrInterval/60.0;  
			tim[l][5] = time0[5] = time0[4] + fajrInterval/60.0;
		} else {  
			time0[0] = (((tim[l][0] = t = tempus(k+1,coalt[0],time0[0]))
					< 24.0)  ? t : 4.0);
			time0[5] = (((tim[l][5] = t = tempus(k+1,coalt[5],time0[5]))
					< 24.0) ? t : 20.0);
		}  	  
	}
/*  correct for daylight saving time */
	if (endDayLight) {
		for (i = beginDayLight-1; i < endDayLight; i++)
			for (k=0; k<6; k++)
				tim[i][k] += 1.0;
	}
}

/* 
 * Computes astro constants for Jan 0 of given year 
 */

void computeConstants(year)
	short	year;
{

/*  ndays = time from 12 hr(noon), Jan 0, 1900 to 0 hr, Jan 0 of year */
/*  t = same in julian centuries (units of 36525 days) */
/*  obl = obliquity of ecliptic */
/*  perigee = sun's longitude at perigee  */
/*  eccy = earth's eccentricity */
/*  dmanom,delsid = daily motion (change) in */
/*                        sun's anomaly, sidereal time */
/*  anom0,sidtm0 = sun's mean anomaly, */
/*              sidereal time, all at 0 hr, jan 0 of year year */
/*  c1,c2 = coefficients in equation of center */

	register double 	t;
	long 				ndays;
	double				obl, eccy;
	
	ndays = ((long) (year-1900))*365+(year-1901)/4;
	t = (ndays-0.5)/36525.0;
	obl = deg2rad(dms2deg(23L,27,8.26)-dms2deg(0L,0,46.845)*t);
	cosobl = cos(obl);
	sinobl = sin(obl);
	eccy = 0.01675104-4.180e-5*t-1.26e-7*t*t;
	perigee = deg2rad(FMOD(dms2deg(281L,13,15.0)+dms2deg(1L,43,9.03)*t+
			  dms2deg(0L,0,1.63)*t*t,360.0));
	dmanom = deg2rad(dms2deg(35999L,2,59.10)/36525.0);
	anom0 = deg2rad(FMOD(dms2deg(358L,28,33.0)-dms2deg(0L,0,0.54)*t*t+
		   	FMOD(dms2deg(35999L,2,59.10)*t,360.0),360.0));
	delsid = hms2h(2400,3,4.542)/36525.0;
	sidtm0 = FMOD(hms2h(6,38,45.836)+FMOD(hms2h(2400,3,4.542)*t,24.0),24.0);
	c1 = eccy*(2-eccy*eccy/4);
	c2 = 5*eccy*eccy/4;
}

/*
 *  Double-duty function for leap year and Daylight Saving dates info.
 *  Finds whether year is leap (sets leap = 1 if yes, 0 if no). 
 *  If hasDayLt is non-zero, then also computes the day numbers of the 
 *  start and end of Daylight Savings Time. 
 *  Sets begin = Day no. of the first Sunday of April, and 
 *      finish = Day no. of the Saturday before the last Sunday of October. 
 */

void dayLight(leap, hasDayLt, begin, finish)
	short*	leap;
	short	hasDayLt;
	short*	begin;
	short*	finish;
{
	short m4,m1,jan0,napr1,noct31,apr1,oct31;
	
	m4 = year%400;
	m1 = year%100;
	*leap = !(year%4 != 0 || m1 == 0 && m4 != 0);
	if (hasDayLt==0) {
	/* No adjustment for Daylight Saving Time (year zero for perpetual) */
		*begin = 367;
		*finish = 0;
		return;
	}
	if (year==0) {
	/* Daylight Saving Time in perpetual calendar. April 1 thru Oct 31 */
		*begin = 92; /* April 1, 31+29+31+1 */
		*finish = *begin+213; /* Oct 31, -1+30+31+30+31+31+30+31 */
		return;
	}
	/* Non-zero year. for annual calendar */
	/* jan0,apr1,oct31 = day of week on those dates (fri=0,sat=1,sun=2,...) */
	/* napr1,noct31 = Day no. in year on those dates */
	jan0 = (m4/100*124+1+m1+m1/4-*leap) % 7;
	napr1 = 91 + *leap; /* 31+28+*leap+31+1 */
	noct31 = 304 + *leap; /* 365+*leap-31-30 */
	apr1 = (napr1+jan0) % 7;
	oct31 = (noct31+jan0) % 7;
	*begin = napr1+2-apr1;
	if ( *begin < napr1 ) *begin += 7;
	*finish = noct31+2-oct31;
	if ( *finish > noct31 ) *finish -= 7;
	*finish = *finish-1;
}

/*  
 * Place sun's coaltitude at noon in coaltn, 
 * and return time of noon for day no. nday of year 
 */

double noontime(nday, coaltn)
	short	nday;
	double*	coaltn;
{
/*  slong =  sun's true longitude at noon */
/*  ra = sun's right ascension, decl = sun's declination */
/*  ha = sun's hour angle west */
/*  locmt = local mean time of phenomenon */

	register double t;
	double longh,days,anomaly,slong,sinslong,ra,decl,locmt;
	
	longh = longitude*HPR;
	days = nday+(12.0+longh)/24.0;
	anomaly = anom0+dmanom*days;
	slong = perigee+anomaly+c1*sin(anomaly)+c2*sin(anomaly*2);
	sinslong = sin(slong);
	ra = atan2(cosobl*sinslong,cos(slong))*HPR;
	if (ra<0.0) ra += 24.0;
	decl = asin(sinobl*sinslong);
	locmt = ra-delsid*days-sidtm0;
	t = locmt+longh+timeZone;
	if (t<0.0) t += 24.0;
	if (t>24.0) t -= 24.0;
	*coaltn = FABS(latitude-decl);
	return(t);
}

/*  
 * Returns time on day no. nday of year when sun's coaltitude is coalt.
 * If no such time, then returns a large number. 
 *    time0 is approximate time of phenomenon 
 */

double tempus(nday, coalt, time0)
	short	nday;
	double	coalt;
	double	time0;
{
/*  slong =  true longitude */
/*  ra = sun's right ascension, sindcl = sin(sun's declination) */
/*  ha = sun's hour angle west */
/*  locmt = local mean time of phenomenon */

	double longh,days,anomaly,slong,sinslong,ra,sindcl,cosha,ha,locmt;
	register double t;
	
	longh = longitude*HPR;
	days = nday+(time0+longh)/24.0;
	anomaly = anom0+dmanom*days;
	slong = perigee+anomaly+c1*sin(anomaly)+c2*sin(anomaly*2);
	sinslong = sin(slong);
	ra = atan2(cosobl*sinslong,cos(slong))*HPR;
	if (ra<0.0) ra += 24.0;
	sindcl = sinobl*sinslong;
	cosha = (cos(coalt)-sindcl*sin(latitude))/
		       (sqrt(1.0-sindcl*sindcl)*cos(latitude));
	/*  if cos(ha)>1, then time cannot be evaluated */
	if (FABS(cosha)>1.0) return(1.0e7);
	ha = acos(cosha)*HPR;
	if (time0<12.0) ha = 24.0-ha;
	locmt = ha+ra-delsid*days-sidtm0;
	t = locmt+longh+timeZone;
	if (t<0.0) t += 24.0;
	if (t>24.0) t -= 24.0;
	return(t);
}

/*
 * Returns the direction of qibla in radians. Eastward from north is positive. 
 */

double qibla()
{

	/*  lat0, long0 are Makkah's latitude and longitude in radians */
	double lat0 = 0.3739077, long0 = -0.69504828, dflong;
	
	dflong = longitude-long0;
	return( atan2(sin(dflong),
				cos(latitude)*tan(lat0)-sin(latitude)*cos(dflong)) );
}

/*
 *	TeX code generation for schedule
 */


/*
 * Some TeX code to include.
 *  n = 1 or 2 for two different sections of the schedule.
 */

void texDcl(n)
	short	n;
{
	switch (n) {
	case 1:
		printf("\\hsize=7.5in \\vsize=11in\n");
		printf("\\hoffset=-0.5in \\voffset=-0.4in\n");
		printf("\\font\\eightrm=cmr8 \\font\\eightbf=cmbx8\n");
		printf("\\font\\emph=cmti8\n");
		printf("\\def\\tabrule{\\noalign{\\hrule}}\n");
		printf("\\def\\tabhead{\n");
		printf("\\noalign{\\medskip} \\tabrule\n");
		printf("&&&&\\omit\\hidewidth Fajr\\hidewidth\n");
		printf("&&\\omit\\hidewidth Shuruq\\hidewidth\n");
		printf("&&\\omit\\hidewidth Zuhr\\hidewidth\n");
		printf("&&\\omit\\hidewidth Asr\\hidewidth\n");
		printf("&&\\omit\\hidewidth Maghrib\\hidewidth\n");
		printf("&&\\omit\\hidewidth Isha\\hidewidth&\\cr\n");
		printf("&&\\omit\\hidewidth Date\\hidewidth\n");
		printf("&&\\omit\\hidewidth Dawn\\hidewidth\n");
		printf("&&\\omit\\hidewidth Sunrise\\hidewidth\n");
		printf("&&\\omit\\hidewidth Noon\\hidewidth\n");
		printf("&&\\omit\\hidewidth Afnoon\\hidewidth\n");
		printf("&&\\omit\\hidewidth Sunset\\hidewidth\n");
		printf("&&\\omit\\hidewidth Night\\hidewidth&\\cr\n");
		printf("\\tabrule}\n");
		printf("\\def\\monthtable#1#2{\\vbox{\\tabskip=0pt \\offinterlineskip\n");
		printf("   \\halign to3.25in{\\strut##&\n");
		printf("   \\vrule##\\tabskip=1em plus2em& \\hfil##\\hfil&\n");
		printf("   \\vrule##& \\hfil##\\hfil& \\vrule##& \\hfil##\\hfil&\n");
		printf("   \\vrule##& \\hfil##\\hfil& \\vrule##& \\hfil##\\hfil&\n");
		printf("   \\vrule##& \\hfil##\\hfil& \\vrule##& \\hfil##\\hfil&\n");
		printf("   \\vrule##\\tabskip=0pt\\cr\n");
	    printf("   &\\multispan{15}\\hfil{\\eightbf #1}\\hfil\\cr\n");
	    printf("   #2 \\tabhead\\chart\\tabrule}}}\n");
		break;
	case 2:
		printf("\\bigskip\n\\eightrm \\normalbaselineskip=9pt\n");
		printf("\\setbox\\strutbox=\\hbox{\\vrule height7pt\n");
		printf("      depth2pt width0pt}%%\n");
		printf("\\valign to9in{#\\bigskip & \\vfil# \\cr\n");
		break;
	}
}

/*  
 * Print title material.
 */

void titleTex()
{
	double abszon, absqib;
	short qibd, qibm, zoneH, zoneM;
	char sgnlat, sgnlng, sgnzon, sgnqib;
	
	sgnlat = (latIsS ? dir[3] : dir[2]);
	sgnlng = (longIsW ? dir[1] : dir[0]);
	abszon = FABS(timeZone);
	zoneH = abszon;  zoneM = 10.0*(abszon-zoneH)+0.5;
	sgnzon = (timeZone<0 ? '-' : '+');
	absqib = FABS(direc);
	qibd = absqib;  qibm = 60.0*(absqib-qibd)+0.5;
	if (qibm>=60) {
		qibm = 0;
		qibd += 1;
	}
	sgnqib = (direc<0 ? dir[1] : dir[0]);
	printf("\\tenrm\n");
	if (year!=0) { 
		printf("\\centerline{%4d A.D.  Prayer Schedule for {\\tenbf ",year);
	} else {
		printf("\\centerline{Perpetual Prayer Schedule for {\\tenbf ");
	}
    printf("%s}}\n\\smallskip\n",name);
    printf("\\centerline{Latitude =$%3d^\\circ%02d'$ %c\\ \\ \\ \\ \\ ",
        latd,latm,sgnlat);
	printf("Longitude = $%3d^\\circ%02d'$ %c}\n",longd,longm,sgnlng);
    printf("\\centerline{Zone Time = GMT %c%2dh",sgnzon,zoneH);
    if (zoneM) printf("%3dm",zoneM);
    printf("\\ \\ \\ \\ \\ Qibla = $%3d^\\circ%02d'$ %c (From N)}\n",
        qibd,qibm,sgnqib);
    texDcl(2);
}

/* 
 * Print times for range of days (in the year) first..last-1.
 * Days in month range from startdate to startdate+last-first
 * to keep all monthly tables of same length. 
 * Blank rows are printed for remaining rows numbered thru 31.
 */

void displayTex(first, last, startdate)  	
	short	first;
	short	last;
	short	startdate;
{
	short 			hour,minute;
	double 			t;
	register short	i,j,l;

	printf("\\def\\chart{\n");	
		for (l=first, i=startdate; l<last; l++, i++) {
			printf("&&%2d",i);
			for (j=0; j<6; j++) {
				printf("&&");
				t = tim[l][j];
				if (t>360.0) {
					printf("   *  ");
				} else if (t<0.0) {
					printf("      ");
				} else {
					/* time conversion to am and pm hours and rounded minutes */
					hour = t;  minute = 60.0*(t-hour)+0.5;
					if (minute>=60) {
						minute = 0;
						hour += 1;
					}
					if (hour>12) hour -= 12;
						printf("%3d:%02d",hour,minute);
				}
			}
			printf("&\\cr\n");
		}
	/* Blank out times for remaining day nos. thru 31 */
		for (i=last-first+1; i<32; i++) {
			printf("&&%2d",i);
			for (j=0; j<6; j++) {
				printf("&&      ");
			}
			printf("&\\cr\n");
		}
		printf("}\n");
}

/*  
 * Print header for monthly section n in schedule.
 */

void headrTex(n)
	short	n;
{

	printf("\\monthtable{");
	switch (n) {
	case 0:
		printf("J A N U A R Y}{}\n");
		break;
	case 1:
		printf("F E B R U A R Y}{}\n");
		break;
	case 2:
		printf("M A R C H}{}\n");
		break;
	case 3:
		printf("A P R I L}{");
		if (year==0 && hasDayLt!=0) {
		    printf("\n");
			printf("   &\\multispan{15}\\hfil{({\\emph Subtract one hour}\n");
			printf("   from all times before first Sunday)}\\hfil\\cr}\n");
		} else {
			printf("}\n");
		}
		break;
	case 4:
		printf("M A Y}{}\n");
		break;
	case 5:
		printf("J U N E}{}\n");
		break;
	case 6:
		printf("J U L Y}{}\n");
		break;
	case 7:
		printf("A U G U S T}{}\n");
		break;
	case 8:
		printf("S E P T E M B E R}{}\n");
		break;
	case 9:
		printf("O C T O B E R}{");
		if (year==0 && hasDayLt!=0) {
		    printf("\n");
			printf("   &\\multispan{15}\\hfil{({\\emph Subtract one hour}\n");
			printf("   from all times starting on last Sunday)}\\hfil\\cr}\n");
		} else {
		    printf("}\n");
		}
		break;
	case 10:
		printf("N O V E M B E R}{}\n");
		break;
	case 11:
		printf("D E C E M B E R}{}\n");
		break;
	}
}

/*
 *  Utility functions
 *
 */

double deg2rad(degree)
	double	degree;
{
	return(degree*RPD);
}

double dm2deg(degree, minute)
	short	degree;
	short	minute;
{
	return((double) degree + minute/60.0);
}

double dms2deg(degree, min, sec)
	long	degree;
	short	min;
	double	sec;
{
	return((double) degree + min/60.0 + sec/3600.0);
}

double hms2h(hour, min, sec)
	short	hour;
	short	min;
	double	sec;
{
	return((double) hour + min/60.0 + sec/3600.0);
}



