/* (c) Anthony Jackson (ac_jackson@yahoo.com), 3/27/2000 */
/* permission granted to copy and modify this file for noncommercial
   purposes, as long as this copyright message is preserved.  For other
   uses, contact me.  */
/* Usage: takes a list of sector files as arguments.  Of those files, the
   first line is the sector name, the second line is the x and y position
   of the sector (separated by a space; cannot be negative), the third
   line must have the numbers 1-7 at each of the following:
   1)	position
   2)	start of UWP
   3)	base code
   4)	trade classifications
   5)	zone (amber, red, etc)
   6)	PBG
   7)	alignment
   All must be present, though they need not be in this order.  The name 
   must be at the start of the line, however, and the position should be
   second.  There may not be comments on the first three lines; beyond
   that any line starting with # is considered a comment.  All sectors on
   the command line will be mapped.
 */
/* requires the file blankmap.ps in the same directory as you are running
   from.  Don't edit unless you know postscript. */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#define IMP_ALIGN ('I'*256+'m')
#define NON_ALIGN ('N'*256+'a')
#define CS_ALIGN ('C'*256+'s')
#define MAX_NEIGHBOR 60
struct	star	{
	char	line[100], uwp[10];
	char	aligns[6], base, gas;
	int		gwp;	/* in billions */
	int		tpos;
	int		pm;
	int		pop;	/* in millions */
	int		port;
	int		tamt;
	int		uwtn,wtn,in,re,ag,na,trade,x,y,back,jumps,align,align2,zone;
	int		tradelen;
	short	neighbors[MAX_NEIGHBOR];
	short	distances[MAX_NEIGHBOR];
	short	weight[MAX_NEIGHBOR];
	int		tsum[MAX_NEIGHBOR];
	} stars[50000];
struct alliegance {
	int	align;
	int	tcnt,scnt;
	int tpop,spop;
	int tgwp,sgwp;
	struct alliegance *next,*sub;
	} pool[500], *alliegances, *freeq=pool;
char *sectors[20][20];
char *sectorf[20][20];
int etrade[20][20],itrade[20][20];
int	align[640][800];
int borders[640][800];
int pass;
int	final;
int tramp;
int	maxstar;
int tot_summaries[8][20], imp_summaries[8][20];
int tot_weighted[8][20], imp_weighted[8][20];
int tot_trade, tot_volume, tot_pop, tot_prod, imp_itrade, imp_etrade,
	imp_pop, imp_prod, imp_world, imp_volume;
FILE *trade_file,*route_file,*summary_file;

/*	get distance on hex-grid	*/
int
get_dist( int x1, int y1, int x2, int y2 ) {
	int	dx, dy;
	y1 = y1 * 2; if( !(x1 % 2) ) y1++;
	y2 = y2 * 2; if( !(x2 % 2) ) y2++;
	dy = y2 - y1; if( dy < 1 ) dy = -dy;
	dx = x2 - x1; if( dx < 1 ) dx = -dx;
	if( dx > dy ) return dx;
	return (dx+dy)/2;
}
/*	as above, but using star numbers rather than positions	*/
int
get_sdist( int s1, int s2 ) {
	return get_dist( stars[s1].x, stars[s1].y,stars[s2].x,stars[s2].y);
	}
/*	find all stars within 4 parsecs of a given star	*/
void
get_neighbors( int starnum ) {
	int		x,y,n,nn=0,dist,wtn=stars[starnum].wtn;

	stars[starnum].neighbors[0] = -1;
	if( stars[starnum].zone == 'R' ) return;
	x = stars[starnum].x; y = stars[starnum].y;
	for(n=0;n < maxstar;n++) {
		if( n == starnum ) continue;
		if( (dist=get_dist( x, y, stars[n].x,stars[n].y )) > 4 ) continue;
		if( stars[n].zone == 'R' ) continue;
		if( dist == 4 ) dist = 6;
		switch( wtn - dist ) {
			case 12: stars[n].trade += 30; break;
			case 11: stars[n].trade += 10; break;
			case 10: stars[n].trade += 3; break;
			case 9: stars[n].trade += 1; break;
			}
		stars[starnum].distances[nn] = dist;
		stars[starnum].neighbors[nn++] = n;
		if( nn >= MAX_NEIGHBOR-1 ) break;
		}
	stars[starnum].neighbors[nn] = -1;
	}
/*	read a sector file	*/
char *mod_name( char *name, char *ext ) {
	static	char	out[100];
	char	*p;
	p = strrchr( name, '/' ); if(!p) p = name;
	sprintf(out,"sec/%s",p);
	if( p = strrchr( out, '.' ) ) *p = 0;
	strcat(out,ext);
	return out;
	}
void
read_sec(char *name) {
	FILE	*f = fopen(name,"r");
	FILE	*hf;
	int		x,y,sx,sy;
	char	buf[100], *sname;
	char	trade[20],*p;
	int		wtn,gwp,pop;
	int		POS, PORT, POP, TL, BASE, TRADE, ZONE, GAS, ALIGN;
	int		pm;

	if( !f ) return;
	hf = fopen(mod_name(name,"_sec.html"),"w");
	fgets( buf, 99, f ); p = strtok(buf,"\n\r"); sname = strdup(p);
	fgets( buf, 99, f ); if(sscanf(buf,"%d %d",&sx,&sy)!=2) return;
	sectors[sx][sy] = sname;
	sectorf[sx][sy] = name;
	fprintf(hf,"<html><head><title%s</title></head>\n"
		"<body><h1>%s</h1><pre>\n",sname,sname);
	fprintf(hf,"%s",buf);
	fgets( buf, 99, f );
	if( (p = strchr( buf, '1' ))) POS=p-buf; else return;
	if( (p = strchr( buf, '2' ))) PORT=p-buf; else return;
	POP = PORT+4; TL = PORT+8;
	if( (p = strchr( buf, '3' ))) BASE=p-buf; else return;
	if( (p = strchr( buf, '4' ))) TRADE=p-buf; else return;
	if( (p = strchr( buf, '5' ))) ZONE=p-buf; else return;
	if( (p = strchr( buf, '6' ))) GAS=p-buf+2; else return;
	if( (p = strchr( buf, '7' ))) ALIGN=p-buf; else return;
	fprintf(hf,"%s",buf);
	while( fgets( buf,99,f)) {
		for(p = buf+1;p-buf < POS;p++)
			if(isalpha(p[-1]) && isupper(*p) ) *p = tolower(*p);
		fprintf(hf,"%s",buf);
		if( *buf == '#' ) continue;	/* comment */
		if( *buf == ' ' ) memcpy( buf, buf+POS, 4 );
		buf[POS-1] = 0;
		for(p = buf+POS-2;*p == ' ' && p > buf;p--) *p = 0;
		if( buf[POP] == 'B' ) buf[POP] = 'A';/* remove pop-11 worlds */
		if( buf[POP] >= 'A' ) wtn = 10 + buf[POP]-'A';
		else wtn = buf[POP] - '0';
		pop = wtn; gwp = 0;
		switch( buf[GAS-2] ) {
			case '1': pm = 10; break;
			case '2': pm = 13; break;
			case '3': pm = 17; break;
			case '4': pm = 22; break;
			case '5': pm = 28; break;
			case '6': pm = 36; break;
			case '7': pm = 47; break;
			case '8': pm = 60; break;
			case '9': pm = 78; break;
			default: pm = 30; break;
		}
		stars[maxstar].pm = pm;
		if(pop>5) for(gwp=1;pop>6;pop--) gwp *= 10;
		stars[maxstar].pop = gwp * pm / 10;
		pop = wtn;
		if( wtn > 11 || wtn < 0 ) {
			fprintf(stderr,"Bad entry %s : %9.9s\n",buf,buf+PORT);
			continue;
			}
		switch( buf[TL] ) {
			case 'J': case 'I': gwp = 39000; break;
			case 'G': case 'H': gwp = 24400; break;
			case 'F': gwp = 15000; break;
			case 'E': gwp = 9375; break;
			case 'C': case 'D': gwp = 5860; break;
			case '9': case 'A': case 'B': gwp = 3660; break;
			case '8': gwp = 2290; break; 
			case '7': gwp = 1430; break;
			case '5': case '6': gwp = 895; break;
			case '2': case '3': case '4': gwp = 560; break;
			case '1': gwp = 350; break;
			case '0': gwp = 220; break;
			}
		gwp *= pm;
		for(;pop>10;pop--) gwp *= 10; for(;pop<10;pop++) gwp /= 10;
		stars[maxstar].gwp = gwp;
		if( buf[TL] == '0' ) wtn--;
		if( buf[TL] >= '5' ) wtn++;
		if( buf[TL] >= '9' ) wtn++;
		if( buf[TL] >= 'F' ) wtn++;
		stars[maxstar].uwtn = wtn;
		stars[maxstar].port = buf[PORT];
		switch( buf[PORT] ) {
			case 'A': wtn = (wtn*3 + 13)/4; break;
			case 'B': wtn = (wtn*3 + 11)/4; break;
			case 'C': if( wtn > 9 ) wtn = (wtn+9)/2;
				else wtn = (3 * wtn + 9)/4; break;
			case 'D': if( wtn > 7 ) wtn = (wtn+7)/2;
				else wtn = (wtn*3+7)/4; break;
			case 'E': if( wtn > 5 ) wtn = (wtn+5)/2;
				else wtn = (wtn*3+5)/4; break;
			case 'X': wtn = (wtn-5)/2; if(wtn < 0) wtn = 0; break;
			default: continue;
			}
		stars[maxstar].wtn = wtn;
		switch(wtn) {
			case 13: stars[maxstar].trade = 10000; break;
			case 12: stars[maxstar].trade = 1000; break;
			case 11: stars[maxstar].trade = 100; break;
			case 10: stars[maxstar].trade = 10; break;
			case 9: stars[maxstar].trade = 1; break;
		}
		strncpy( trade, buf+TRADE, 16 ); trade[16] = 0;
		for(p=strtok(trade," ");p;p = strtok(0," ")) {
			if( !strcmp( p, "Ri" ) )
				stars[maxstar].gwp = stars[maxstar].gwp*16/10;
			if( !strcmp( p, "In" ) )
				stars[maxstar].gwp = stars[maxstar].gwp*14/10;
			if( !strcmp( p, "Ag" ) )
				stars[maxstar].gwp = stars[maxstar].gwp*12/10;
			if( !strcmp( p, "Po" ) )
				stars[maxstar].gwp = stars[maxstar].gwp*8/10;
			if( !strcmp( p, "Ni" ) )
				stars[maxstar].gwp = stars[maxstar].gwp*8/10;
			if( !strcmp( p, "Ag" ) ) stars[maxstar].ag = 1;
			if( !strcmp( p, "As" ) || !strcmp( p, "Ba" ) ||
				!strcmp( p, "De" ) || !strcmp( p, "Fl" ) ||
				!strcmp( p, "Ic" ) || !strcmp( p, "Na" ) ||
				!strcmp( p, "Va" ) || !strcmp( p, "Wa" ) ) stars[maxstar].na=1;
			if( !strcmp( p, "As" ) || !strcmp( p, "Ba" ) ||
				!strcmp( p, "De" ) || !strcmp( p, "Na" ) ||
				!strcmp( p, "Fl" ) || !strcmp( p, "Ic" ) ||
				!strcmp( p, "Va" ) || !strcmp( p, "Wa" ) ) stars[maxstar].re=1;
			if( !strcmp( p, "In" ) ) stars[maxstar].in = 1;
			}
		if( stars[maxstar].re ) stars[maxstar].gwp = stars[maxstar].gwp*8/10;
		memcpy( stars[maxstar].line, buf, ALIGN+2 );
		memcpy( stars[maxstar].uwp, stars[maxstar].line+PORT, 9 );
		stars[maxstar].tpos = TRADE;
		if( sscanf( buf+POS,"%2d%2d",&x,&y) != 2 ||
			x > 32 || x < 1 || y > 40 || y < 1 ) {
			fprintf(stderr,"Badloc: %d,%d@%d,%d: %s\n",x,y,sx,sy,buf);
			}
		x += sx*32;
		y += sy*40;
		stars[maxstar].x = x; stars[maxstar].y = y;
		stars[maxstar].align = ((int)buf[ALIGN])*256 + (int)buf[ALIGN+1];
		strncpy(stars[maxstar].aligns, buf+ALIGN,2); stars[maxstar].aligns[2]=0;
		align[x][y] = stars[maxstar].align;
		if( buf[ALIGN+2] == '/' ) {
			stars[maxstar].align2 = ((int)buf[ALIGN+3])*256 + (int)buf[ALIGN+4];
			strncpy(stars[maxstar].aligns, buf+ALIGN+3,2);
			stars[maxstar].aligns[2]=0;
			/* sub-alignments, for vegan autonomy, solomani sub-groups */
			/* will not create a border, but will have different code */
			}
		stars[maxstar].zone = buf[ZONE];
		stars[maxstar].base = buf[BASE];
		stars[maxstar].gas = buf[GAS];
		maxstar++;
	}
	fclose(f);
	fprintf(hf,"</pre></body></html>\n");
	fclose(hf);
}
int
ga( int al, int old ) {
	if( al == NON_ALIGN ) return old;
	if( al == CS_ALIGN ) return old;
	if( !old ) return al;
	if( !al ) return old;
	if( al == old ) return al;
	return al;
	}
void
compute_borders(void) {
	/*	first, give every hex an alliegance */
	int		x,y;
	int		unaligned = 0, al=0, shift=0;

	for( shift = 0; shift < 2; shift++ ) {
		unaligned = 0;
		for(x=1;x<639;x++)
			for(y=1;y<799;y++) {
				if( align[x][y] ) continue;	/* already set */
				al = 0;
				/*	check neighbors.  Always have neighbors of:
					X-1, Y; X, Y-1; X, Y+1; X+1, Y;
					if even, add X-1, Y+1 and X+1, Y+1;
					if odd, add X-1, Y-1 and X+1, Y-1;
				*/
				al = ga( align[x-1][y], al );
				al = ga( align[x-1][y+(x%2 ? -1:1)], al );
				al = ga( align[x+1][y], al );
				al = ga( align[x+1][y+(x%2 ? -1:1)], al );
				al = ga( align[x][y-1], al );
				al = ga( align[x][y+1], al );
				if( !al ) unaligned++;
				else borders[x][y] = al;
			}
		for(x=1;x<639;x++) for(y=1;y<799;y++)
			if( borders[x][y] ) {
				align[x][y] = borders[x][y];
				borders[x][y] = 0;
			}
	}
	for(x=1;x<639;x++)
		for(y=1;y<799;y++)
			if( align[x][y] == NON_ALIGN ) align[x][y] = 0;
	for(x=1;x<639;x++)
		for(y=1;y<799;y++) {
			al = align[x][y];
			borders[x][y] = 0;
			shift = -(x%2);
			if( align[x-1][y+shift] != al ) borders[x][y] += 1;/*UR*/
			if( align[x][y-1] != al ) borders[x][y] += 2;/*top*/
			if( align[x+1][y+shift] != al ) borders[x][y] += 4;/*UL*/
			/*	the other system is responsible if this is reversed */
		}
	for(x=1;x<639;x++) for(y=1;y<799;y++)
		if( align[x][y] == NON_ALIGN ) align[x][y] = 0;
}

int
sortfn( struct star *w1, struct star *w2 ) {
	if( w2->wtn != w1->wtn ) return w2->wtn - w1->wtn;
	if( w2->align != w1->align ) return w2->align - w1->align;
	if( w2->line[0] != w1->line[0] ) return (int)w2->line[0] - (int)w1->line[0];
	return strcmp( w2->line, w1->line );
}
void
sort_stars(void) {
	int		n;
	qsort( stars, maxstar, sizeof( struct star ), sortfn );
	for(n=0;n<maxstar;n++) get_neighbors(n);
	compute_borders();
}
int sec_x( int world ) {
	return ((stars[world].x-1)/32);
}
int sec_y( int world ) {
	return ((stars[world].y-1)/40);
}
int
add_trade( int from, int to, int amt ) {
	int	n, x=amt;
	stars[from].tamt += amt;
	stars[to].tamt += amt;
	if( from > to ) return add_trade(to,from,amt);
	for(n=0;n<MAX_NEIGHBOR;n++) {
		if( stars[from].neighbors[n] != to ) continue;
		x = amt + stars[from].tsum[n];
		stars[from].tsum[n] = x;
		}
	if( sec_x(from) == sec_x(to) && sec_y(from) == sec_y(to)) return;
	for(n=0;n<MAX_NEIGHBOR;n++) {
		if( stars[to].neighbors[n] != from ) continue;
		x = amt + stars[to].tsum[n];
		stars[to].tsum[n] = x;
		}
	}
void
add_weight( int from, int to, int weight ) {
	int	n, x=weight;
	for(n=0;n<MAX_NEIGHBOR;n++) {
		if( stars[from].neighbors[n] != to ) continue;
		x = weight + stars[from].tsum[n];
		stars[from].weight[n] = x;
		}
	for(n=0;n<MAX_NEIGHBOR;n++) {
		if( stars[to].neighbors[n] != from ) continue;
		x = weight + stars[to].tsum[n];
		stars[to].weight[n] = x;
	}
}

void
draw_lineback( int world, int brightness, int verbose ) {
	int	back;
	stars[world].trade += brightness;
	back = stars[world].back;
	if( back == -1 ) return;
	if( final ) (void)add_trade( world, back, brightness );
	add_weight( world, back, brightness );
	draw_lineback( back, brightness, verbose );
}
int
get_trade( int w1, int w2, int jmp) {
	int		tn, lt;
	tn = stars[w1].wtn + stars[w2].wtn;
	if( ( stars[w1].ag && stars[w2].na ) ||
		( stars[w2].ag && stars[w1].na ) ) tn++;
	else if( ( stars[w1].re && stars[w2].in ) ||
		( stars[w2].re && stars[w1].in ) ) tn++;
	if( stars[w1].align == NON_ALIGN ||
		(stars[w1].align != stars[w2].align &&
		(stars[w1].align*stars[w2].align != IMP_ALIGN*CS_ALIGN))) tn--;
	if( get_sdist(w1,w2) > 1 ) tn--;
	if( jmp > 2 ) tn--;
	if( jmp > 5 ) tn--;	/* -3 */
	if( jmp > 9 ) tn--;	/* -4 */
	if( jmp > 19 ) tn--; /* -5 */
	if( jmp > 29 ) tn--; /* -6 */
	if( jmp > 59 ) tn--; /* -7 */
	if( jmp > 99 ) tn--; /* -8 */
	if( tn > 2 * stars[w1].wtn+2 ) tn = 2 * stars[w1].wtn+2;
	if( tn > 2 * stars[w2].wtn+2 ) tn = 2 * stars[w2].wtn+2;
	if( tn < 16 ) return tn;
	if( !tramp && tn < 18 ) return tn;
	if( tramp && tn > 17 ) return tn;
	if( tn % 2 ) lt = 3; else lt = 1;
	while( tn > 17 ) { tn-= 2; lt *= 10; }
	if( final ) {
		if(lt >= 10) {
			fprintf(route_file,"%s:%d:%d:%s:%s\n",sectors[sec_x(w1)][sec_y(w1)],
				lt,jmp,stars[w1].line,stars[w2].line);
			fprintf(route_file,"%s:%d:%d:%s:%s\n",sectors[sec_x(w2)][sec_y(w2)],
				lt,jmp,stars[w2].line,stars[w1].line);
			}
		tot_trade += lt;
		if( stars[w1].align == IMP_ALIGN || stars[w2].align == IMP_ALIGN )
			if( stars[w1].align == stars[w2].align ) imp_itrade += lt;
			else imp_etrade += lt;
		if( sec_x(w1) != sec_x(w2) || sec_y(w1) != sec_y(w2) ) {
			etrade[sec_x(w1)][sec_y(w1)] += lt/2;
			etrade[sec_x(w2)][sec_y(w2)] += lt/2;
		} else itrade[sec_x(w1)][sec_y(w1)] += lt;
		draw_lineback( w1, lt, 1 );
		}
	else draw_lineback( w1, lt, 0 );
	return tn;
}

int
get_weight( int from, int to ) {
	int		n;
	for(n=0;n<MAX_NEIGHBOR;n++) {
		if( stars[from].neighbors[n] != to ) continue;
		return stars[from].weight[n];
	}
	return 0;
}

int
weight_adj( int x ) {
	if( !x ) return 0;
	if( x >= 10 ) return 2 + weight_adj( x/10 );
	if( x < 3 ) return 2;
	return 3;
}

int
route_cost( int from, int to, int dist ) {
	int	weight, cost;
	if( dist < 1 ) {
		fprintf(stderr,"bad distance %d: %.15s(%d,%d) to %.15s(%d,%d\n",dist,
			stars[from].line, stars[from].x,stars[from].y,
			stars[to].line,stars[to].x,stars[to].y);
		dist = 1;
		}
	weight = get_weight(from, to) * 10 + stars[to].trade;
	cost = dist*25 - weight_adj(weight);
	if( stars[from].align != stars[to].align ) cost += 25;
	if( stars[from].port > 'C' ) cost += 25;
	if( stars[from].port > 'D' ) cost += 25;
	if( dist == 1 ) cost += 10;
	if( dist == 3 ) cost += 5;
	return cost;
}

void
get_paths( int source, int world, int jumps ) {
	int		next, nn, tl=15,weight, dist, ljump;
	tl = stars[world].tradelen;
	if( world > source ) get_trade( world, source, stars[world].jumps );
		/* treat jumps through low-grade ports as extra-long */
	ljump = stars[world].jumps;
	if( world != source && stars[world].port > 'C' ) ljump++;
	if( !tramp && world != source && stars[world].port > 'D' ) ljump++;
	for(nn=0;nn < MAX_NEIGHBOR;nn++) {
		next = stars[world].neighbors[nn];
		if( next == -1 ) break;
		dist = stars[world].distances[nn];
		if( tramp && dist > 2 && stars[world].tsum[nn] < 10 ) continue;
/*		if( stars[next].jumps < ljump+dist ) continue;*/
		weight = route_cost( world, next, dist ) + tl;
		if( stars[next].tradelen <= weight ) continue;
		stars[next].jumps = ljump+dist;
		stars[next].back = world;
		stars[next].tradelen = weight;
		}
	}

void
get_trade_to( int world ) {
	int		max, jn, n;
	fprintf(stderr,"%d:get_trade_to %d %.20s\n",pass,stars[world].wtn,
		stars[world].line);
	/*	there's a limit to how far it's useful to show these links	*/
	switch( stars[world].wtn ) {
		case 13: max = 99; break;
		case 12: max = 29; break;
		case 11: max = 19; break;
		case 10: max = 9; break;
		case 9: max = 5; break;
		case 8: max = 2; break;
		default: return;
		}
	for(n=0;n<maxstar;n++) {
		stars[n].jumps =  999;
		stars[n].tradelen = 99999;
		}
	stars[world].jumps = 0;
	stars[world].tradelen = 0;
	stars[world].back = -1;
	for(jn = 0;jn <= max; jn++) {
		for(n=0;n < maxstar;n++) {
			if( stars[n].jumps == jn ) get_paths( world, n, jn );
/*			if( stars[n].tradelen/50 == jn ) get_paths( world, n, jn );*/
		}
	}
}

char * tradecolor( int n ) {
	if( n >= 1000 ) return "4";
	if( n >= 100 ) return "2";
	if( n >= 10 ) return "1";
	if( n ) return "0.5";
	return "0";
	}

void
show_borders( int sx, int sy, FILE *f ) {
	int		x,y,b;

	for(y=1;y <= 40;y++) {
		for(x = 1;x <= 32;x++) {
			b = borders[x + sx*32][y+sy*40];
			if( !b ) continue;
			if( b & 4 ) fprintf(f,"1 "); else fprintf(f,"0 ");
			if( b & 2 ) fprintf(f,"1 "); else fprintf(f,"0 ");
			if( b & 1 ) fprintf(f,"1 "); else fprintf(f,"0 ");
			fprintf(f,"%d %d border\n", x, y );
		}
	}
}
char *print_comma(int n) {
	static	char	buf[20];
	char	*p = buf;
	if(n >= 1000000) sprintf(buf,"%d,%03d,%03d",n/1000000,(n/1000)%1000,n%1000);
	else if( n >= 1000 ) sprintf(buf,"%d,%03d",n/1000,n%1000);
	else sprintf(buf,"%d",n);
	return buf;
	}
int code2num( char code ) {
	if( code < '0' ) return 19;
	if( code <= '9' ) return code - '0';
	if( code < 'A' ) return 19;
	if( code <= 'I' ) return code - 'A' + 10;
	if( code <= 'Z' ) return 18;
	return 0;
}
clear_sub_al() {
	int		n;
	for(n = 0;n<500;n++)
		pool[n].scnt = pool[n].spop = pool[n].sgwp = 0;
}
show_alliegances( int sect, struct alliegance *current, FILE *f ) {
	fprintf(f,"<ul>\n");
	for(;current;current = current->next) {
		if( sect && !current->scnt ) continue;
		if( !sect && current->tcnt < 10 ) continue;
		fprintf(f,"<li>%c%c: %d worlds, %sM pop, ",current->align/256,
			current->align%256,sect?current->scnt:current->tcnt,
			print_comma(sect?current->spop:current->tpop));
		fprintf(f,"%s BCr gnp\n",print_comma(sect?current->sgwp:current->tgwp));
		if( current->sub ) show_alliegances( sect, current->sub, f );
		}
	fprintf(f,"</ul>\n");
	}
add_alliegance_data( int al, int al2, int pop, int gwp ) {
	int		n;
	struct	alliegance	*current, *tmp, *parent;
	for(current = alliegances;current;current=current->next) {
		if( current->align > al ) { current=0;break; }
		if( current->align == al ) break;
		if( !current->next || current->next->align > al ) {
			tmp = freeq++;
			tmp->next = current->next;
			current->next = tmp;
			current = tmp;
			break;
			}
		}
	if( !current ) {
		current=freeq++; current->next = alliegances; alliegances = current; 
		}
	current->align = al;
	current->tcnt++; current->scnt++;
	current->tpop += pop; current->spop += pop;
	current->tgwp += gwp; current->sgwp += gwp;
	if( !al2 ) return;
	parent = current;
	for(current = parent->sub;current;current=current->next) {
		if( current->align > al2 ) { current=0;break; }
		if( current->align == al2 ) break;
		if( !current->next || current->next->align > al2 ) {
			tmp = freeq++;
			tmp->next = current->next;
			current->next = tmp;
			current = tmp;
			break;
			}
		}
	if( !current ) {
		current = freeq++;
		current->next = parent->sub;
		parent->sub = current;
		}
	current->align = al2;
	current->tcnt++; current->scnt++; 
	current->tpop += pop; current->spop += pop;
	current->tgwp += gwp; current->sgwp += gwp;
	}
void
show_sector( int sx, int sy ) {
	FILE	*f;
	int		n, nn, other, is_bold=1,t;
	char	*buf, *fn, wtn, cp, x, y, cbuf[200];
	int		tvol=0,pop=0,gsp=0,sys=0,avg=0;
	int		summaries[8][20];
	int		weighted[8][20];
	if( !sectors[sx][sy] ) return;
	memset(summaries,0,sizeof(summaries));
	memset(weighted,0,sizeof(weighted));
	clear_sub_al();
	sprintf(cbuf,"cp blankmap.ps %s",mod_name(sectorf[sx][sy],".ps"));
	system(cbuf);
	f = fopen(mod_name( sectorf[sx][sy],".ps"),"a" );
	fputs("drawhexes\n",f);
	fprintf(f,"(%s) namesec\n",sectors[sx][sy]);
	if(sy > 0 && sectors[sx][sy-1]) fprintf(f,"(%s) abovesec\n",sectors[sx][sy-1]);
	if(sy < 9 && sectors[sx][sy+1]) fprintf(f,"(%s) belowsec\n",sectors[sx][sy+1]);
	if(sx > 0 && sectors[sx-1][sy]) fprintf(f,"(%s) leftsec\n",sectors[sx-1][sy]);
	if(sx < 9 && sectors[sx+1][sy]) fprintf(f,"(%s) rightsec\n",sectors[sx+1][sy]);
	fprintf(f,"/Courier-Bold findfont 4 scalefont setfont\n");
	show_borders( sx, sy, f );
	for(n=0;n<maxstar;n++) {
		if( sec_x(n) != sx || sec_y(n) != sy ) continue;
		sys++;
		if( stars[n].zone == 'A' ) fprintf(f,"%d %d amber\n",
			stars[n].x-sx*32,stars[n].y-sy*40);
		if( stars[n].zone == 'R' ) fprintf(f,"%d %d redzone\n",
			stars[n].x-sx*32,stars[n].y-sy*40);
		pop += stars[n].pop;
		add_alliegance_data( stars[n].align, stars[n].align2, stars[n].pop,
			stars[n].gwp );
		tot_pop += stars[n].pop;
		tot_prod += stars[n].gwp;
		if( stars[n].align == IMP_ALIGN ) {
			imp_world++;
			imp_pop += stars[n].pop;
			imp_prod += stars[n].gwp;
			}
		if( stars[n].pop > 100000 ) fprintf(stderr,"bad pop %s=%d\n",
			stars[n].line,stars[n].pop);
		gsp += stars[n].gwp;
		if( !stars[n].trade ) continue;
		fprintf(trade_file,"%s:%s:(null):%d\n",sectors[sec_x(n)][sec_y(n)],
			stars[n].line,stars[n].tamt);
		for(nn=0;nn<MAX_NEIGHBOR;nn++) {
			if( (other=stars[n].neighbors[nn]) == -1 ) break;
			if( stars[n].tsum[nn] < 1 ) continue;
			if( sec_x(other) == sx && sec_y(other)==sy )
				tvol += stars[n].tsum[nn];
			else tvol += stars[n].tsum[nn]/2;
			fprintf(f,"%d %d %d %d %s hexl\n",
				stars[n].x-sx*32,stars[n].y-sy*40,
				stars[other].x-sx*32,stars[other].y-sy*40,
				tradecolor(stars[n].tsum[nn]));
			if( n < other ) {
				tot_volume += stars[n].tsum[nn];
				if(stars[n].align == IMP_ALIGN||stars[other].align == IMP_ALIGN)
					imp_volume += stars[n].tsum[nn];
				fprintf(trade_file,"%s:%s:%s:%d\n",sectors[sec_x(n)][sec_y(n)],
					stars[n].line,stars[other].line, stars[n].tsum[nn]);
				fprintf(trade_file,"%s:%s:%s:%d\n",
					sectors[sec_x(other)][sec_y(other)], stars[other].line,
					stars[n].line, stars[n].tsum[nn]);
				}
			}
		}
	for(n=0;n<maxstar;n++) {
		if( sec_x(n) != sx || sec_y(n) != sy ) continue;
		for(nn=0;nn<7;nn++) {
			summaries[nn][code2num(stars[n].uwp[nn])]++;
			weighted[nn][code2num(stars[n].uwp[nn])] += stars[n].pop;
			tot_summaries[nn][code2num(stars[n].uwp[nn])]++;
			tot_weighted[nn][code2num(stars[n].uwp[nn])] += stars[n].pop;
			if( stars[n].align == IMP_ALIGN ) {
				imp_weighted[nn][code2num(stars[n].uwp[nn])] += stars[n].pop;
				imp_summaries[nn][code2num(stars[n].uwp[nn])]++;
				}
			}
		summaries[7][code2num(stars[n].uwp[8])]++;
		weighted[7][code2num(stars[n].uwp[8])] += stars[n].pop;
		tot_summaries[7][code2num(stars[n].uwp[8])]++;
		tot_weighted[7][code2num(stars[n].uwp[8])] += stars[n].pop;
		if( stars[n].align == IMP_ALIGN ) {
			imp_summaries[7][code2num(stars[n].uwp[8])]++;
			imp_weighted[7][code2num(stars[n].uwp[8])] += stars[n].pop;
			}
		buf = stars[n].line;
		wtn = stars[n].wtn;
		if( wtn > 9 ) wtn += 'A' - 10;
		else if( wtn > 0 ) wtn += '0';
		else wtn = '0';
		x = stars[n].x - sx * 32;
		y = stars[n].y - sy * 40;
		if( stars[n].align == NON_ALIGN ) {
			if( is_bold ) fputs("gsave 0.3 setgray\n",f);
			is_bold = 0;
		} else {
			if( !is_bold ) fputs("grestore\n",f);
			is_bold = 1;
		}
		if( strstr( stars[n].line+stars[n].tpos,"Cp" ) ) cp = '+';
		else if( strstr( stars[n].line+stars[n].tpos,"Cx" ) ) cp = '*';
		else cp = ' ';
		fprintf(f,"(%7.7s) (%7.7s%c) (%2.2s %c%c%c%c) %d %d world\n",
			stars[n].line, stars[n].uwp,stars[n].uwp[8],stars[n].aligns,cp,
				stars[n].base, stars[n].gas,wtn,x,y);
	}
	if( !is_bold ) fputs("grestore\n",f);
	fputs("showpage\n",f);
	fclose(f);
	sprintf(cbuf,"ps2pdf %s",mod_name(sectorf[sx][sy],".ps"));
	sprintf(cbuf+strlen(cbuf)," %s",mod_name(sectorf[sx][sy],".pdf"));
	system(cbuf);
	fn = strrchr(sectorf[sx][sy],'/'); if( !fn )fn = sectorf[sx][sy]; else fn++;
	f = fopen(mod_name(sectorf[sx][sy],".html"),"w");
	fprintf(f,"<html><head><title>%s</title></head>\n",sectors[sx][sy]);
	fprintf(f,"<body bgcolor=BLACK text=#00FF00 link=#FF0000>\n"
		"<h1><center>%s</center></h1>\n",sectors[sx][sy]);
	fprintf(f,"<table>\n");
	fprintf(f,"<tr><td>Systems</td><td>%d</td></tr>\n",sys);
	fprintf(f,"<tr><td>Population</td><td>%s million</td></tr>\n",
		print_comma(pop));
	fprintf(f,"<tr><td>Gross Sector Product</td><td>%s billion</td></tr>\n",
		print_comma(gsp));
	if(pop > 100000) avg = gsp/(pop/1000);
	else if(pop) avg = gsp*1000/pop;
	else avg = 0;
	if(pop < 100) pop = 100;
	fprintf(f,"<tr><td>Per Capita GSP</td><td>Cr %s</td></tr>\n",
		print_comma(avg));
	fprintf(f,"<tr><td>Trade Volume</td><td>%s billion</td></tr>\n",
		print_comma(tvol/10));
	fprintf(f,"<tr><td>Internal Trade</td><td>%s billion</td></tr>\n",
		print_comma(itrade[sx][sy]/10));
	fprintf(f,"<tr><td>External Trade</td><td>%s billion</td></tr>\n",
		print_comma(etrade[sx][sy]/10));
	fprintf(f,"</table>\n");
	fprintf(f,"<p>Alliegance Information\n");
	show_alliegances( 1, alliegances, f );
	fprintf(f,"<p>Sector Data File is <a href=%s>here</a>\n",mod_name(fn,"_sec.html"));
	fprintf(f,"<p>PDF map of sector is <a href=%s>here</a>\n",
		mod_name(fn,".pdf"));
	fprintf(f,"<p>Sector Notes are <a href=%s>here</a>\n",
		mod_name(fn,"_worlds.html"));
	fprintf(f,"<p>Summary Report:\n<table>\n<tr><td>Component</td>");
	for(nn=0;nn<=9;nn++) fprintf(f,"<td width=4%%>%d</td>",nn);
	for(nn=0;nn<8;nn++) fprintf(f,"<td width=4%%>%c</td>",nn+'A');
	fprintf(f,"<td width=4%%>I-Z</td>\n");
	fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",summaries[0][nn]);
	fprintf(f,"</tr><tr><td>SIZE</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",summaries[1][nn]);
	fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",summaries[2][nn]);
	fprintf(f,"</tr><tr><td>WATER</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",summaries[3][nn]);
	fprintf(f,"</tr><tr><td>POPULATION</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",summaries[4][nn]);
	fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",summaries[5][nn]);
	fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",summaries[6][nn]);
	fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",summaries[7][nn]);
	fprintf(f,"</tr><tr><td colspan=20 align=center>Percent by Population</td>\n");
	fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",weighted[0][nn]/(pop/100));
	fprintf(f,"</tr><tr><td>SIZE</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",weighted[1][nn]/(pop/100));
	fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",weighted[2][nn]/(pop/100));
	fprintf(f,"</tr><tr><td>WATER</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",weighted[3][nn]/(pop/100));
	fprintf(f,"</tr><tr><td>POPULATION</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",weighted[4][nn]/(pop/100));
	fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",weighted[5][nn]/(pop/100));
	fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",weighted[6][nn]/(pop/100));
	fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
	for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",weighted[7][nn]/(pop/100));
	fprintf(f,"</tr></table>\n");
	fclose(f);
	fprintf(summary_file,"<tr><td>%s</td>",sectors[sx][sy]);
	fprintf(summary_file,"<td>%d,%d</td>",sx-8,sy-4);
	fprintf(summary_file,"<td align=right>%d</td>",sys);
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(pop));
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(gsp));
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(avg));
	fprintf(summary_file,"<td align=right>%s</td>",
		print_comma(tvol/10));
	fprintf(summary_file,"<td align=right>%s</td>",
		print_comma(itrade[sx][sy]/10));
	fprintf(summary_file,"<td align=right>%s</td></tr>\n",
		print_comma(etrade[sx][sy]/10));
}
unsigned char bitmap[1280][1600][3];
void
draw_tl(int x1, int y1, int x2, int y2, int brightness ) {
	int		dx, dy, x, y, dist, r, n;
	y1 = y1 * 2 - (x1 & 1); x1 = x1 * 2 - 1;
	y2 = y2 * 2 - (x2 & 1); x2 = x2 * 2 - 1;
	dx = x1 - x2; dy = y1 - y2;
	if( dx * dx > dy * dy ) dist = (dx > 0) ? dx : -dx;
	else dist = (dy > 0) ? dy : -dy;
	if( dist < 1 ) return;
	brightness /= dist+1;
	brightness *= 60;
	printf("draw_tl: %d,%d to %d,%d, b=%d\n",x1,y1,x2,y2,brightness);
	for(r = 0;r <= dist;r++) {
		x = x2 + r * dx / dist;
		y = y2 + r * dy / dist;
		if( x < 0 || y < 0 ) continue;
		n = bitmap[x][y][2];
		n = n * n + brightness; if( n > 65000 ) n = 65000;
		n = (int) sqrt( (double)n );
		bitmap[x][y][2] = n;
		}
	}

void
show_all() {
	FILE	*f = fopen("allmap.ppm","w");
	FILE	*h = fopen("map.html","w");
    int     n, x, y, b, nn, minx=20, miny=20, maxx=0, maxy=0;
	for(x = 0;x < 20;x++) for(y=0;y<20;y++) {
		if( !sectors[x][y] ) continue;
		if( x < minx ) minx = x; if( x >= maxx ) maxx = x+1;
		if( y < miny ) miny = y; if( y >= maxy ) maxy = y+1;
		}
	fprintf(h,
		"<html><head><title>Map of Traveller Charted Space</title></head>\n"
		"<body bgcolor=BLACK text=#00FF00 link=#FF0000>\n"
		"<h1><center>Map of Traveller Charted Space</center></h1>\n"
		"<p>Related Links</p><ul>\n"
		"<li><a href=summary.html>Toplevel Summary</a> of known space.\n"
		"<li><a href=top_summary.html>Statistical Summary</a> of charted space.\n"
		"<li><a href=imperial_summary.html>Statistical Summary</a> of imperial space.\n"
		"<li><a href=notes.html>Notes</a> on these files.\n"
		"</ul>\n"
		"<p>Key:\n<ul>\n"
		"<li><font color=#00A000>Green</font> Dots: star systems.\n"
		"<li><font color=#A00000>Red</font> Lines: borders.\n"
		"<li><font color=#0000C0>Bright Blue</font> Grid: sector borders.\n"
		"<li><font color=#000080>Dim Blue</font> Grid: subsector borders.\n"
		"<li><font color=#000080>Blue</font> Lines: trade mains, brighter is bigger.\n"
		"<p><img src=allmap.gif usemap=#map0>"
		"<map name=map0>\n");
	for( x = minx; x < maxx; x++ ) for(y = miny; y < maxy; y++) {
		if( !sectorf[x][y] ) continue;
		fprintf(h,
			"<area shape=rect alt=\"%s\" coords=%d,%d,%d,%d href=\"%s\">\n",
			sectors[x][y],(x-minx)*64,(y-miny)*80,(x-minx)*64+63,(y-miny)*80+79,
			mod_name(sectorf[x][y],".html"));
		}
	fprintf(h,"</map></body></html>\n"); fclose(h);
	minx *= 64; maxx *= 64; miny *= 80; maxy *= 80;
	for( x = minx; x <= maxx;x++) {
		for(y = miny;y <= maxy;y++) {
			if( x % 64 == 0 || y % 80 == 0 ) bitmap[x][y][2] = 192;
			else if( x % 16 == 0 || y % 20 == 0 ) bitmap[x][y][2] = 128;
			}
		}
	for(x = minx/2+1; x <= maxx/2; x++ )
		for(y = miny/2+1; y <= maxy/2; y++ ) {
			b = borders[x][y];
			if(b & 1) bitmap[2*x-2][2*y-(x&1)][0] =
				bitmap[2*x-2][2*y-(x&1)-1][0] = 160;
			if(b & 2) bitmap[2*x-1][2*y-(x&1)-1][0] = 160;
			if(b & 4) bitmap[2*x][2*y-(x&1)][0] =
				bitmap[2*x][2*y-(x&1)-1][0] = 160;
			}
    for(n=0;n<maxstar;n++) {
		int		other;
        x = stars[n].x * 2-1;
        y = stars[n].y * 2 - (stars[n].x & 1);
		if( x < minx || x > maxx )
			fprintf(stderr,"badx:%d, minx%d,maxx%d\n",x,minx,maxx);
		if( y < miny || y > maxy )
			fprintf(stderr,"bady:%d, miny%d,maxy%d\n",y,miny,maxy);
		bitmap[x][y][1] = 160;
		for(nn=0;nn<MAX_NEIGHBOR;nn++) {
			if(stars[n].tsum[nn]>=100) {
				other = stars[n].neighbors[nn];
				if( n < other ) draw_tl( stars[n].x, stars[n].y,
					stars[other].x, stars[other].y,
					stars[n].tsum[nn]);
				}
			}
		}
	fprintf(f,"P6\n#creator=cmap\n%d %d\n255\n", 1+maxx-minx, 1+maxy-miny );
	for(y = miny;y <= maxy;y++)
		for( x = minx; x <= maxx;x++)
			fprintf(f,"%c%c%c",bitmap[x][y][0],bitmap[x][y][1],
				(bitmap[x][y][2] & 0xF0));
	fclose(f);
}
int
main(int argc, char **argv) {
	int		y,x,n;
	FILE	*f;

	for(n=1;n<argc;n++) read_sec(argv[n]);
	sort_stars();
	fprintf(stderr,"stars sorted.\n");
	pass++;
	for(n=0;n<maxstar;n++) {
		if( stars[n].wtn < 9 ) break;
		get_trade_to( n );
		}
	pass++;
	for(;n>=0;n--) get_trade_to(n);
	trade_file = fopen("TRADE","w");
	route_file = fopen("ROUTES","w");
	summary_file = fopen("summary.html","w");
	fprintf(summary_file,
		"<html><head>Economic Summary</head><body bgcolor=BLACK text=#00FF00>\n"
		"<h1>Economic Summary</h1><h2>Statistical Analysis</h2>\n"
		"<p>Populations are in millions, economy and trade in billions.\n"
		"<table><tr><td>Sector</td><td>X,Y</td><td># Worlds</td>"
		"<td>Population</td><td>Economy</td><td>Per Capita</td>"
		"<td>T.Volume</td><td>Int. Trade</td><td>Ext. Trade</td></tr>\n");
	final=1;
	pass++;
	for(n=0;n<maxstar;n++) {
		if( stars[n].wtn < 9 ) break;
		get_trade_to( n );
		}
	tramp = 1;
	pass++;
	for(n=0;n<maxstar;n++) {
		if( stars[n].wtn < 8 ) break;
		get_trade_to( n );
		}
	show_all();
/*	show_sector(0,0);*/
	for(y=0;y<=19;y++) for(x=0;x<=19;x++) show_sector(x,y);
    fprintf(summary_file,"<tr><td>Imperial Total</td>");
	fprintf(summary_file,"<td>0,0</td>");
	fprintf(summary_file,"<td align=right>%d</td>",imp_world);
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(imp_pop));
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(imp_prod));
	fprintf(summary_file,"<td align=right>%s</td>",
		print_comma(imp_prod/(imp_pop/1000)));
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(imp_volume/10));
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(imp_itrade/10));
	fprintf(summary_file,"<td align=right>%s</td></tr>\n",
		print_comma(imp_etrade/10));
    fprintf(summary_file,"<tr><td>Global Total</td>");
	fprintf(summary_file,"<td>0,0</td>");
	fprintf(summary_file,"<td align=right>%d</td>",maxstar);
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(tot_pop));
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(tot_prod));
	fprintf(summary_file,"<td align=right>%s</td>",
		print_comma(tot_prod/(tot_pop/1000)));
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(tot_volume/10));
	fprintf(summary_file,"<td align=right>%s</td>",print_comma(tot_trade/10));
	fprintf(summary_file,"<td align=right>0</td></tr>\n");
	fprintf(summary_file,"</table></html>");
	fclose(summary_file);
	f = fopen("imperial_summary.html","w");
	fprintf(f,"<html><head><title>Imperial Summary</title></head>\n");
	fprintf(f,"<body bgcolor=BLACK text=#00FF00 link=#FF0000>\n"
		"<h1><center>Imperial Summary</center></h1>\n");
	fprintf(f,"<table>\n");
	fprintf(f,"<tr><td>Systems</td><td>%d</td></tr>\n",imp_world);
	fprintf(f,"<tr><td>Population</td><td>%s million</td></tr>\n",
		print_comma(imp_pop));
	fprintf(f,"<tr><td>Gross Imperial Product</td><td>%s billion</td></tr>\n",
		print_comma(imp_prod));
	fprintf(f,"<tr><td>Per Capita GSP</td><td>Cr %s</td></tr>\n",
		print_comma(imp_prod/(imp_pop/1000)));
	fprintf(f,"<tr><td>Internal Trade</td><td>%s billion</td></tr>\n",
		print_comma(imp_itrade/10));
	fprintf(f,"<tr><td>External Trade</td><td>%s billion</td></tr>\n",
		print_comma(imp_etrade/10));
	fprintf(f,"</table></body></html>\n");
	fprintf(f,"<p>Summary Report:\n<table>\n<tr><td>Component</td>");
	for(n=0;n<=9;n++) fprintf(f,"<td width=4%%>%d</td>",n);
	for(n=0;n<8;n++) fprintf(f,"<td width=4%%>%c</td>",n+'A');
	fprintf(f,"<td width=4%%>I-Z</td>\n");
	fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[0][n]);
	fprintf(f,"</tr><tr><td>SIZE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[1][n]);
	fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[2][n]);
	fprintf(f,"</tr><tr><td>WATER</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[3][n]);
	fprintf(f,"</tr><tr><td>POPULATION</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[4][n]);
	fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[5][n]);
	fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[6][n]);
	fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[7][n]);
	fprintf(f,"</tr><tr><td colspan=20 align=center>Percent by Population</td>\n");
	fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",imp_weighted[0][n]/(imp_pop/100));
	fprintf(f,"</tr><tr><td>SIZE</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",imp_weighted[1][n]/(imp_pop/100));
	fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",imp_weighted[2][n]/(imp_pop/100));
	fprintf(f,"</tr><tr><td>WATER</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",imp_weighted[3][n]/(imp_pop/100));
	fprintf(f,"</tr><tr><td>POPULATION</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",imp_weighted[4][n]/(imp_pop/100));
	fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",imp_weighted[5][n]/(imp_pop/100));
	fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",imp_weighted[6][n]/(imp_pop/100));
	fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d%%</td>",
		imp_weighted[7][n]/(imp_pop/100));
	fprintf(f,"</tr></table>\n");
	fclose(f);
	f = fopen("top_summary.html","w");
	fprintf(f,"<html><head><title>Toplevel Summary</title></head>\n");
	fprintf(f,"<body bgcolor=BLACK text=#00FF00 link=#FF0000>\n"
		"<h1><center>Toplevel Summary</center></h1>\n");
	fprintf(f,"<table>\n");
	fprintf(f,"<tr><td>Systems</td><td>%d</td></tr>\n",maxstar);
	fprintf(f,"<tr><td>Population</td><td>%s million</td></tr>\n",
		print_comma(tot_pop));
	fprintf(f,"<tr><td>Gross Total Product</td><td>%s billion</td></tr>\n",
		print_comma(tot_prod));
	fprintf(f,"<tr><td>Per Capita GSP</td><td>Cr %s</td></tr>\n",
		print_comma(tot_prod/(tot_pop/1000)));
	fprintf(f,"<tr><td>Trade</td><td>%s billion</td></tr>\n",
		print_comma(tot_trade/10));
	fprintf(f,"</table>\n");
	fprintf(f,"<p>Alliegance Information\n");
	show_alliegances( 0, alliegances, f );
	fprintf(f,"<p>Summary Report:\n<table>\n<tr><td>Component</td>");
	for(n=0;n<=9;n++) fprintf(f,"<td width=4%%>%d</td>",n);
	for(n=0;n<8;n++) fprintf(f,"<td width=4%%>%c</td>",n+'A');
	fprintf(f,"<td width=4%%>I-Z</td>\n");
	fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[0][n]);
	fprintf(f,"</tr><tr><td>SIZE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[1][n]);
	fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[2][n]);
	fprintf(f,"</tr><tr><td>WATER</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[3][n]);
	fprintf(f,"</tr><tr><td>POPULATION</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[4][n]);
	fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[5][n]);
	fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[6][n]);
	fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[7][n]);
	fprintf(f,"</tr><tr><td colspan=20 align=center>Percent by Population</td>\n");
	fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",tot_weighted[0][n]/(tot_pop/100));
	fprintf(f,"</tr><tr><td>SIZE</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",tot_weighted[1][n]/(tot_pop/100));
	fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",tot_weighted[2][n]/(tot_pop/100));
	fprintf(f,"</tr><tr><td>WATER</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",tot_weighted[3][n]/(tot_pop/100));
	fprintf(f,"</tr><tr><td>POPULATION</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",tot_weighted[4][n]/(tot_pop/100));
	fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",tot_weighted[5][n]/(tot_pop/100));
	fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
	for(n=0;n<19;n++)
		fprintf(f,"<td>%d%%</td>",tot_weighted[6][n]/(tot_pop/100));
	fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d%%</td>",
		tot_weighted[7][n]/(tot_pop/100));
	fprintf(f,"</tr></table>\n");
	fclose(f);
	return 0;
}
