#include<stdio.h>
#include<stdlib.h>
#include<strings.h>
#include<allinc.h>
#include<unistd.h>
#include<signal.h>
#include<vga.h>
#include<vgagl.h>
#include<vgakeyboard.h>
#include<sys/time.h>
#include<sys/types.h>
#include<fcntl.h>
#include"zsoftpcx.h"

typedef struct timeval t_tv;
typedef struct timezone t_tz;
	
unsigned long giverand(unsigned long range,int seedadd);

void viewpcx(int XBeg,int YBeg,char *libname,char *indexname,int cnum,int orientation);

void north_pixel(int *x,int *y,int xm,int ym,int xb,int yb,int pixel);

void east_pixel(int *x,int *y,int xm,int ym,int xb,int yb,int pixel);

void south_pixel(int *x,int *y,int xm,int ym,int xb,int yb,int pixel);

void west_pixel(int *x,int *y,int xm,int ym,int xb,int yb,int pixel);		



void main(int argc,char *argv[]) {
	char question[5000];
	char name[200];
	char nuls[80];
	int hand[11][2] = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
			   {0,0},{0,0},{0,0},{0,0},{0,0}};
	int done=0;
	int deckx[78] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };	
	int vgamode=G800x600x256;
	char posit[11][80] = {"Significator","Cover","Cross","Crown","Beneath","Behind",
			      "Before","Yourself","Your House","Your hopes and fears",
			      "Outcome"};
	/* significator is at 0,0
	   cover is at 325,200
	   cross is at 239,295
	   before is at 475,200
	   behind is at 175,200
	   crown is at 325,0
	   beneath is at 325,400
	   himself is at 700,425
	   house is at 600,275
	   hopes is at 700,125
	   outcome is at 600,0
	   
	*/
	int pos[11][2]={{0,0},{325,200},{239,295},{475,200},{175,200},{325,0},{325,400},
			{700,425},{600,275},{700,125},{600,0}};
	int seed,x,y;

	printf("\nVGATarot - Celtic Cross V0.3\n");
	printf("\nPlease enter your name (first and last) > ");
	gets(name);
	printf("Please enter your question\n> ");
	gets(question);
	
	for(x=0,seed=0;x!=strlen(name);x++,seed+=name[x]);
	for(x=0;x!=strlen(question);x++,seed+=question[x]);

	printf("Please choose a significator\n");
	for(x=0;x!=78;x+=3) printf("[%02d] %-25s [%02d] %-25s [%02d] %-25s\n",x+1,deck[x],x+2,deck[x+1],x+3,deck[x+2]);

	while(!done) {
		printf("\n> ");
		gets(nuls);
	
		if((atoi(nuls)<1)||(atoi(nuls)>78)) {
			printf("please choose a correct significator (1-78)\n"); } else done = 1; }
		
	deckx[atoi(nuls)-1]=1;
	hand[0][0]=atoi(nuls)-1;
	hand[0][1]=0;
	y=1;
	done=0;
	
	while(!done) {
		x=(int)giverand(78,seed);
		if(deckx[x]==0) {
			deckx[x]=1;
			hand[y][0]=x; 
			if((int)giverand(100,seed)>50) hand[y][1]=1; else hand[y][1]=0;
			y++; } 
		if(y==11) done=1; }

	if(!vga_hasmode(vgamode)) {
		printf("mode is unsupported\n"); 
		exit(-1); }
		
	vga_setmode(vgamode);
	gl_setcontextvga(vgamode);
	gl_enableclipping();
	gl_setwritemode(WRITEMODE_OVERWRITE);
	
	printf("\n");

	for(x=0;x!=11;x++) {
		if(hand[x][1]==0) seed=1; else seed=3;
		if(x==2) { if(hand[x][1]==0) seed=2; else seed=4; }
		printf("%-20s : %s %s\n",posit[x],deck[hand[x][0]],hand[x][1]==0?"":"Reversed");
		viewpcx(pos[x][0],pos[x][1],"tarotlib.lbr","tarotlib.index",hand[x][0],seed); } 
		
	printf("\n");

	getchar();
	vga_setmode(TEXT);
	
	exit(1); }
	
unsigned long giverand(unsigned long range,int seedadd)
	{ 
	t_tv tv;
	t_tz tz;
		
	gettimeofday(&tv,&tz);
	srandom((unsigned int)tv.tv_usec+(unsigned int)seedadd);
	return (unsigned long)((random()%range)+1); }

void viewpcx(int XBeg,int YBeg,char *libname,char *indexname,int cnum,int orientation) { 
	int fi; /* index file */
	int fp; /* data file */
	unsigned char *data_pix;
	unsigned long foffset;
	unsigned long flength;
	int XPos,YPos,XMax,YMax;
	zhead pcx;
	Palette pal;
	unsigned long x;
	unsigned int y,z,inbyte;
	unsigned char inc;

	if((fi=open(indexname,O_RDONLY))==-1) {
		vga_setmode(TEXT);
		printf("cannot open index file\n");
		exit(-1); }
		
	lseek(fi,cnum*8,SEEK_SET); /* get the correct index */
	
	read(fi,&foffset,sizeof(foffset)); /* get the offset */
	read(fi,&flength,sizeof(flength)); /* get the length */
	
	close(fi); /* close index file */
	
	if((fp=open(libname,O_RDONLY))==-1) { /* open library file */
		vga_setmode(TEXT);
		printf("cannot open library file\n");
		exit(-1); }
	
	lseek(fp,foffset,SEEK_SET); /* go to correct offset in library */
			
	if(read(fp,&pcx,sizeof(pcx))!=sizeof(pcx)) { /* read PCX header information */
		vga_setmode(TEXT);
		printf("cannot read header information of picture %d\n",cnum);
		exit(-1); }
		
	XMax=(int)pcx.x2; YMax=(int)pcx.y2; /* set the x and y dimensions of the picture */
	
	lseek(fp,128-sizeof(pcx),SEEK_CUR);
	
	if((data_pix=(char *)malloc(flength-128))==NULL) { /* get picture memory */
		vga_setmode(TEXT);
		printf("couldn't allocate picture data memory\n");
		exit(-1); }	
		
	if(((unsigned long)read(fp,data_pix,(flength-128)))!=(flength-128)) { /* read picture data */
		vga_setmode(TEXT);
		printf("couldn't read in picture data\n");
		exit(-1); }
		
	close(fp); /* close library file */
	
	data_pix+=(flength-128-768); /* get to the palette data */
				
	for(x=0;x<255;x++) { /* set the palette data */
		inc=*data_pix++;
		pal.color[x].red=(inc/4);
		inc=*data_pix++;
		pal.color[x].green=(inc/4);
		inc=*data_pix++;
		pal.color[x].blue=(inc/4); }
		
	data_pix-=(flength-131); /* why 131?  I've no damn clue, but it works better than 128 */
		
	gl_setpalette(&pal); /* set the palette */
	
	switch(orientation) { /* set up correct orientation parameters */
		case 1 : /* north */ 
					XMax=(int)pcx.x2+1;
					YMax=(int)pcx.y2;
					XPos=XBeg; 
					YPos=YBeg; 
					break;
		case 2 : /* east */ 
					XMax=(int)pcx.x2+1;
					YMax=(int)pcx.y2;
					XPos=YBeg+YMax;
					YPos=XBeg;
					break;
		case 3 : /* south */ 
					XMax=(int)pcx.x2+1;
					YMax=(int)pcx.y2;
					XPos=XBeg+XMax; 
					YPos=YBeg+YMax; 
					break;
		case 4 : /* west */ 
					XMax=(int)pcx.x2+1;
					YMax=(int)pcx.y2;
					XPos=YBeg;
					YPos=XBeg+XMax;
					break; }
	
	for(x=0;x<(XMax*YMax);) { /* decode the picture */
		inbyte=(unsigned int)*data_pix++;
		if(inbyte>0xc0) { /* RLE compression */
			inbyte-=0xc0;
			y=(unsigned int)*data_pix++;
			for(z=0;z<inbyte;z++) {
				x++;
				switch(orientation) {
					case 1 : north_pixel(&XPos,&YPos,XMax,YMax,XBeg,YBeg,y); break;
					case 2 : east_pixel(&XPos,&YPos,XMax,YMax,XBeg,YBeg,y); break;					
					case 3 : south_pixel(&XPos,&YPos,XMax,YMax,XBeg,YBeg,y); break;
					case 4 : west_pixel(&XPos,&YPos,XMax,YMax,XBeg,YBeg,y); break; } } }
		else {
			x++;
			switch(orientation) {
				case 1 : north_pixel(&XPos,&YPos,XMax,YMax,XBeg,YBeg,inbyte); break;
				case 2 : east_pixel(&XPos,&YPos,XMax,YMax,XBeg,YBeg,inbyte); break;									
				case 3 : south_pixel(&XPos,&YPos,XMax,YMax,XBeg,YBeg,inbyte); break;
				case 4 : west_pixel(&XPos,&YPos,XMax,YMax,XBeg,YBeg,inbyte); break; } } }
				
		free(data_pix); } /* free the data, we are done */
		
void north_pixel(int *x,int *y,int xm,int ym,int xb,int yb,int pixel) {
	if(*y>(ym+yb)) return;
	gl_setpixel(*x,*y,pixel);
	*x=*x+1;
	if(*x==(xm+xb)) {
		*x=xb;
		*y=*y+1; } }
		
void south_pixel(int *x,int *y,int xm,int ym,int xb,int yb,int pixel) { 
	if(*y==yb) return;
	gl_setpixel(*x,*y,pixel);
	*x=*x-1;
	if(*x==xb) {
		*x=xm+xb;
		*y=*y-1; } }		
		
void west_pixel(int *x,int *y,int xm,int ym,int xb,int yb,int pixel) {
	if(*x>(ym+yb)) return;
	gl_setpixel(*x,*y,pixel);
	*y=*y-1;
	if(*y==xb) {
		*y=xb+xm;
		*x=*x+1; } }
		
void east_pixel(int *x,int *y,int xm,int ym,int xb,int yb,int pixel) {
	if((*x)<yb) return;
	gl_setpixel(*x,*y,pixel);
	*y=*y+1;
	if(*y==(xm+xb)) {
		*y=xb;
		*x=*x-1; } }
		