/*
   ***  Galaxy Mapper 2.0 xgalaxy.c
   ***  Compiled under ansi on SGI and Sun workstations
   ***
   ***  This is my first X program (and almost my first C) so don't send any
   ***  flames.  Any suggestions or improvements can be sent to me 
   ***  (since I'm not quite finished yet) at truscott@gfx.engga.uwo.ca
   ***
   ***  To compile type 'cc xgalaxy.c -o xgalaxy -lX11 -lm'
   ***
   ***  To run type 'xgalaxy <name of turn file> <name of home planet file>'
   ***  The default is 'xgalaxy turn homeworld'
   ***
   ***  What this program does it to show the galaxy map for the game
   ***  galaxy.  What it does for the game player is that it will show
   ***  who owns what planets (colour coded, New on version 1.0b),
   ***  and when you click you mouse by a planet it will tell
   ***  you the name of the planet and it's S points.  Also, if you click
   ***  on another planet, it will give you the S points again as well as
   ***  the distance (In light years) to the last planet that you clicked on.
   ***  Version 2.0 changes the parsing command to allow for future additions.
   ***  As well as fixing that colour problem.  This version also fixes the set
   ***  map size from only 200 to any size.
   ***
   ***  Enjoy.
   ***
   ***  Ashley A. Truscott

   ***  The file homeworld is in the format below

   	1    70.40   36.99
   	2   133.64    0.10
	3    96.77  142.23
	4    92.27  184.73
	5   130.93   34.76 
	etc...

*/

/* X include files */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include "xgalaxy.h"

int	numplayer;
PLAYER	**player;
PLANET	**planet;
struct axises	**points;

main (argc, argv)
int argc;
char **argv;
{
        /* Declarations */
	Display 	*mydisplay;
	Window		mywindow;
	Window		exitwindow;
	Window		rootdumb;
	Window		mapwindow;
	Colormap	cmap;
	GC		mygc;
	GC		exitgc;
	GC		mapgc;
	XEvent 		myevent;
	KeySym		mykey;
	XSizeHints	myhint;
	XSizeHints	exithint;
	XSizeHints	maphint;
	int		myscreen;
	unsigned long	myforeground, mybackground;
        int             i,j,k,l,x,count,t,s,stat,r,ack1,ack2,xdumb, ydumb, xloc, yloc;
	unsigned int	widthdumb, heightdumb, bwidthdumb, depthdumb, keydumb;
	unsigned long	pixels[10];
	int		flags = {DoRed|DoGreen|DoBlue};
	char		text[10];
	int		done;
	float		deltax,deltay,distance,damn;
        char            *sbFont;
        Font            font;
        Status          status;
	char		line[100];
	long 		index, ind;
	char		ground1[80], ground2[80], other[80];
	float		zen1, zen2, qyv1, qyv2, correct;

	int 		pip,large,play,homeworld,mult;
	char		file1[20], file2[20];

	FILE		*stream;
	FILE		*infile;

	strcpy(ground1,""); strcpy(ground2,""); 
	strcpy(file1,"turn"); strcpy(file2,"homeworld");
	zen1=0.0; zen2=0.0; qyv1=0.0; qyv2=0.0;
	numplayer = 0; 


	/* Find Files*/
	if (argc > 1)
	{
		strcpy(file1,argv[1]);
		strcpy(file2,argv[2]);
	}

	stream = fopen(file1,"rt");
	infile = fopen(file2,"rt");
	
        /* Initialization */
	mydisplay = XOpenDisplay("");
	myscreen = DefaultScreen (mydisplay);

        /* Default pixel values */
	mybackground = WhitePixel (mydisplay, myscreen);
	myforeground = BlackPixel (mydisplay, myscreen);

        /* Default program-specified window position and size */
	myhint.x = 20;
	myhint.y = 30;
	myhint.width = 900;
	myhint.height = 660;
	myhint.flags = PPosition | PSize;
	
	exithint.width = 40;
	exithint.height = 15;
	exithint.flags = PPosition | PSize;

	maphint.x = 30;
	maphint.y = 30;
	maphint.width = 600;
	maphint.height = 600;
	maphint.flags = PPosition | PSize;


	/* Load Data */
	rewind(stream);
	stat = 0;
	do
	{
		fgets(line,99,stream);
		if (strstr(line,"0,0") != NULL) stat = 1;
	}
	while (stat == 0);

	for (l=0; l<100; l++) other[l] = line[l+4];
	sscanf(other,"%d", &mult);
	correct = 600.0 / (float)(mult);

	rewind(stream);

	count = 0;
	while (1)
	{
		fgets(line,99,infile);
		if(isspace(line[0]) != 0) break;
		count++;
	}

	points = (struct axises **) calloc (count, sizeof(struct axises *));
	rewind(infile);

	homeworld = 0; 
	while (fscanf(infile, "%d %f %f", &j, &deltax, &deltay) != EOF) 
	{
		points[homeworld]=(struct axises *) malloc (sizeof(struct axises));

		points[homeworld]->x_axis = (int)(deltax*correct);
		points[homeworld]->y_axis = (int)(deltay*correct);
		homeworld++;
	}

	
	t = 0;
	stat = 0;
	do
	{
		fgets(line,99,stream);
		if (strstr(line,"Status of Players") != NULL) stat = 1;
	}
	while (stat == 0);
	ind = ftell(stream);

	stat = 0;
	do
	{
		fgets(line,99,stream);
		if (strstr(line,"Your Ship Types") != NULL) stat = 1;
		t++;
	}
	while (stat == 0);

	numplayer = t - 1;
	player = (PLAYER **) calloc (numplayer, sizeof(PLAYER *));

	fseek(stream, ind, SEEK_SET);
	fgets(line,99,stream);
	fgets(line,99,stream);
	
	for (l=0;l<numplayer;l++)
	{
		player[l]=(PLAYER *)malloc(sizeof(PLAYER));
	}

	strcpy(player[0]->temp,"Your");
	strcpy(player[1]->temp,"Unidentified");
	strcpy(player[2]->temp,"Uninhabited");

	fseek(stream, ind, SEEK_SET);
	
	fgets(line,99,stream);
	fgets(line,99,stream);

	for (l=3; l<numplayer; l++)
	{
		fgets(line,99,stream);
		for (s=0; s<100; s++) 
			if(isspace(line[s]) != 0) 
			{	
				pip=s;
				break;
			}
		strncpy(player[l]->temp,line,pip);
	}

	for (l=0; l<numplayer; l++)
	{
		sprintf(player[l]->playername,"%s Planets", player[l]->temp);
	}

	for (i=0; i<numplayer; i++)
	{
		rewind(stream);
		stat = 0;
		do
		{
			fgets(line,99,stream);
			if (strstr(line,player[i]->playername) != NULL) stat = 1;
			if (feof(stream) != 0) stat = 2;
		}
		while (stat == 0);

		if (stat == 2) player[i]->numplanet = 0;

		if (stat == 1)
		{
			index = ftell(stream);

			fgets(line,99,stream);
			fgets(line,99,stream);
			large = 0; count = 0;

			while (1)
			{
				fgets(line,99,stream);
				if(isspace(line[0]) != 0) break;
				for (s=0; s<100; s++)
					if(isspace(line[s]) != 0)
					{
						pip=s;
						break;
					}
				if (large < pip) large=pip;
				count++;
			}

			player[i]->numplanet = count;
			player[i]->planet = (PLANET **) calloc (count, sizeof(PLANET *));
			fseek(stream, index, SEEK_SET);
			fgets(line,99,stream);
			fgets(line,99,stream);

			sprintf(other,"%%%ds %%f %%f %%f",large);

			for (j=0; j<player[i]->numplanet; j++)
			{
				player[i]->planet[j]=(PLANET *)malloc(sizeof(PLANET));

				player[i]->planet[j]->s = 0.0;
				fgets(line,99,stream);
				sscanf(line,other, &player[i]->planet[j]->name, &player[i]->planet[j]->x, &player[i]->planet[j]->y, &player[i]->planet[j]->s);
			}
		}
	}


        /* Window creation */
	mywindow = XCreateSimpleWindow (mydisplay, DefaultRootWindow (mydisplay), myhint.x, myhint.y, myhint.width, myhint.height, 5, myforeground, mybackground);
	XSetStandardProperties (mydisplay, mywindow, "Galaxy Mapper Version 2.0", "Galaxy", None, argv, argc, &myhint);

	exitwindow = XCreateSimpleWindow(mydisplay, mywindow, myhint.width-50, 5, exithint.width, exithint.height, 2, myforeground, mybackground);
	XSetStandardProperties (mydisplay, exitwindow, "", "", None, argv, argc, &exithint);

	mapwindow = XCreateSimpleWindow(mydisplay, mywindow, maphint.x, maphint.y, maphint.width, maphint.height, 2, myforeground, mybackground);
	XSetStandardProperties (mydisplay, mapwindow, "", "", None, argv, argc, &maphint);

        /* Colour */
	cmap = DefaultColormap (mydisplay, DefaultScreen (mydisplay));
	status = XAllocColorCells (mydisplay, cmap, False, NULL, 0, pixels, 10);
	XStoreNamedColor (mydisplay, cmap, "Black", pixels[0], flags);
	XStoreNamedColor (mydisplay, cmap, "Red", pixels[1], flags);
	XStoreNamedColor (mydisplay, cmap, "Blue", pixels[2], flags);
	XStoreNamedColor (mydisplay, cmap, "Green", pixels[3], flags);
	XStoreNamedColor (mydisplay, cmap, "Orange", pixels[4], flags);
	XStoreNamedColor (mydisplay, cmap, "Tan", pixels[5], flags);
	XStoreNamedColor (mydisplay, cmap, "Yellow", pixels[6], flags);
	XStoreNamedColor (mydisplay, cmap, "Cyan", pixels[7], flags);
	XStoreNamedColor (mydisplay, cmap, "Pink", pixels[8], flags);
	XStoreNamedColor (mydisplay, cmap, "Magenta", pixels[9], flags);
	
        /*  GC creation and initialization */
	mygc = XCreateGC (mydisplay, mywindow, 0, 0);
	XSetBackground (mydisplay, mygc, mybackground);
	XSetForeground (mydisplay, mygc, pixels[0]);

	exitgc = XCreateGC (mydisplay, exitwindow, 0, 0);
	XSetBackground (mydisplay, exitgc, pixels[1]);
	XSetForeground (mydisplay, exitgc, pixels[0]);
	XSetWindowBackground (mydisplay, exitwindow, pixels[1]);

	mapgc = XCreateGC (mydisplay, mapwindow, 0, 0);
	XSetBackground (mydisplay, mapgc, mybackground);
	XSetForeground (mydisplay, mapgc, pixels[0]);

        /* Input event selection */
	XSelectInput (mydisplay, mywindow, ButtonPressMask | KeyPressMask | ExposureMask);
	XSelectInput (mydisplay, exitwindow, ButtonPressMask | KeyPressMask | ExposureMask);
	XSelectInput (mydisplay, mapwindow, ButtonPressMask | KeyPressMask | ExposureMask);

        /* Font Type */
	sbFont = "-*-times-*-r-*-*-17-*-*-*-*-*-*-*";
	font = XLoadFont(mydisplay,sbFont);
	XSetFont (mydisplay,mygc,font);
	XSetFont (mydisplay,exitgc,font);
	XSetFont (mydisplay,mapgc,font);

        /* Window mapping */
	XMapRaised (mydisplay, mywindow);
	XMapRaised (mydisplay, exitwindow);
	XMapRaised (mydisplay, mapwindow);

        /* main event-reading loop */
	done = 0;
	while (done == 0)
	{
                /* Read the next event */
		XNextEvent (mydisplay, &myevent);
		switch (myevent.type)
		{
                        /* Repaint window on expose events */
			case Expose:
			if (myevent.xexpose.count == 0)
			{
				status = XGetGeometry (mydisplay, mywindow, &rootdumb, &xdumb, &ydumb, &widthdumb, &heightdumb, &bwidthdumb, &depthdumb);
				XMoveWindow (mydisplay, exitwindow, widthdumb-50, 5); 
				XSetForeground (mydisplay, mapgc, pixels[0]);
				XDrawImageString (myevent.xexpose.display, exitwindow, exitgc, 5, 13, "Exit", 4 );
				for (count=0; count<homeworld; count++)
				{
					XDrawArc (mydisplay, mapwindow, mapgc, points[count]->x_axis-15, -15+points[count]->y_axis, 30,30,0,360*64);
					XDrawArc (mydisplay, mapwindow, mapgc, points[count]->x_axis-30, -30+points[count]->y_axis, 60,60,0,360*64);
					XDrawArc (mydisplay, mapwindow, mapgc, points[count]->x_axis-45, -45+points[count]->y_axis, 90,90,0,360*64);
					XDrawArc (mydisplay, mapwindow, mapgc, points[count]->x_axis-60, -60+points[count]->y_axis, 120,120,0,360*64);
				}
				XDrawLine (mydisplay, mapwindow, mygc, 0, 300, 600,300);
				XDrawLine (mydisplay, mapwindow, mygc, 300, 0, 300,600);

				count = 0;
				for (i=0; i<numplayer; i++)
				{
					if (player[i]->numplanet != 0)
					{
						XSetForeground (mydisplay, mygc, pixels[count+1]);
						XDrawImageString (mydisplay, mywindow, mygc, 660, 125+(count*25), player[i]->playername, strlen(player[i]->playername) );
						for (j=0; j<player[i]->numplanet; j++)
						{
							XSetForeground (mydisplay, mapgc, pixels[count+1]);
							XFillArc (mydisplay, mapwindow, mapgc, (int)(player[i]->planet[j]->x*correct)-2, (int)(player[i]->planet[j]->y*correct)-2, 4, 4, 0,360*64);
						}
						count++;
					}
				}
			}
			break;

                        /* Process keyboard mapping changes */
			case MappingNotify:
			XRefreshKeyboardMapping (&myevent);
			break;

                        /* Process mouse-button presses */
			case ButtonPress:
			if (myevent.xbutton.window == exitwindow)
			done = 1;
			if (myevent.xbutton.window == mapwindow)
			{
				XClearArea (mydisplay, mywindow, 600, 0, 900, 110, False);
				XQueryPointer (mydisplay, mapwindow, &rootdumb, &rootdumb, &xdumb, &ydumb, &xdumb, &ydumb, &keydumb);
				xloc = xdumb/3; yloc = ydumb/3; damn=32767.0;
				for (i=0; i<numplayer; i++)
				{
					if (player[i]->numplanet != 0)
					for (j=0; j<player[i]->numplanet; j++)
					{
						distance = sqrt( pow((xloc-player[i]->planet[j]->x),2.0) + pow((yloc-player[i]->planet[j]->y),2.0));
						if (damn > distance) 
						{
							damn = distance;
							ack1 = i; ack2=j;
						}
					}
				}

				strcpy(ground2,ground1);
				strcpy(ground1,player[ack1]->planet[ack2]->name);
				sprintf(other," S = %4.1f\n", player[ack1]->planet[ack2]->s);
				strcat(ground1,other);
				qyv1=zen1; qyv2=zen2; 
				strcpy(other,"");
				zen1=player[ack1]->planet[ack2]->x; zen2=player[ack1]->planet[ack2]->y;
				distance = sqrt( pow((zen1-qyv1),2.0) + pow((zen2-qyv2),2.0) );
				sprintf(other,"Distance = %3.1f\n",distance);
				XSetForeground (mydisplay, mygc, pixels[0]);
				XDrawImageString (mydisplay, mywindow, mygc, 660, 75, ground1, strlen(ground1) );
				XDrawImageString (mydisplay, mywindow, mygc, 660, 50, ground2, strlen(ground2) );
				XDrawImageString (mydisplay, mywindow, mygc, 660, 100, other, strlen(other) );
			}
			break;

                        /* Process keyboard input */
			case KeyPress:
                        i = XLookupString (&myevent, text, 10, &mykey, 0);
                        if (i == 1 && text[0] == 'q') done = 1;
			break;

               }   /* switch (myevent.type) */

        }   /*  while (done == 0) */

        /* Termination */
	free (points);
	free (planet);
	free (player);
	fclose(infile);
	fclose(stream);
        XUnloadFont (mydisplay,font);
	XFreeGC (mydisplay, mapgc);
	XFreeGC (mydisplay, exitgc);
	XFreeGC (mydisplay, mygc);
	XDestroyWindow (mydisplay, mapwindow);
	XDestroyWindow (mydisplay, exitwindow);
	XDestroyWindow (mydisplay, mywindow);
	XCloseDisplay (mydisplay);
        exit (0);
}
