# include "stdio.h"
# include "cbt.h"
# include "ctype.h"
# include "assert.h"
# include "math.h"
# define SAME 0
# define torad 0.0174532925

double dist(), atof();
double clat, clng;
double radius=50.0;
char countypat[100];
char *countyname = "/usr/spool/town/countymap";
char statepname[100];
char *statename = "/usr/spool/town/statemap";
double radlat, radlong;
int labx[500];
int laby[500];
int nlab=0;
int ctyflg=0;
int countyline=0, numnames=1000;

# define abs(x) ( (t=(x))>= 0 ? t : -t )
main(argc,argv)
	char *argv[];
{
char line[100], request[100], rka[100], rra[300];
char *s, *strchr();
long l1, l2;
char nline[100];
mbuf key, rkey, rrec;
bfile *townfile;
FILE *cntypat, *countyf, *namepat, *namef, *pointf=NULL;
FILE *statepat, *state, *patch, *fdata, *bigname, *bigpat;
double lat, lng;
int townfind, x, y, j, use, a1, a2;
townfile = bopen("/usr/spool/town/ustowns", 0);
argc--; argv++;
while (argc-- > 0)
	{
	if (argv[0][0]=='-')
	switch(argv[0][1])
		{
		case 'f':
			countyname = statename = argv[1];
			argv++; argc--;
			break;
		case 'n':
			numnames = atoi(argv[0]+2);
			break;
		case 'c':
			countyline = atoi(argv[0]+2);
			ctyflg = 1;
			break;
		}
	argv++;
	}
if (townfile==NULL)
	{
	fprintf(stderr, "No town list\n");
	exit(1);
	}
sprintf(countypat, "%s.pat", countyname);
sprintf(statepname, "%s.pat", statename);
cntypat = fopen(countypat, "r");
assert(cntypat!=NULL);
countyf = fopen(countyname, "r");
assert(countyf!=NULL);
namepat = fopen("/usr/spool/town/ftownpat", "r");
assert(namepat!=NULL);
namef = fopen("/usr/spool/town/ftown", "r");
assert(namef!=NULL);
bigpat = fopen("/usr/spool/town/bigpat", "r");
assert(bigpat!=NULL);
bigname = fopen("/usr/spool/town/big", "r");
assert(bigname!=NULL);
state = fopen(statename, "r");
assert(state!=NULL);
statepat = fopen(statepname, "r");
assert(statepat!=NULL);
rkey.mdata = rka; rrec.mdata = rra;
openpl();
while (gets(request))
	{
	s = strchr(request, '\t');
	if (s!=NULL)
		{
		*s++ = 0;
		radius= atof(s);
		s = strchr(s, ' ');
		if (s!=NULL)
			{
			while (*s==' ')
				s++;
			if (*s)
				pointf = fopen(s, "r");
			}
		}
	if (strlen(request)==0)
		continue;
	lcase(request);
	townfind=0;
	if (ctyflg == 0) countyline = (radius<100.);
	nlab=0;
	key.mdata = request; key.mlen = strlen(request);
	bseek(townfile, key);
	while (bread(townfile, &rkey, &rrec)==NULL)
		{
		rkey.mdata[rkey.mlen]=0;
		rrec.mdata[rrec.mlen]=0;
		if (strncmp(rkey.mdata, request, key.mlen)!=SAME)
			break;
		sscanf(rra, "%lf%lf", &lat, &lng);
		townfind++;
		}
	if (townfind==0)
		{
		fprintf(stderr, "Can't find that place\n");
		continue;
		}
	if (townfind>1)
		{
		fprintf(stderr, "Ambiguous - specify state, please\n");
		continue;
		}
	erase();
	space(-5000, -5000, 5000, 5000);
	caps(rka);
	clat = lat; clng=lng;
	/* standard correction latitude = 40.0 N*/
	clng = clng * cos(torad*40.0);
	radlat = radius/dist(clat, clng, clat+1., clng);
	radlong = radius*cos(torad*40.0)/dist(clat, clng, clat, clng+1.);
	a1 = lat/4.; a2 = lng/4.;
	use=0;
	if (countyline)
		{
		patch = cntypat; fdata = countyf;
		}
	else
		{
		patch = statepat; fdata = state;
		}
	rewind(patch);
	fgets(line, 100, patch);
	while (fgets(nline, 100, patch))
		{
		x = atoi(line);
		y = atoi(line+3);
		if (okpat(x, y, lat, lng))
			{
			ctydraw( atol(line+6), atol(nline+6), fdata);
			use++;
			}
		if (x==a1 && y==a2)
			{l1 = atol(line+6); l2 = atol(nline+6);}
		strcpy(line, nline);
		}
	if (use==0)
		ctydraw (l1, l2, fdata);
	lcase(rka);
	if (radius > 200.)
		{
		patch = bigpat; fdata = bigname;
		}
	else
		{
		patch = namepat; fdata = namef;
		}
	if (patch!=NULL && numnames>0)
		{
		rewind(patch);
		use=0;
		fgets(line, 100, patch);
		while (fgets(nline, 100, patch))
			{
			x = atoi(line);
			y = atoi(line+3);
			if (okpat(x,y, lat, lng))
				{
				ckcit (atol(line+6), atol(nline+6), fdata);
				use++;
				}
			if (a1==x && a2==y)
				{l1 = atol(line+6); l2 = atol(nline+6);}
			strcpy(line, nline);
			}
		if (use==0)
			{
			ckcit( l1, l2, fdata);
			}
		}
	if (pointf!=NULL)
		{
		pltpts(pointf);
		fclose(pointf);
		}
	for(j=0; j<10; j++)
		{
		move(-5000,4999);
		move (-5000, 5000);
		}
	/* that hopes to flush out tek */
	fflush(stdout);
	}
exit(0);
}
okpat(ax, ay, lat, lng)
	double lat, lng;
{
double d;
d = dist(ax*4., ay*4., lat, lng);
if (d<radius) return(1);
d = dist((ax+1)*4., ay*4., lat, lng);
if (d<radius) return(1);
d = dist(ax*4., (ay+1)*4., lat, lng);
if (d<radius) return(1);
d = dist((ax+1)*4., (ay+1)*4., lat, lng);
if (d<radius) return(1);
return(0);
}
ctydraw (pos1, pos2, ff)
	FILE *ff;
	long pos1, pos2;
{
float a[4];
int x0, y0, x1, y1;
register int t;
double alat, alng, blat, blng;
fseek (ff, pos1, 0);
while (fread (a, 4, sizeof(float), ff))
	{
	if (ftell(ff)>= pos2) break;
	alat = a[0];
	alng = a[1];
	blat = a[2];
	blng = a[3];

	x0 = (clng - alng)*5000/radlong;
	y0 = (alat - clat)*5000/radlat;
	x1 = (clng - blng)*5000/radlong;
	y1 = (blat - clat)*5000/radlat;
	if (abs(x0)<5000 && abs(x1)<5000 && abs(y0)<5000 && abs(y1)<5000)
		{
		line(x0,y0,x1,y1);
		continue;
		}
	if ((abs(x0)<5000 && abs(y0)<5000) || (abs(x1)<5000 && abs(y1)<5000) )
		{
		partial(&x0, &y0, &x1, &y1);
		line(x0, y0, x1, y1);
		}
	}
}
double
dist (aplat, aplon, bplat, bplon)
	double aplon, aplat, bplon, bplat;
{
/* this code is from the picadad manual. I don't pretend
   to understand it. */
double as, bs, ac, bc, p, cd, d, er;
double rad=0.0174532925;
er = aplon-bplon;
if (er<0) er= -er;
if (er<0.001)
	{
	d = aplat-bplat;
	if (d<0) d= -d;
	return(d*69.055);
	}
as = sin(rad*aplat);
bs = sin(rad*bplat);
ac = cos(rad*aplat);
bc = cos(rad*bplat);
p = cos(er*rad);
cd = (as*bs+ac*bc*p);
return( acos(cd)*3956.56);
}
lcase (s)
	char *s;
{
int c;
for( ; c= *s; s++)
	if (isupper(c))
		*s = tolower(c);
}
caps(s)
	char *s;
{
int c;
if (islower(*s)) *s = toupper(*s);
for( s++; c= *s; s++)
	{
	if (islower(c) && (s[-1]==' ' || s[-1]=='-'))
		if (strncmp(s, "of ", 3)!=SAME)
			*s = toupper(c);
	if (*s==',') break;
	}
for(s++; c= *s; s++)
	if (islower(c)) *s=toupper(c);
}
ckcit(pos1, pos2, countyf)
	FILE *countyf;
	long pos1, pos2;
{
char nam[50], *s;
int x0, y0, i, xthres, ythres, sz;
register int t;
double alat, alng;
float a[2];
fseek (countyf, pos1, 0);
while (fread(a, 2, sizeof(float), countyf))
	{
	if (ftell(countyf) >=pos2) break;
	alat = a[0];
	alng = a[1];
	sz = getc(countyf);
	s=nam;
	while (i= getc(countyf))
		{
		if (i=='\n' || i==0) break;
		*s++ = i;
		}
	*s=0;
	switch (sz)
		{
		case '9': xthres=0; ythres=0; break;
		case '8': xthres=500; ythres=150; break;
		case '7': xthres=1000; ythres=300; break;
		case '6': xthres=1500; ythres=400; break;
		default : xthres=2000; ythres=400; break;
		}
	x0 = (clng-alng)*5000/radlong;
	y0 = (alat-clat)*5000/radlat;
	if (abs(x0)<5000 && abs(y0)<5000)
		{
		for(i=0; i<nlab; i++)
			{
			if (abs(x0-labx[i])<xthres && abs(y0-laby[i])<ythres)
				break;
			}
		if (i<nlab) continue;
		labx[nlab]=x0; laby[nlab]=y0;
		nlab++;
		assert(nlab<500);
		point(x0,y0);
		caps(nam);
		label(nam);
		}
	if (nlab>numnames) break;
	}
}
pltpts(fi)
	FILE *fi;
{
char ln[100], *s;
double alat, alng;
int x, y;
register int t;
while (fgets(ln, 100, fi))
	{
	trimnl(s=ln);
	while (isspace(*s)) s++;
	alat = atof(s);
	while (*s && !isspace(*s))s++;
	while (isspace(*s))s++;
	alng = atof(s);
	while (*s && !isspace(*s)) s++;
	while (isspace(*s)) s++;
	if (s==NULL || alat <0.0 || alng < 0.0)
		continue;
	alng = alng * cos(torad*40.0); /* crummy map projection */
	x = (clng - alng)*5000/radlong;
	y = (alat - clat)*5000/radlat;
	if (abs(x)<5000 && abs(y)<5000)
		{
		move(x,y);
		label(s);
		}
	}
}
partial (x0, y0, x1, y1)
	int *x0, *y0, *x1, *y1;
{ /* pick part of line within 5000 limit */
int ax, ay, bx, by, cx, cy;
double a, b; /* y= ax + b*/
register int t;
ax = *x0; ay= *y0; bx = *x1; by = *y1;
if (abs(ax)>5000 || abs(ay)>5000)
	{
	cx = ax; ax = bx; bx = cx;
	cy = ay; ay = by; by = cy;
	}
/* ax, ay is inside; bx, by is outside */
if (ax == bx) /* vertical line*/
	{
	if (by>5000) by=5000;
	else
	if (by< -5000) by= -5000;
	}
else
if (ay == by) /* horizontal line */
	{
	if (bx>5000) bx=5000;
	else
	if (bx< -5000) bx= -5000;
	}
else
	{/* normal case, with slope */
	a = ( (double) (by-ay) ) / (bx-ax);
	b = ay - a*ax;
	if (bx>5000)
		{
		bx=5000;
		by = a*bx+b;
		}
	else
	if (bx< -5000)
		{
		bx = -5000;
		by = a*bx+b;
		}
	/* now bx is in range.  what about by */
	if (by> 5000)
		{
		by = 5000;
		bx = (by -b)/a;
		}
	else
	if (by< -5000)
		{
		by = -5000;
		bx = (by - b) /a;
		}
	}
*x0 = ax;
*x1 = bx;
*y0 = ay;
*y1 = by;
}
trimnl(s)
	char *s;
{
while (*s)s++;
if (*--s== '\n')*s=0;
}
