/* Command decoding, user interface, calls hide */
#include "general.h"
#include "gsurface.h"
#ifdef unix
#define VAXC 1
#endif
#ifdef VAXC
#define huge
#define farmalloc malloc
#define farfree free 
#endif
#ifdef unix
char *strlwr(char *);
#endif
char *(*gtxt)[];   /* gtxt is a pointer to an array of poiter to char */
int ngtxt=0;
int gle_debug;
int noscreenio;

FILE *df;

int hide(float huge *z,int nx, int ny, float minz, float maxz, struct surface_struct *sff);
int scr_end(void);
typedef char *TOKENS[];
int token(char *lin,TOKENS tok,int *ntok,char *outbuff);
int hide_enddefaults(void);

int gle_abort(char *s);
int init_memory(void);
int scr_init(void);
int text_expand(int x);
int token_space(void);
int hide_defaults(void);
int pass_line(void);
char *gletop();
char *getstrv(void);
char *sdup(char *s);
int text_load(char *fname);
int text_free(void);
int do_help(char *s);
int int_edt(char *fname);
int pass_title(void);
int pass_cube(void);
int pass_top(void);
int pass_bot(void);
int pass_marker(void);
int pass_droplines(void);
int pass_riselines(void);
int pass_back(void);
int pass_right(void);
int pass_base(void);
int pass_axis(void);
int pass_anytitle(void);

int getstr(char *s);
float getf(void);
int geton(void);
FILE *myfopen(char *fname, char *mode);
int pass_data(int *nx, int *ny, float *zmin, float *zmax);
extern int trace_on,this_line;
int ngerror;
char input_file[80];

int batch_only=false;
char glearg0[66];
char gleroot[60];
static int xsample,ysample;
#ifdef unix
#include "../../glepath.h"
#endif
main(int argc, char **argv)
{
	char dtype[60];
	char fname[60],*ss;
	int i;

	i=1;
	trace_on = false;

/*---------------------------------------------------------------------------*/
	strcpy(gleroot,argv[0]);
#ifdef unix
	dtype[0] = 0;
	ss = getenv("GLE_TOP");
	if (ss==NULL) ss = GLEPATH;
	strcpy(gleroot,ss);
#endif
#ifdef __TURBOC__
	ss = strchr(gleroot,'\\');
	if (ss==NULL) gle_abort("Unable to locate files AGRV[0] wrong");
	for (;strchr(ss+1,'\\')!=NULL;) ss = strchr(ss+1,'\\');
	*(ss+1) = 0;
#endif
	strcpy(fname,"test.sur");
	init_memory(); /* saves some memory for emergencies */
	if (argc>1) strupr( argv[1] );
	if (argc>1) strcpy(fname, argv[1]);
	for (i=1;i<argc; i++) {
		strupr(argv[i]);
		if (strncmp(argv[i],"-B",2)==0)  batch_only = true;
	}
	strlwr(fname);
	if (!batch_only) scr_init();
	if (strchr(fname,'.')==NULL) strcat(fname,".sur");
	strcpy(input_file,fname);
	text_expand(50); /* Initially allocate 500 lines of text */
	text_load(fname);
	/* IF VAX THEN JUST CALL DRAW_HIDDEN */
	if (batch_only) draw_hidden();
	else int_edt(fname);
	if (!batch_only) scr_end();
}
static char inbuff[200];
static char tkbuff[500];
static char *tk[500];
static int ntok,ct;
static struct surface_struct sf;
static float zmin = 10e10,zmax = -10e10;
static float huge *z;
static int nx,ny;
static int insurf,gotsurf;
static double dxmin,dymin,dxmax,dymax;
double zclipmin,zclipmax;
int zclipminset,zclipmaxset;
draw_hidden()
{
	int i,dri,al;
	static char *space_str = " ";
	
	xsample = 1; ysample = 1;
	zclipmin = 0;  zclipminset = false;
	zclipmax = 0;  zclipmaxset = false;
 
	dxmin = dymin = dxmax = dymax = 0;
	zmin = 10e10; zmax = -10e10;
	ngerror = 0;
	token_space();
	for (i=0;i<500;i++) tk[i] = space_str;
	insurf = false; gotsurf = false;
	hide_defaults();
	for (dri=1;dri<=ngtxt;dri++) {
		strcpy(inbuff, (*gtxt)[dri]);
		al = strlen(inbuff);
		if (trace_on) gprint("Source | %s \n",inbuff);
		token(inbuff,tk,&ntok,tkbuff);
		this_line = dri;
		pass_line();
	}
	if (!gotsurf) {
		gprint("Expecting BEGIN SURFACE ... END SURFACE \n");
		return;
	}
	if (nx==0 || ny==0) {
		gprint("No zdata to plot \n");
		return;
	}
	if (zclipminset || zclipmaxset) {
		for (i=0;i<nx*ny;i++) {
			if (zclipminset) if (z[i]<zclipmin) z[i] = zclipmin;
			if (zclipmaxset) if (z[i]>zclipmax) z[i] = zclipmax;
		}
		if (zclipminset) zmin = zclipmin;
		if (zclipmaxset) zmax = zclipmax;
	}
	hide_enddefaults();

	hide(z,nx,ny,zmin,zmax,&sf);	
}
#define kw(k) if (strcmp(tk[ct],k)==0) 
char *getstrv()
{
	char *s;
	if (ct>=ngtxt) { gprint("Expecting string \n"); return NULL;}
	s = sdup(tk[++ct]);
	if (*s == '"') {	/* remove quotes if exist */
		strcpy(s,tk[ct]+1);
		s[strlen(s)-1] = 0;
	}
	return s;
}		
getstr(char *s)
{
	if (ct>=ngtxt) { gprint("Expecting Color or Lstyle\n"); return;}
	strncpy(s,tk[++ct],11);
}		
float getf()
{
	if (ct>=ngtxt) gprint("Expecting Number\n");
	return atof(tk[++ct]);
}
int geton()
{
	if (ct>=ngtxt) gprint("Expecting ON | OFF\n");
	ct++;
	if (strcmp(tk[ct],"ON")==0) return true;
	if (strcmp(tk[ct],"OFF")==0) return false;
	gprint("Expecting ON | OFF, asuming ON\n");
	return true;
}
pass_line()
{
	int i;
/*	for (i=1; i<ntok; i++) printf("Token {%s} \n",tk[i]); */
	ct = 1;	/* current token */

	if (ntok<1) return;
	kw("BEGIN") {if (strcmp(tk[++ct],"SURFACE")==0) insurf = true; return; }
	if (!insurf) return;
	gotsurf = true;
	     kw("END") {if (strcmp(tk[++ct],"SURFACE")==0) insurf = false;}
	else kw("SIZE") {sf.screenx = getf(); sf.screeny = getf();}
	else kw("TITLE") pass_title();
	else kw("CUBE") pass_cube();
	else kw("DATA") {pass_data(&nx,&ny,&zmin,&zmax);	}
	else kw("ROTATE") {sf.xrotate = getf(); sf.yrotate = getf(); sf.zrotate = getf();} 
	else kw("EYE") {sf.eye_x = getf(); sf.eye_y = getf(); sf.vdist = getf();} 
	else kw("VIEW") {sf.eye_x = getf(); sf.eye_y = getf(); sf.vdist = getf();} 
	else kw("HARRAY") sf.maxh = getf();
	else kw("ZCLIP") pass_zclip();
	else kw("SKIRT") sf.skirt_on = geton();
	else kw("XLINES") sf.xlines_on = geton();
	else kw("YLINES") sf.ylines_on = geton();
	else kw("TOP") pass_top();
	else kw("UNDERNEATH") pass_bot();
	else kw("HIDDEN") sf.hidden_on = geton();
	else kw("MARKER") pass_marker();
	else kw("POINTS") pass_points();
	else kw("DROPLINES") pass_droplines();
	else kw("RISELINES") pass_riselines();
	else kw("HIDDEN") sf.hidden_on = geton();
	else kw("BASE") pass_base();
	else kw("BACK") pass_back();
	else kw("RIGHT") pass_right();
	else if (strstr(tk[1],"AXIS")!=NULL)  pass_axis();
	else if (strstr(tk[1],"TITLE")!=NULL)  pass_anytitle(); 
 
	if (ct<ntok) {
		gprint("Extra parameters on end of line {%s} \n",tk[ct]);
 	}
}
pass_title()
{
	sf.title = getstrv();
	for (ct++;ct<=ntok;ct++) {
		kw("HEI") sf.title_hei = getf();
		else kw("DIST") sf.title_dist = getf();
		else kw("COLOR") getstr(sf.title_color);
		else gprint("Expecting one of HEI, DIST, COLOR , found {%s} \n",tk[ct]);
	}
}
pass_anytitle()
{
	struct axis_struct *ax;
	if (*tk[ct]=='X') ax = &sf.xaxis;
	if (*tk[ct]=='Y') ax = &sf.yaxis;
	if (*tk[ct]=='Z') ax = &sf.zaxis;
	
	ax->title = getstrv();
	for (ct++;ct<=ntok;ct++) {
		kw("HEI") ax->title_hei = getf();
		else kw("DIST") ax->title_dist = getf();
		else kw("COLOR") getstr(ax->title_color);
		else gprint("Expecting one of HEI, DIST, COLOR , found {%s} \n",tk[ct]);
	}
}
pass_cube()
{
	for (ct++;ct<=ntok;ct++) {
		kw("ON") sf.cube_on = true;
		else kw("OFF") sf.cube_on = false;
		else kw("NOFRONT") sf.cube_front_on = false;
		else kw("FRONT") sf.cube_front_on = geton();
		else kw("LSTYLE") getstr(sf.cube_lstyle);
		else kw("COLOR") getstr(sf.cube_color);
		else kw("XLEN") sf.sizex = getf();
		else kw("YLEN") sf.sizey = getf();
		else kw("ZLEN") sf.sizez = getf();
		else gprint("Expecting one of OFF, XLEN, YLEN, ZLEN, FRONT, LSTYLE, COLOR, found {%s} \n",tk[ct]);
	}

}
pass_zclip()
{
	for (ct++;ct<=ntok;ct++) {
		kw("MIN") { zclipmin = getf(); zclipminset = true; }
		else kw("MAX") { zclipmax = getf(); zclipmaxset = true; }
		else gprint("Expecting one of MIN, MAX found {%s} \n",tk[ct]);
	}
}
pass_back()
{
	for (ct++;ct<=ntok;ct++) {
		kw("YSTEP") sf.back_ystep = getf();
		else kw("ZSTEP") sf.back_zstep = getf();
		else kw("LSTYLE") getstr(sf.back_lstyle);
		else kw("COLOR") getstr(sf.back_color);
		else kw("NOHIDDEN") sf.back_hidden = false;
		else gprint("Expecting one of YSTEP, ZSTEP, LSTYLE, COLOR found {%s} \n",tk[ct]);
	}
}
pass_right()
{
	for (ct++;ct<=ntok;ct++) {
		kw("ZSTEP") sf.right_zstep = getf();
		else kw("XSTEP") sf.right_xstep = getf();
		else kw("LSTYLE") getstr(sf.right_lstyle);
		else kw("COLOR") getstr(sf.right_color);
		else kw("NOHIDDEN") sf.right_hidden = false;
		else gprint("Expecting one of ZSTEP, XSTEP, LSTYLE, COLOR found {%s} \n",tk[ct]);
	}
}
pass_base()
{
	for (ct++;ct<=ntok;ct++) {
		kw("XSTEP") sf.base_xstep = getf();
		else kw("YSTEP") sf.base_ystep = getf();
		else kw("LSTYLE") getstr(sf.base_lstyle);
		else kw("COLOR") getstr(sf.base_color);
		else kw("NOHIDDEN") sf.base_hidden = false;
		else gprint("Expecting one of XSTEP, YSTEP, LSTYLE, COLOR found {%s} \n",tk[ct]);
	}
}
pass_droplines() /* toplines lstyle color hidden */
{
	sf.droplines = true;
	for (ct++;ct<=ntok;ct++) {
		kw("LSTYLE") getstr(sf.droplines_lstyle);
		else kw("COLOR") getstr(sf.droplines_color);
		else kw("HIDDEN") sf.droplines_hidden = true;
		else gprint("Expecting one of LSTYLE, COLOR , found {%s} \n",tk[ct]);
	}

}
pass_riselines() /* toplines lstyle color hidden */
{
	sf.riselines = true;
	for (ct++;ct<=ntok;ct++) {
		kw("LSTYLE") getstr(sf.riselines_lstyle);
		else kw("COLOR") getstr(sf.riselines_color);
		else kw("HIDDEN") sf.riselines_hidden = true;
		else gprint("Expecting one of LSTYLE, COLOR , found {%s} \n",tk[ct]);
	}

}
pass_top() /* top lstyle color off */
{
	for (ct++;ct<=ntok;ct++) {
		kw("LSTYLE") getstr(sf.top_lstyle);
		else kw("COLOR") getstr(sf.top_color);
		else kw("ON") sf.top_on = true;
		else kw("OFF") sf.top_on = false;
		else gprint("Expecting one of OFF, LSTYLE, COLOR , found {%s} \n",tk[ct]);
	}
}
pass_bot() 
{
	sf.bot_on = true;
	for (ct++;ct<=ntok;ct++) {
		kw("LSTYLE") getstr(sf.bot_lstyle);
		else kw("COLOR") getstr(sf.bot_color);
		else kw("ON") sf.bot_on = true;
		else kw("OFF") sf.bot_on = false;
		else gprint("Expecting one of ON, OFF, LSTYLE, COLOR , found {%s} \n",tk[ct]);
	}
}
pass_marker() 
{
	getstr(sf.marker);
	for (ct++;ct<=ntok;ct++) {
		kw("COLOR") getstr(sf.marker_color);
		else kw("HEI") sf.marker_hei = getf();
		else gprint("Expecting MARKER markername COLOR c HEI h, found {%s} \n",tk[ct]);
	}
}
pass_axis()
{
	struct axis_struct *ax=NULL;
	if (*tk[ct]=='X') ax = &sf.xaxis;
	if (*tk[ct]=='Y') ax = &sf.yaxis;
	if (*tk[ct]=='Z') ax = &sf.zaxis;
	if (ax==NULL) { gprint("Expecting xaxis,yaxis,zaxis,  \n"); return;}

	for (ct++;ct<=ntok;ct++) {
		     kw("MIN") {ax->min = getf(); ax->minset = true;}
		else kw("MAX") {ax->max = getf(); ax->maxset = true;}
		else kw("DTICKS") ax->step = getf();
		else kw("TICKLEN") ax->ticklen = getf();
		else kw("LEN") ax->ticklen = getf();
		else kw("COLOR") getstr(ax->color);
		else kw("STEP") ax->step = getf();
		else kw("HEI") ax->hei = getf();
		else kw("OFF") ax->on = false;
		else kw("ON") ax->on = true;
		else kw("NOFIRST") ax->nofirst = true;
		else kw("NOLAST") ax->nolast = true;
 		else gprint("Expecting HEI, DIST, COLOR , TICKLEN, MIN, MAX, STEP, found {%s} \n",tk[ct]);
	}
}
static char buff[2032];
FILE *myfopen(char *fname, char *mode);
int alloc_zdata(int nx, int ny);
alloc_zdata(int nx, int ny)
{
	if (z!=NULL) farfree(z);
	z = farmalloc((long) nx * ((long) ny+1) * sizeof(float));
	if (z==NULL) {
		gprint("Unable to allocate enough memory for datafile\n");
		return true;
	}
	return false;
}
double getkeyval(char *buff,char *k);
double getkeyval(char *buff,char *k)
{
	char *s;
	s = strstr(buff,k);
	if (s!=NULL) return atof(s+strlen(k));
	return 0.0;
}
pass_data(int *nx, int *ny, float *zmin, float *zmax)	/* data test.z [nx ny] */
{	
	double v;
	long x,y,xx,yy;
	int c,b,mx,my,xcnt,ycnt;
	char *s;
	char *fname;
	int i;

	xx = yy = x = y = 0;
	fname = getstrv();
 	*nx = 0; *ny = 0;
	for (ct++;ct<=ntok;ct++) {
		kw("NX") *nx = getf();
		else kw("NY") *ny = getf();
		else kw("XSAMPLE") xsample = getf();
		else kw("YSAMPLE") ysample = getf();
		else kw("SAMPLE") {xsample = getf(); ysample = xsample; }
		else gprint("Wanted DATA file.Z  XSAMPLE YSAMPLE SAMPLE NX NY. Found {%s} \n",tk[ct]);
	}
	if (*nx != 0) {
		mx = (*nx - 1)/xsample + 1;
		my = (*ny - 1)/ysample + 1;
	}
	xcnt = xsample; ycnt = ysample;

	if (nx==NULL || ny==0) printf("nx or ny is zero \n");
	if (*nx!=0 && *ny != 0)   if (alloc_zdata(*nx,*ny)) return;
	df = myfopen(fname,"r");
	if (df==NULL) {*nx = 0; *ny = 0; return;}
	for (;!feof(df);) {
	  if (fgets(buff,2000,df)!=NULL) {
		if (*nx==0) {
			strupr(buff);
			*nx  = getkeyval(buff,"NX");
			*ny  = getkeyval(buff,"NY");
			dxmin = getkeyval(buff,"XMIN");
			dymin = getkeyval(buff,"YMIN");
			dxmax = getkeyval(buff,"XMAX");
			dymax = getkeyval(buff,"YMAX");
			if (*nx==0 || *ny==0) {
				gprint("Expecting ! NX 10 NY 10  in first line of data file \n");
				return;
			}
			mx = (*nx - 1)/xsample + 1;
			my = (*ny - 1)/ysample + 1;
			if (alloc_zdata(mx,my)) return;
			fgets(buff,2000,df);
		}
check_again:
		b = strlen(buff);
		c = buff[b-1];
		if (strchr(" \n\t",c)==NULL) { /* we're halfway thru a number */
			buff[b] = getc(df);
			buff[b+1] = 0;
			goto check_again;
		}
		s = strchr(buff,'!');
		if (s!=NULL) *s = 0;
		s = strtok(buff," \t\n,");
		for (;s!=NULL;) {
			v = atof(s);
			if (isdigit(*s) || *s=='-' || *s=='+' || *s=='.') {
				if (x>= *nx) {
					if (ycnt==ysample) {ycnt = 0; yy++;}
					x = 0; y++; ycnt++; xx = 0; xcnt = xsample;
					if (abortkey()) goto abort_data;
				}
				if (y>= *ny) {
					gprint("Too much data in data file %ld %d \n",y,*ny);
					return;
				}
				if (v < *zmin) *zmin = v;
				if (v > *zmax) *zmax = v;

				if (xx<mx && xcnt==xsample && ycnt==ysample) {
					z[xx + yy * mx] = v;	
					xx++;	
					xcnt = 0; 
				}
				xcnt++; 
				x++;
			} else gprint("Not a number {%s} \n",s);
			s = strtok(NULL," \t\n,");
		}	
	  }
	}
	fclose(df);
	*ny = my;
	*nx = mx;
	return;
abort_data:
	fclose(df);
	*nx = 0; *ny = 0;
	return;
}
float *pntxyz;
int npnts;
pnt_alloc(int size)
{
	static cursize;
	void *d;
	if (size+10<cursize) return;
	size = size*2;
	d = farmalloc(size*sizeof(float));
	if (d==NULL) {
		gprint("Unable to allocate storage for POINTS data\n");
		gle_abort("memory shortage\n");
	}
	if (cursize>0) memcpy(d,pntxyz,cursize*sizeof(float));
	cursize = size;
	pntxyz = d;
}
pass_points()
{
	double v;
	char *s;
	char *fname;
	int i,nd,nc;
	fname = getstrv();

	pnt_alloc(30);

	if (ct>ngtxt) {
		gprint("Expecting POINTS filename.xyz \n");
		return;
	}
			
	df = myfopen(fname,"r");
	if (df==NULL) return;
	nd = 0;
	for (;!feof(df);) {
	  if (fgets(buff,2000,df)!=NULL) {
		s = strchr(buff,'!');
		if (s!=NULL) *s = 0;
		nc = 0;
		s = strtok(buff," \t\n,");
		for (;s!=NULL;) {
			v = atof(s);
			pnt_alloc(nd);
			if (isdigit(*s) || *s=='-' || *s=='+' || *s=='.') {
				pntxyz[nd++] = v; nc++;
			} else gprint("Not a number {%s} \n",s);
			s = strtok(NULL," \t\n,");
		}
		if (nc>0 && nc!=3) {
			gprint("Expecting 3 columns in data file, found %d (FATAL ERROR) \n",nc);
		}
	  }
	}
	fclose(df);
	npnts = nd;
	sf.pntxyz = pntxyz;
	sf.npnts = npnts;
}
hide_enddefaults() /* defaults after data and commands read */
{
	if (dxmin==dxmax) dxmax = nx-1;
	if (dymin==dymax) dymax = ny-1;
	if (!sf.xaxis.maxset)  sf.xaxis.max = dxmax;
	if (!sf.yaxis.maxset)  sf.yaxis.max = dymax;
	if (!sf.xaxis.minset)  sf.xaxis.min = dxmin;
	if (!sf.yaxis.minset)  sf.yaxis.min = dymin;
	if (!sf.zaxis.minset)  sf.zaxis.min = zmin;
	if (!sf.zaxis.maxset)  sf.zaxis.max = zmax;
	if (sf.zrotate==0 && sf.xrotate==0 && sf.yrotate==0) {
		sf.xrotate = 60;
		sf.yrotate = 50;
		sf.zrotate = 20;	/* not needed as is corrected later*/
	}
	if (sf.eye_x== -1) {
		sf.eye_x = sf.sizex/2.0;
		sf.eye_y = sf.sizex/2.0;
	}

}

hide_defaults()
{
	/* Setup some defaults, */
	memset(&sf,0,sizeof(sf));
	sf.sizey = sf.sizex = 18;
	sf.sizey = sf.sizex = sf.sizez = 18;
	sf.screenx = 18; sf.screeny = 18;
	sf.eye_x = -1;
	sf.zaxis.type = 2;
	sf.yaxis.type = 1;
	sf.xaxis.on = sf.yaxis.on = sf.zaxis.on = true;
	sf.cube_hidden_on = true;
	sf.cube_on = true;
	sf.cube_front_on = false;
	sf.xlines_on = true;
	sf.ylines_on = true;
	sf.hidden_on = true;
	sf.top_on = true;	
	sf.bot_on = false;
	sf.base_hidden = sf.right_hidden = sf.back_hidden = true;
}
FILE *myfopen(char *fname, char *mode)
{
	FILE *f;
	f = fopen(strlwr(fname),mode);
	if (f==NULL) {
		gprint("Unable to open {%s} \n\n",fname); perror("");
		return NULL;
	}
	return f;
}
abortkey()
{
	if (!kbhit()) return false;
	printf("Press ESC again: \n");
	if (scr_getch()==27) return true;
	else return false;
}
char *gle_top()
{
	char *s;
#ifdef unix
	return gleroot;
#endif
#ifdef __TURBOC__
	return gleroot;
#else
	return "cgle_top:";
#endif
}
char *gledir(char *s);
char *bgidir()
{
#ifdef __TURBOC__
	char *s;
	s = getenv("GLE_BGI");
	if (s==NULL) {
		s = gledir("");
	}
	return s;
#endif
}

char *fontdir(char *fname)
{
	static char fbuff[80];
#ifdef __TURBOC__
	strcpy(fbuff,gle_top());
	strcat(fbuff,"font\\");
#else
	strcpy(fbuff,"cgle_top:");
#endif
#ifdef unix
	strcpy(fbuff,gle_top());
	strcat(fbuff,"font/");
#endif
	strcat(fbuff,fname);
	return &fbuff[0];
}
char *gletopdir(char *fname)
{
	static char fbuff[80];
	strcpy(fbuff,gle_top());
	strcat(fbuff,fname);
	return fbuff;
}
char *gledir(char *fname)
{
	static char fbuff[80];
#ifdef __TURBOC__
	strcpy(fbuff,gle_top());
	strcat(fbuff,"exe\\");
#else
	strcpy(fbuff,"cgle_top:");
#endif
#ifdef unix
	strcpy(fbuff,gle_top());
#endif
	strcat(fbuff,fname);
	return &fbuff[0];
}
