#include "all.h"

#include "justify.h"
#include "axis.h"
#include <math.h>
#include "mygraph.h"
int start_subtick(double *tick1, double gmin, double dticks);
int nice_ticks(double *dticks, double *gmin,double *gmax
	, double *t1,double *tn,int minset, int maxset);
int numtrim(char **d,char *s, double dticks);

int nice_log_ticks(double *start, double *last, double *gmin, double *gmax);
double fnloglen(double v,struct axis_struct *ax);
double fnlogx(double v,struct axis_struct *ax);
int fnbig(double v);

/*
#define fnx(vv)  (((vv-gmin)/(gmax-gmin)) * ax->length)
*/
#define fnx(vv) m_fnx(vv)
#define fnlx(vv) fnlogx(vv,ax)
#define true (!false)
#define false 0
struct axis_struct ax;

#define kw(ss) if (strcmp(tok(ct),ss)==0)

static double  gglen,ggmin,ggmax,ggnegate;
double m_fnx(double v);
double m_fnx(double v)
{
	if (ggnegate) 	{
		v = ggmax - (v-ggmin);
	}
	return (((v-ggmin)/(ggmax-ggmin)) * gglen );

}
draw_axis(struct axis_struct *ax)	/* Draws the axis */
{
	double fi,x,y,gmin,gmax,dticks,tick1,tickn;
	int i,xax,n,savecap,dolittle;
   	int isbig;
	double tlen,stlen,dsubticks,tt,t,start;
	double h,label_width,dist;
	double bl,br,bu,bd;
	double ox,oy,llen,maxd,maxwid,ty,tx;
	double th;

	if (ax->type==1 || ax->type==3) xax = true; else xax = false;
	g_source("BEGIN AXIS  =====\n");
/*! Return if side is turned OFF*/
	if (ax->off) return ;
#define dont if (1==2)
/*! Ok lets draw the side first. */
	g_get_line_cap(&savecap);
	g_get_xy(&ox,&oy);
	g_gsave();
	g_set_color(ax->side_color);
	g_set_line_width(ax->side_lwidth);
	g_set_line_style(ax->side_lstyle);
	if (!ax->side_off) {
		g_set_line_cap(1);
		g_get_xy(&x,&y);
		if (xax)
			g_line(x+ax->length,y);
		else
			g_line(x,y+ax->length);
	}
	g_grestore();
	g_set_line_cap(savecap);

/*----------------------------- Generate the places for labels to go */
	ggmin = ax->min;
	ggmax = ax->max;
	ggnegate = ax->negate;
	gmin = ax->min;
	gmax = ax->max;
	gglen = ax->length;

	if (ax->log) {	/* generate places for log main ticks */
	 if (!ax->lgset) {
		/* dist between 10^0 and 10^1 */
		dist = fnloglen(2,ax) - fnloglen(1,ax);
		if (dist > ax->base*4.5) ax->lg25 = true;
		if (dist > ax->base*22.0) ax->lg1 = true;
	 }
	 nice_log_ticks(&tick1,&tickn,&gmin,&gmax);
	 if (ax->nplaces == 0) { /* haven't been set, so generate positions. */
	  for (fi=tick1; fi<= tickn+(pow(10.0,floor(log10(fi)+.0001)))/100
			; fi += pow(10.0,floor(log10(fi)+.0001))) {
		i = floor(.0001 + fi/pow(10.0,floor(log10(fi))));
		if (fnbig(fi) || (ax->lg1) || (ax->lg25 && ((i==2) || (i==5))) ) {
		 if (++(ax->nplaces)>199) {gprint("Too many places\n");return;}
		 ax->places[ax->nplaces] = fi;
		}
	  }
	 }
	} else {
	dticks = 0;
	if (ax->nticks!=0)  dticks = (gmax - gmin)/ax->nticks;
	if (ax->dticks!=0)  dticks = ax->dticks ;
	if (dticks>0) if ((gmax - gmin)/dticks>90) {gprint("too many ticks \n"); dticks = 0;}

	nice_ticks(&dticks, &gmin, &gmax, &tick1, &tickn,ax->minset,ax->maxset);

	if (ax->nofirst) tick1 = tick1 + dticks;
	if (ax->nolast) tickn = tickn - dticks;
	tickn = tickn + dticks/100; /* to avoid rounding errors */
	if (ax->nplaces == 0) { /* haven't been set, so generate positions. */
	  { double end_tick = (tickn+dticks/100.0);
	  for (fi=tick1; fi<=end_tick; fi += dticks) {
		if (++(ax->nplaces)>49) {gprint("Too many places\n");return;}
		ax->places[ax->nplaces] = fi;
	  }
	  }
	}
	}

/*------------------------------  Now draw the ticks	(subticks first) */
	g_gsave();

	tlen = ax->base/5;
	if (ax->ticks_length!=0) tlen = ax->ticks_length;
	/* first the subticks */
	stlen = tlen/2;
	if (ax->subticks_length!=0) stlen = ax->subticks_length;
	dsubticks = 0;

	if (!ax->log) {	/* Draw little log ticks if enough space */
	if (ax->nsubticks!=0)  dsubticks = (dticks)/(ax->nsubticks+1);
	if (ax->dsubticks!=0)  dsubticks = ax->dsubticks;
	if (dsubticks==0) dsubticks = dticks / 2.0;
	if ((gmax - gmin)/dsubticks>2000) {gprint("too many subticks \n");
						dsubticks = dticks;}

	start_subtick(&tick1, gmin, dsubticks);
	g_set_color(ax->subticks_color);
	g_set_line_width(ax->subticks_lwidth);
	g_set_line_style(ax->subticks_lstyle);
	if (ax->type>2) t = -stlen; else t = stlen;
	if (!ax->subticks_off) {
	  if (dsubticks==0) dsubticks = dticks / 2.0;
	  for (fi=tick1; fi<=gmax; fi += dsubticks) {
/* 	    if (!fnbig(fi)) { */
		if (xax) {
			g_move(ox+fnx(fi),oy);
			g_line(ox+fnx(fi),oy+t);
		} else {
			g_move(ox,fnx(fi)+oy);
			g_line(ox+t,oy+fnx(fi));
		}
/*	    } 	*/
	  }
	}
	}

/*------------------------------  Now the main ticks */
	g_set_color(ax->ticks_color);
	g_set_line_width(ax->ticks_lwidth);
	g_set_line_style(ax->ticks_lstyle);

	if (ax->type>2) t = -tlen; else t = tlen;
	if (ax->type>2) tt = -stlen; else tt = stlen;
	if (!ax->ticks_off) {
	  if (ax->log) {	/* Draw log ticks */
	    g_set_color(ax->subticks_color);
	    g_set_line_width(ax->subticks_lwidth);
	    g_set_line_style(ax->subticks_lstyle);
	    nice_log_ticks(&tick1,&tickn,&gmin,&gmax);
	    for (fi=tick1; fi<= tickn+(pow(10.0,floor(log10(fi)+.0001)))/100
			; fi += pow(10.0,floor(log10(fi)+.0001))) {
		i = floor(fi/pow(10.0,floor(log10(fi))));
		isbig = (fnbig(fi));
		if (isbig) {
			x = t;
		    	g_set_color(ax->ticks_color);
		    	g_set_line_width(ax->ticks_lwidth);
		    	g_set_line_style(ax->ticks_lstyle);
		} else x = tt;
		if (xax) {
			g_move(ox+fnlx(fi),oy);
			g_line(ox+fnlx(fi),oy+x);
		} else {
			g_move(ox,fnlx(fi)+oy);
			g_line(ox+x,oy+fnlx(fi));
		}
		if (isbig) {
		    	g_set_color(ax->subticks_color);
		    	g_set_line_width(ax->subticks_lwidth);
		    	g_set_line_style(ax->subticks_lstyle);
		}
	    }
	  } else {
	    for (i=1;i<=ax->nplaces; i++) {
		fi = ax->places[i];
		if (xax) {
			g_move(ox+fnx(fi),oy);
			g_line(ox+fnx(fi),oy+t);
		} else {
			g_move(ox,fnx(fi)+oy);
			g_line(ox+t,oy+fnx(fi));
		}
	    }
	  }
	}
	g_grestore();
/*------------------------------  Now draw the labels 	*/
	llen = 0;
	if (tlen<0) llen = -tlen;
	h = ax->label_hei;
	if (h==0) h = ax->base;
	llen = llen + h*.5;
	if (ax->label_dist!=0) llen = ax->label_dist;

	{char cbuff[100];
	if (ax->nnam==0) {
	  if (ax->log) {
	    if (log10(gmax)-log10(gmin) < 5) dolittle = true;
	    else dolittle = false;
	    for (i=1;i<=ax->nplaces; i++) {
		fi = ax->places[i];
		n = floor(.0001 + fi/pow(10.0,floor(log10(fi))));
		if (fnbig(fi)) {
			n = floor(log10(fi)+.5);
			sprintf(cbuff,"10\\sup {%d}",n);
			mystrcpy(&ax->names[i],cbuff);
		} else {
		  if (dolittle) {
			n = floor(.0001 + fi/(pow(10.0,floor(log10(fi)))));
			sprintf(cbuff,"{\\sethei{%g}%d}",h*.7,n);
			mystrcpy(&ax->names[i],cbuff);
		  }
		}
	    }
	    ax->nnam = ax->nplaces;
	  } else {
	    for (i=1;i<=ax->nplaces; i++) {
		fi = ax->places[i];
		x = fabs(fi);
		if (x<.00001*dticks) {fi = 0; x = 0;}
		if (ax->decimal>0) {
			sprintf(cbuff,"%.*f",ax->decimal,fi);
			ax->names[i] = myallocz(20);
			strncpy(ax->names[i],cbuff,19);
		} else {
			if (fi==0 || (x>1e-5 && x<1e6)) sprintf(cbuff,"%f",fi);
			else sprintf(cbuff,"%e",fi);
			numtrim(&ax->names[i],cbuff,dticks);
		}
	    }
	    ax->nnam = ax->nplaces;
	  }
	}}
	g_set_color(ax->label_color);
	g_set_line_width(ax->label_lwidth);
	g_set_line_style(ax->label_lstyle);
	g_set_font(ax->label_font);
	g_set_hei(h);
	maxd = 0;
	maxwid = 0;
	tx = ox-.3*h;   /* I wonder what tx should be set to ??? */
 	if (ax->type==4) tx = ox + .3*h;
	if (ax->type==1) ty = oy-llen-.3*h;
	if (ax->type==3) ty = oy+llen;
	if (!ax->label_off) {
	  for (i=1;i<=ax->nnam;i++) {
		g_measure(ax->names[i],&bl,&br,&bu,&bd);
		if (bd>maxd) maxd = bd;
		if (bl+br>maxwid) maxwid = bl+br;
	  }
	  for (i=1;i<=ax->nnam;i++) {
		g_measure(ax->names[i], &bl, &br,&bu,&bd);
		fi = fnx(ax->places[i]);
		if (ax->log) fi = fnlx(ax->places[i]);
		switch (ax->type) {
		  case 1: /* xaxis */
			y = oy-llen-bu+bd-.3*h;
			if (y<ty) ty = y;
			g_move(ox+fi+ax->shift,oy-llen-(.7*h) );
			g_jtext(JUST_CENTRE);
			break;
		  case 2: /* yaxis */
			x = ox-br+bl-llen-.3*h;
/* bug here with axis labels 0 10 20, nofirst  */
			if (i!=1 && i!=ax->nnam) if (x<tx) tx = x;
			g_move(ox -llen ,oy+fi+ax->shift);
			g_jtext(JUST_RC);
			break;
		  case 3: /* x2axis */
			y = oy+llen+maxd+bu;
			if (y>ty) ty = y;
			g_move(ox+fi+ax->shift,oy+llen+maxd);
			g_jtext(JUST_CENTRE);
			break;
		  case 4: /* y2axis */
			x = ox+br-bl+llen+.3*h;
			if (i!=1 && i!=ax->nnam) if (x>tx) tx = x;
			g_move(ox+llen ,oy + fi +ax->shift);
			g_jtext(JUST_LC);
			break;
		}
		if (bd>maxd) maxd = bd;
		if (bl+br>maxwid) maxwid = bl+br;
	  }
	}
/*---------------------------------- Now the axis title. */

	if (ax->title==NULL) return;
	g_gsave();
	th = h * 1.3;
	if (ax->title_scale!=0) th = th*ax->title_scale ;
	if (ax->title_hei!=0) th = ax->title_hei ;
	g_set_color(ax->title_color);
	g_set_font(ax->title_font);
	g_set_hei(th);
	g_measure(ax->title,&bl,&br,&bu,&bd);
	if (!ax->title_off) {
	  switch (ax->type) {
	    case 1: /*  xaxis   */
		g_move(ox+ax->length/2,ty - ax->title_dist);
		g_jtext(JUST_TC);
		break;
	    case 2: /*  yaxis   */
		g_move(tx - ax->title_dist,oy + ax->length/2);
		g_rotate(90.0);
		g_jtext(JUST_BC);
		g_rotate(-90.0);
		break;
	    case 3: /*  x2axis   */
		g_move(ox+ax->length/2,ty + ax->title_dist);
		g_jtext(JUST_BC);
		break;
	    case 4: /*  y2axis   */
		g_move(tx + ax->title_dist,oy + ax->length/2);
		if (ax->title_rot) {
			g_rotate(-90.0);
			g_jtext(JUST_BC);
			g_rotate(90.0);
		} else {
			g_rotate(90.0);
			g_jtext(JUST_TC);
			g_rotate(-90.0);
		}
		break;
	  }
	}
	g_grestore();
	g_move(ox,oy);
	g_source("END AXIS  ===== \n");
}
/*-------------------------------------------------------------------------*/
nice_ticks(double *dticks, double *gmin,double *gmax
	, double *t1,double *tn,int minset, int maxset)
{
	double delta,st,expnt,n;
	int ni;

/*  	GMIN AND GMAX are set in GRAPH2.C in setrange() 	*/
	delta = *gmax-*gmin;
	if (delta==0) {gprint("Axis range error min=%g max=%g \n",*gmin,*gmax);
		*gmax = *gmin+10;
		delta = 10;
	}
	st = delta/10;
	expnt = floor(log10(st));
	n = st/pow(10.0,expnt);
	if (n>5)
		ni = 10;
	else if (n>2)
		ni = 5;
	else if (n>1)
		ni = 2;
	else
		ni = 1;
	if (*dticks==0) *dticks = ni * pow(10.0,expnt);
	if (*gmin - (delta/1000) <=  floor( *gmin/ *dticks) * *dticks)
		*t1 = *gmin;
	else
		*t1 = (floor(*gmin/ *dticks) * *dticks ) + *dticks;

	*tn = *gmax;
/*	gprint("tn %g,(%g) %g < %g \n",*tn,*gmax / *dticks,( floor( *gmax/ *dticks) * *dticks)
			,(*gmax - (delta/1000)) );

*/
	if (  (floor(.000001+ *gmax / *dticks) * *dticks) <
	  (*gmax - (delta/1000) ) )
		*tn = floor(.00001 + *gmax/ *dticks ) * *dticks;
/*
	gprint("tn is now %g \n",*tn);
    This is commented out because setting the range is different
    from setting the labelling,  e.g. xaxis min 1 max 10.2 should not
    label 10.2

	if (maxset) *tn = *gmax;
	if (minset) *t1 = *gmin;
    */

}
/*-------------------------------------------------------------------------*/
double chop(double f);
double chop(double f)
{
	return (double) (int32) f;
}
/*-------------------------------------------------------------------------*/
start_subtick(double *tick1, double gmin, double dticks)
{
	if (gmin == chop(gmin/dticks) * dticks)
		*tick1 = gmin;
	else
		*tick1 = chop(gmin/dticks) * dticks + dticks;
}
/*-------------------------------------------------------------------------*/
numtrime(char *o,char *s)
{
	char *nonzero;
	char *e,*f;

	strcpy(o,s);

	e = strchr(s,'e');
	if (e==NULL) return;

	e--;
	for (; *e=='0'; e--) ;

	f = strchr(s,'e');
	strcpy(e+1,f);
	strcpy(o,s);

}
/*-------------------------------------------------------------------------*/
numtrim(char **d,char *s,double dticks)
{
	char *o,*nonzero=0;

	if (*d==0)  *d = myallocz(20);
	o = *d;
	nonzero = 0;
	if (strchr(s,'e')!=NULL) {
		numtrime(o,s);
		return;
	}
	while (*s==' ' && *s!=0) s++;
	while (*s!=0) {
		*(o++) = *(s++);
		if (*s=='.') {
			nonzero = o-1;
			if (dticks!=floor(dticks)) nonzero = o+1;
			while (*s!=0) {
				*(o++) = *(s++);
				if ((*s!='0') && (*s!=0))
					if (o>nonzero) nonzero = o;
			}
		}
	}
	*(o++) = 0;
	if (nonzero!=NULL) *(nonzero+1) = 0;
}
/*-------------------------------------------------------------------------*/
nice_log_ticks(double *start, double *last, double *gmin, double *gmax)
{
	double sz;

	if (*gmin<=0) {
		gprint("FATAL ERROR, LOG AXIS WITH MIN OF ZERO***\n");
		*gmin = 1;
	}
	if (*gmax<=0) *gmax = 10;
	*start = pow(10.0,floor(log10(*gmin)));

	if (floor(log10(*gmin)) != log10(*gmin)) {
		sz = pow(10.0,floor(log10(*gmin)));
		*start = floor((*gmin)/sz)*sz + sz;
		if (*start>(*gmin+sz-sz/100)) *start = *start - sz;
	}
	*last = floor(log10(*gmax))+1;
	if (floor(log10(*gmax))==log10(*gmax)) {
		--*last;
		*last = pow(10.0,*last);
	} else {
		*last = pow(10.0,*last-1);
		*last = floor((*gmax) / *last) * *last;
	}
}
double fnloglen(double v,struct axis_struct *ax)  /* Dist in cm in log axis */
{
	if (ax->negate) {
		v = ax->max - (v- ax->min);
	}
   return ((v-log10(ax->min))/(log10(ax->max)-log10(ax->min))) * ax->length;
}
double fnlogx(double v,struct axis_struct *ax)
{
	if (ax->negate) {
		v = ax->max - (v- ax->min);
	}
	return fnloglen(log10(v),ax);
}
fnbig(double v)
{
	if (fabs(log10(v)-floor(log10(v)+.5)) < .001)
		return true;
	else return false;
}



