/*

	This module contains shared code which may be used by any module. That includes isthere2, a c++ version of isthere.

*/
#include "defs.h"

#ifndef MODSHAREHPP
#define EXT 
#else
#define EXT extern
#endif
	
#define RETVAL_STAR 1
#define RETVAL_PLANET 2
#define RETVAL_BOTH 3
#define RETVAL_NONE 0

//FILE * goesfile;

char   *situation_file  = "..\\DATA\\Current.BIN";
char   *wsituation_file  = "..\\DATA\\wCurrent.BIN";
char   *real_situation_file;

#define CHECK_SITUATION \
	asm xor	ax, ax; asm mov	es, ax; asm cmp	byte ptr es:[0x449], 0x13; asm je	startup; real_situation_file=wsituation_file; goto donestartup; startup: real_situation_file=situation_file; donestartup:

char current_galaxy		= 0;				//67
#ifdef GALAXY2
char	*file2 = "..\\DATA\\starma~1.map";
char	*guide2 = "..\\DATA\\starma~1.gd";

#endif
inline void ReadCurrentGalaxy ()
{
#ifdef GALAXY2
	FILE * fh = fopen (real_situation_file, "rb");
	if (fh!=NULL) {
		fseek(fh, 370+67, SEEK_SET);
		fread (&current_galaxy, 1, 1, fh);
		fclose (fh);
	}
#else
	current_galaxy = 0;
#endif
}

struct SM3FindStruct {
	Udword starFP;
	Udword myFP;
	Uword pNum;
	Uword mNum;
	char starname[21];
	Uchar flags;
	Udword discoverer;
	char name[21];
	Dword sx, sy, sz;
	Uword data;
	Udword nextAlternateFP;
	char retvalType;
} sm3data;

//Function Declarations
EXT Word __cdecl DebugPrintf(const char * format, ...);
EXT void areaclear (Uchar far *dest, Word x, Word y, Word x2, Word y2, Word l, Word h, Uchar pattern);
EXT void wrouthud (Uword x, Uword y, Uword l, char *text);
EXT void warnMsg (char *text, Word line);
EXT void msg (char *string);
EXT Dword ImulAndAdd(Dword main, Dword secondary);
EXT char isthere (double star_id, Word analyzed_sectors_range, double center_x, double center_y, double center_z, FastBool warn);
EXT void PrepareFromSectorCoords (double sect_x, double sect_y, double sect_z);
EXT void PrepareFromSectorCoords (Dword sect_x, Dword sect_y, Dword sect_z);
EXT Dword FindInStarmap (FILE* fh, Dword starmap3Len, char *tgtname, SM3FindStruct *storage);
		

#ifndef MODSHAREHPP
#define MODSHAREHPP
//Includes
#include <stdarg.h>	//for DebugPrintf (SL)
#include <math.h>

//Variables and functions
char warnbuffer[640];

int __cdecl DebugPrintf(const char * format, ...) {
	static Uchar firstRun = 1;
	char stringBuffer[1024];
	va_list argptr;
    int retVal;
	va_start(argptr, format);
	retVal=vsprintf(stringBuffer, format, argptr);
	if (firstRun) {
		firstRun=0;
		FILE* file = fopen("..\\moo3.txt", "wt");
		if (file!=NULL) {
			fprintf(file, "%s\n", stringBuffer);
			fclose(file);
		}
	} else {
		FILE* file = fopen("..\\moo3.txt", "at");
		if (file!=NULL) {
			fprintf(file, "%s\n", stringBuffer);
			fclose(file);
		}
	}
	//retVal=sprintf(stringBuffer2, "echo %s", stringBuffer);
	va_end(argptr);
	
	return retVal;
}


Uchar far *adaptor = (Uchar far *) 0xA0000000;

char digimap[65*5] = {
	 0, 0, 0, 0, 0, // 32. spazio vuoto
	 2, 2, 2, 0, 2, // 33. punto esclamativo
	 5, 0, 0, 0, 0, // 34. virgolette
	 0, 0, 3, 5, 5, // 35. cancelletto (rappresentato da una piccola n.)
	 2, 2, 6, 2, 2, // 36. sistro
	 1, 4, 2, 1, 4, // 37. percento
	 0, 0, 2, 0, 0, // 38. e commericale (non Š possibile visualizzarla)
	 0, 2, 2, 0, 0, // 39. apice
	 4, 2, 2, 2, 4, // 40. parentesi tonda aperta
	 1, 2, 2, 2, 1, // 41. parentesi tonda chiusa
	 0, 0, 7, 2, 2, // 42. asterisco
	 0, 2, 7, 2, 0, // 43. segno pi—
	 0, 0, 0, 2, 1, // 44. virgola
	 0, 0, 7, 0, 0, // 45. segno meno
	 0, 0, 0, 0, 2, // 46. punto
	 0, 4, 2, 1, 0, // 47. barra destrorsa
	 7, 5, 5, 5, 7, // 48. 0
	 3, 2, 2, 2, 7, // 49. 1
	 7, 4, 7, 1, 7, // 50. 2
	 7, 4, 6, 4, 7, // 51. 3
	 4, 6, 5, 7, 4, // 52. 4
	 7, 1, 7, 4, 7, // 53. 5
	 7, 1, 7, 5, 7, // 54. 6
	 7, 4, 4, 4, 4, // 55. 7
	 7, 5, 7, 5, 7, // 56. 8
	 7, 5, 7, 4, 4, // 57. 9
	 0, 2, 0, 2, 0, // 58. duepunti
	 0, 2, 0, 2, 1, // 59. punto e virgola
	 4, 2, 1, 2, 4, // 60. minore
	 0, 7, 0, 7, 0, // 61. uguale
	 1, 2, 4, 2, 1, // 62. maggiore
	 7, 4, 6, 0, 2, // 63. punto interrogativo
	 0, 2, 0, 0, 0, // 64. a commerciale (non visualizzabile)
	 7, 5, 7, 5, 5, // 65. A
	 7, 5, 3, 5, 7, // 66. B
	 7, 1, 1, 1, 7, // 67. C
	 3, 5, 5, 5, 3, // 68. D
	 7, 1, 3, 1, 7, // 69. E
	 7, 1, 3, 1, 1, // 70. F
	 7, 1, 5, 5, 7, // 71. G
	 5, 5, 7, 5, 5, // 72. H
	 2, 2, 2, 2, 2, // 73. I
	 4, 4, 4, 5, 7, // 74. J
	 5, 5, 3, 5, 5, // 75. K
	 1, 1, 1, 1, 7, // 76. L
	 7, 7, 5, 5, 5, // 77. M
	 5, 7, 7, 5, 5, // 78. N
	 7, 5, 5, 5, 7, // 79. O
	 7, 5, 7, 1, 1, // 80. P
	 7, 5, 5, 1, 5, // 81. Q
	 7, 5, 3, 5, 5, // 82. R
	 7, 1, 7, 4, 7, // 83. S
	 7, 2, 2, 2, 2, // 84. T
	 5, 5, 5, 5, 7, // 85. U
	 5, 5, 5, 5, 2, // 86. V
	 5, 5, 7, 7, 5, // 87. W
	 5, 5, 2, 5, 5, // 88. X
	 5, 5, 7, 2, 2, // 89. Y
	 7, 4, 2, 1, 7, // 90. Z
	 0, 0, 6, 2, 2, // 91. parentesi quadra aperta
	 0, 1, 2, 4, 0, // 92. barra sinistrorsa
	 2, 2, 6, 0, 0, // 93. parentesi quadra chiusa
	 2, 2, 2, 2, 2, // 94. ordinale femminile
	 0, 0, 0, 0, 7, // 95. sottolinea
	 1, 2, 0, 0, 0  // 96. accento
};

//NOTVALID: Uses segments, relies on display width being 320
void areaclear (Uchar far *dest, Word x, Word y,
		Word x2, Word y2, Word l, Word h, Uchar pattern)
{
	Uword p;

	if (x<0) x = 0;
	if (y<0) y = 0;

	if (x2>=320) x2 = 319;
	if (y2>=200) y2 = 199;

	if (x2>0) l = x2 - x;
	if (y2>0) h = y2 - y;

	if (x+l>=320) l = 320 - x;
	if (y+h>=200) h = 200 - y;

	if (l<1 || h<1) return;

	p = 320 * y + x;

	asm {	push es
		pusha
		pushf
		cld
		les di, dword ptr dest
		add di, p
		mov al, pattern
		SHL_EAX_8
		mov al, pattern
		SHL_EAX_8
		mov al, pattern
		SHL_EAX_8
		mov al, pattern }
ac_nextl: asm {	push di
		mov cx, l
		shr cx, 2
		jcxz ac_bytes
		REP_STOSD
	}
ac_bytes: asm { mov cx, l
		and cx, 3
		jcxz ac_endl
		rep stosb }
ac_endl:  asm { pop di
		add di, 320
		dec h
		jnz ac_nextl
		popf
		popa
		pop es }
}

//NOTVALID: Directly writes to adaptor, relies on display width being 320
void wrouthud (Uword x, Uword y, Uword l, char *text)
{
	Word j, i, n;
	Uword spot;

	n = 0; if (!l) l = 32767;
	spot = y * 320 + x;

	while (text[n] && n < l) {
		j = (text[n] - 32) * 5;
		for (i = 0; i < 5; i++) {
			if (digimap[j + i] & 1) adaptor[spot+0] = 191 - adaptor[spot+0];
			if (digimap[j + i] & 2) adaptor[spot+1] = 191 - adaptor[spot+1];
			if (digimap[j + i] & 4) adaptor[spot+2] = 191 - adaptor[spot+2];
			spot += 320;
		}
		spot -= 320 * 5;
		spot += 4;
		n++;
	}
}

//NOTVALID: Directly writes to adaptor, text only appears centered on display size of 320x200
void warnMsg (char *text, int line)
{
	int w2 = strlen(text) * 2;

	areaclear (adaptor, 160 - w2 - 1, 100 + line * 8, 0, 0, w2*2 + 2, 8, 127);
	wrouthud (160 - w2, 100 + line * 8 + 1, NULL, text);
}

//////////////////////////////////////////////////////////////////////////////

char msgbuffer[77];
char *divider = "&&&&&&&&&&&&&&&&&&&&&";

void msg (char *string)
{
	int x;

	strcpy (msgbuffer, string);
	msgbuffer[21] = 0;
	//fprintf (goesfile, msgbuffer);
	printf (msgbuffer);

	x = strlen(msgbuffer);
	while (x < 21) {
		//fprintf (goesfile, " ");
		printf (" ");
		x++;
	}
}

void longmsg(char *string) {
	strcpy(msgbuffer, string);
	int pos = 0;
	int len = strlen(msgbuffer);
	while (pos < len-21) {
		//fprintf(goesfile, "%.21s", &(msgbuffer[pos]));
		printf("%.21s", &(msgbuffer[pos]));
		pos+=21;
		while (pos < len-21 && msgbuffer[pos]==32) {
			pos++;
		}
	}
	printf("%.21s", &(msgbuffer[pos]));
	int x = strlen(&(msgbuffer[pos]));
	while (x < 21) {
		//fprintf(goesfile, " ");
		printf(" ");
		x++;
	}
}

long ImulAndAdd(long main, long secondary) {
	long result = 0;
	asm {
		#ifdef WINDOWS
		mov edx, dword ptr main
		mov eax, dword ptr secondary
		imul edx
		add edx, eax
		mov dword ptr result, edx
		#else
		db 0x66; mov dx, word ptr main
		db 0x66; mov ax, word ptr secondary
		db 0x66; imul dx
		db 0x66; add dx, ax
		db 0x66; mov word ptr result, dx
		#endif
	}
	return result;
}

double foundstar_x, foundstar_y, foundstar_z, foundstar_id;
Dword foundstar_sx, foundstar_sy, foundstar_sz;

#define advance 100000
#define halfadvance 50000

char isthere2 (double star_id, Word analyzed_sectors_range, double center_x, double center_y, double center_z, FastBool warn) {
	//TODO: Check current_galaxy
	double laststar_id;
	Dword laststar_x, laststar_y, laststar_z;

	Uword visible_sectors_x = analyzed_sectors_range;
	Uword visible_sectors_y = analyzed_sectors_range;
	Uword visible_sectors_z = analyzed_sectors_range;
	Uword maxvisy = ((2E9 + fabs(center_y))/30.0)*2+2;
	if (visible_sectors_y>maxvisy) {
		visible_sectors_y = (Uword)maxvisy;
	}
	Dword   	sect_x, sect_y, sect_z;

	sect_x = (center_x - visible_sectors_x*halfadvance) / advance; sect_x *= advance;
	sect_y = (center_y - visible_sectors_y*halfadvance) / advance; sect_y *= advance;
	sect_z = (center_z - visible_sectors_z*halfadvance) / advance; sect_z *= advance;
	
	Dword start_y = sect_y;
	Dword start_z = sect_z;
	
	Dword rarity_factor;
	Dword xz, mixer;
	for (Uword sx = visible_sectors_x; sx>0; sect_y=start_y, sect_x+=advance, sx--) {
		double dsect_x = sect_x; dsect_x*=dsect_x;
		for (Uword sy = visible_sectors_y; sy>0; sect_z=start_z, sect_y+=advance, sy--) {
			double dsect_y = sect_y; dsect_y=30*fabs(dsect_y);
			for (Uword sz = visible_sectors_z; sz>0; sect_z+=advance, sz--) {
				double dsect_z = sect_z; dsect_z*=dsect_z;
				double distance_from_home = sqrt (dsect_x + dsect_z) + dsect_y;
				rarity_factor = distance_from_home * 0.25e-8;
				rarity_factor = 1 << rarity_factor;
				rarity_factor--;
				xz = sect_x + sect_z;
				laststar_x = (xz & 0x1ffff) + sect_x - halfadvance;
				if (laststar_x!=0) {
					laststar_y = ImulAndAdd(laststar_x, xz);
					mixer = xz + laststar_y;
					laststar_y = (laststar_y & 0x1ffff) + sect_y - halfadvance;
					if (laststar_y!=0) {
						laststar_z = ImulAndAdd(laststar_y, mixer);
						laststar_z = (laststar_z & 0x1ffff) + sect_z - halfadvance;
						if (laststar_z!=0) {
							Word rarity = (((Word)laststar_x) + ((Word)laststar_y) + ((Word)laststar_z));
							if ((rarity & rarity_factor) == 0) {
								//if (fabs(laststar_id-star_id)<0.00001) return 1;
								laststar_id = ((double)laststar_x)/advance*((double)laststar_y)/advance*((double)laststar_z)/advance;
								#ifdef ISTHEREACTION
									foundstar_x=(double)laststar_x;
									foundstar_y=(double)laststar_y;
									foundstar_z=(double)laststar_z;
									foundstar_id=foundstar_id;
									ISTHEREACTION
								#else
								if (laststar_id==star_id) {
									foundstar_x=(double)laststar_x;
									foundstar_y=(double)laststar_y;
									foundstar_z=(double)laststar_z;
									foundstar_id=foundstar_id;
									
									return 1;
								}
								#endif
							}
						}
					}
				}
			}
		}
		if (warn) {
			sprintf (warnbuffer, "SLICE %d OF %d", visible_sectors_x - sx, visible_sectors_x);
			warnMsg (warnbuffer, 0);
			while (kbhit()) {
				if (getch() == 27) {
					return (0);
				}
			}
		}
	}
	return (0);
}

#define advance 100000
#define halfadvance 50000

void PrepareFromSectorCoords (double sect_x, double sect_y, double sect_z) {
	//TODO: Check current_galaxy
	Dword xz, mixer;
	Dword laststar_x, laststar_y, laststar_z;
	double laststar_id;
	xz = sect_x + sect_z;
	laststar_x = (xz & 0x1ffff) + sect_x - halfadvance;
	laststar_y = ImulAndAdd(laststar_x, xz);
	mixer = xz + laststar_y;
	laststar_y = (laststar_y & 0x1ffff) + sect_y - halfadvance;
	laststar_z = ImulAndAdd(laststar_y, mixer);
	laststar_z = (laststar_z & 0x1ffff) + sect_z - halfadvance;
	laststar_id = ((double)laststar_x)/advance*((double)laststar_y)/advance*((double)laststar_z)/advance;
	foundstar_x=(double)laststar_x;
	foundstar_y=(double)laststar_y;
	foundstar_z=(double)laststar_z;
	foundstar_sx=sect_x;
	foundstar_sy=sect_y;
	foundstar_sz=sect_z;
	foundstar_id=laststar_id;
}

void PrepareFromSectorCoords (Dword sect_x, Dword sect_y, Dword sect_z) {
	PrepareFromSectorCoords((double)sect_x, (double)sect_y, (double)sect_z);
}
	
Dword FindInStarmap (FILE* fh, Dword starmap3Len, char *tgtname, SM3FindStruct *storage) {
	//TODO: Check current_galaxy
	char retvalType = RETVAL_NONE;
	char lastname[21];
	char starname[21];
	char object_label[21];
	char subjectname[21];
	char name[21];
	Dword starFP;
	Uchar flags;
	Udword discoverer;
	Dword sx, sy, sz;
	Uword data;
	Udword nextAlternateFP;
	Dword p, n, ctc;
	ctc = strlen (tgtname);
	Bool exactMatch = 0;
	name[20]=0;
	if (ctc > 20 || ctc <= 0) {
		msg ("INVALID OBJECT NAME.");
		return(0);
	}
	n = 0;
	exactMatch=0;
	fseek (fh, 10, SEEK_SET);
	while (ftell(fh)<starmap3Len) {
		Udword curFP = ftell(fh);
		fread(&flags, 1, 1, fh);
		fread(&discoverer, 4, 1, fh);
		fread(&name, 20, 1, fh);
		if (flags&0x8) {
			fread(&sx, 4, 1, fh);
			fread(&sy, 4, 1, fh);
			fread(&sz, 4, 1, fh);
			fread(&data, 2, 1, fh);
			fread(&nextAlternateFP, 4, 1, fh);
		} else {
			fread(&starFP, 4, 1, fh);
			fread(&data, 2, 1, fh);
			fread(&nextAlternateFP, 4, 1, fh);
		}	
			
		if (memcmp(name, tgtname, ctc)==0 && !(flags&0x20)) {
			if (ctc<20 && ctc>=2 && name[ctc]==32 && name[ctc-1]!=32) {
				exactMatch=1;
				for (int pos = 19; pos>ctc; pos--) {
					if (name[pos]!=32) {
						exactMatch=0;
						break;
					}
				}
				if (exactMatch) {
					if (n>1) {
						msg("NEVERMIND, FOUND");
						msg("EXACT MATCH:");
						msg(name);
					}
					n=1;
				}
			}
			if (!exactMatch) {
				//found it
				if (n==1) {	//If this is the second match
					msg ("AMBIGUOUS SEARCH KEY:");
					msg ("PLEASE EXPAND NAME...");
					msg (divider);
					msg ("POSSIBLE RESULTS ARE:");
					msg (divider);
					lastname[20]=0;
					msg (lastname);
				}
				if (n>0) {
					msg (name);
				}
				n++;
			}
			storage->flags=flags;
			storage->discoverer=discoverer;
			memcpy(lastname, name, 21);
			memcpy(subjectname, name, 21);
			memcpy(storage->name, subjectname, 21);
			storage->myFP = curFP;
			storage->data=data;
			storage->nextAlternateFP=nextAlternateFP;
			
			if (flags&0x8) {
				if (exactMatch) {
					retvalType=RETVAL_STAR;
				} else if (retvalType==RETVAL_BOTH) {
					//do nothing
				} else if (retvalType==RETVAL_PLANET) {
					retvalType=RETVAL_BOTH;
				} else {	//If it was NONE or DELETED
					retvalType=RETVAL_STAR;
				}
				storage->pNum=0x1F;
				storage->mNum=0x1F;
				storage->sx = sx;
				storage->sy = sy;
				storage->sz = sz;
				
				memcpy(storage->starname, subjectname, 20);
				storage->starFP = curFP;
			} else {
				if (exactMatch) {
					retvalType=RETVAL_PLANET;
				} else if (retvalType==RETVAL_BOTH) {
					//do nothing
				} else if (retvalType==RETVAL_STAR) {
					retvalType=RETVAL_BOTH;
				} else {	//If it was NONE or DELETED
					retvalType=RETVAL_PLANET;
				}
				Dword pos = ftell(fh);
				storage->starFP = starFP;
				fseek(fh, starFP+5, SEEK_SET);
				fread(&(storage->starname), 20, 1, fh);
				fseek(fh, starFP+25, SEEK_SET);
				fread(&sx, 4, 1, fh);
				fread(&sy, 4, 1, fh);
				fread(&sz, 4, 1, fh);
				//printf("FOR %.20s: SX=%lli SY=%lli SZ=%lli. ", storage->starname, sx, sy, sz);
				storage->sx = sx;
				storage->sy = sy;
				storage->sz = sz;
				fseek(fh, pos, SEEK_SET);
				
				storage->pNum = ((data>>4)&0x1F);
				storage->mNum = ((data>>9)&0x1F);
			}
			if (exactMatch) break;
		}
	}
	
	if (!n)
		msg ("OBJECT NOT FOUND.");
	/*if (n > 1) {
		found=0;
	}*/
	
	storage->retvalType = retvalType;
	return (n);
}

#else
//Extern variable defs		
EXT char msgbuffer[];

#endif