var SHAPE_POINT=1;
var SHAPE_LINE=2;
var SHAPE_RECT=3;
var SHAPE_POLYLINE=4;
var SHAPE_POLYGON=5;
var SHAPE_ELLIPSE=6;
var SHAPE_ARC=7;
var SHAPE_LABEL=8;
var SHAPE_IMAGE=9;
var SHAPE_CURVE=10;

var ARC_OPEN=0;
var ARC_CHORD=1;
var ARC_PIE=2;
var ARC_STEP=5;
var NO_LINE=-2;

var COLOR_RED='#FF0000';
var COLOR_GREEN='#00FF00';
var COLOR_BLUE='#3399FF';
var COLOR_YELLOW='#FFFF00';
var COLOR_PINK='#FAAFBA';
var COLOR_ORANGE='#FF8000';
var COLOR_CYAN='#339966';
var COLOR_LIGHTCYAN='#CFECEC';
var COLOR_MAGENTA='#990000';
var COLOR_LIGHTGRAY='#CCCCCC';
var COLOR_GRAY='#888888';
var COLOR_DARKGRAY='#333333';
var COLOR_WHITE='#FFFFFF';
var COLOR_BLACK='#000000';
var COLOR_MARKS=[COLOR_BLUE,COLOR_PINK,COLOR_GREEN,COLOR_YELLOW,COLOR_RED,COLOR_CYAN,COLOR_WHITE,COLOR_MAGENTA];
var COLOR_HS=[COLOR_BLUE,COLOR_GREEN,COLOR_RED,COLOR_CYAN,COLOR_MAGENTA,COLOR_BLACK];
var COLOR_LS=[COLOR_PINK,COLOR_YELLOW,COLOR_LIGHTCYAN,COLOR_WHITE,COLOR_LIGHTGRAY];
var COLOR_NS=[COLOR_WHITE,COLOR_ORANGE,COLOR_BLUE];

function getNColor(idx) {
	return COLOR_NS[idx%COLOR_NS.length];
}

function getLColor(idx) {
	return COLOR_LS[idx%COLOR_LS.length];
}

function getHColor(idx) {
	return COLOR_HS[idx%COLOR_HS.length];
}

function getMColor(idx) {
	return COLOR_MARKS[idx%COLOR_MARKS.length];
}

function jsGData(ishape, data, lineColor, fillColor, strokeWidth)
{
	this.shape=ishape;
	this.lineColor=lineColor;
	this.fillColor=fillColor;
	this.strokeWidth=strokeWidth;
	this.data=data;
}

function jsGraphicsNorm(iDiv,xmin,xmax,ymin,ymax,tmargin,bmargin,lmargin,rmargin)
{
	this.name=iDiv;
	this.g = new jsGraphics(iDiv);
	this.g.setPrintable(true);
	this.jsgData=new Array();
	this.lColor="#000000";
	this.fColor="#000000";
	this.stroke=1;
	this.x1=0;
	this.x2=0;
	this.y1=0;
	this.y2=0;
	this.xmin=0;
	this.xmax=200;
	this.ymin=0;
	this.ymax=200;
	this.xmarg1=0;
	this.xmarg2=0;
	this.ymarg1=0;
	this.ymarg2=0;
	if (xmin) this.xmin=xmin;
	if (xmax) this.xmax=xmax;
	if (ymin) this.ymin=ymin;
	if (ymax) this.ymax=ymax;
	if (lmargin) this.xmarg1=lmargin;
	if (rmargin) this.xmarg2=rmargin;
	if (bmargin) this.ymarg1=bmargin;
	if (tmargin) this.ymarg2=tmargin;
	this.xratio=1;
	this.yratio=1;

	this.setMargin = function(mleft,mright,mbottom,mtop)
	{
		this.xmarg1=mleft;
		this.xmarg2=mright;
		this.ymarg1=mbottom;
		this.ymarg2=mtop;
	};

	this.setMaximum = function(xmin,xmax,ymin,ymax)
	{
		this.xmin=xmin;
		this.xmax=xmax;
		this.ymin=ymin;
		this.ymax=ymax;
	};

	this.initialize=function(){
		//alert("("+this.xmin+","+this.xmax+","+this.ymin+","+this.ymax+"), ("+this.xmarg1+","+this.xmarg2+","+this.ymarg1+","+this.ymarg2+")");
		var elem=document.getElementById(this.name);
		var sxlen=elem.style.width;
		var ipx=sxlen.indexOf('px');
		var xlen=200;
		if (ipx>0)
		{
			xlen = parseInt(sxlen.substring(0,ipx));
		}
		var sylen=elem.style.height;
		var ipx=sylen.indexOf('px');
		var ylen=200;
		if (ipx>0)
		{
			ylen = parseInt(sylen.substring(0,ipx));
		}
		this.x1=this.xmarg1;
		this.x2=xlen-this.xmarg2;
		this.y1=this.ymarg2;
		this.y2=ylen-this.ymarg1;
		this.xratio=(this.x2-this.x1)/(this.xmax-this.xmin);
		this.yratio=Math.abs((this.y2-this.y1)/(this.ymax-this.ymin));
		if (this.xratio>this.yratio)
		{
			// adjust x1 and x2
			var nlen = (this.x2-this.x1)*(1-this.yratio/this.xratio)/2.0;
			this.xratio=this.yratio;
			this.x2 -= nlen;
			this.x1 += nlen;
		}
		else if (this.xratio<this.yratio)
		{
			var nlen = (this.y2-this.y1)*(1-this.xratio/this.yratio)/2.0;
			this.yratio=this.xratio;
			this.y2 -= nlen;
			this.y1 += nlen;
		}
	};

	this.setSize = function(w,h)
	{
		var elem=document.getElementById(this.name);
		elem.style.width=w+'px';
		elem.style.height=h+'px';
	};

	this.transformX = function(x)
	{
		return ((x-this.xmin)/(this.xmax-this.xmin))*(this.x2-this.x1)+this.x1;
	};

	this.transformXs = function(xs)
	{
		var vs = new Array(xs.length);
		for (var i=0;i<xs.length;i++)
		{
			vs[i]=this.transformX(xs[i]);
		}
		return vs;
	};

	this.transformY = function(y)
	{
		return this.y2-((y-this.ymin)/(this.ymax-this.ymin))*(this.y2-this.y1);
	};

	this.transformYs = function(ys)
	{
		var vs = new Array(ys.length);
		for (var i=0;i<ys.length;i++)
		{
			vs[i]=this.transformY(ys[i]);
		}
		return vs;
	};

	this.setLineColor = function(x)
	{
		this.lcolor=x;
	};

	this.setFillColor = function(x)
	{
		this.fcolor=x;
	};

	this.setStroke2 = function(x)
	{
		this.stroke=x;
	};

	this.setPrintable2 = function(arg)
	{
		this.g.setPrintable(arg);
	};

	this.setStrokeAndColor = function(strokeWidth, lineColor)
	{
		if (lineColor)
		{
			this.g.setColor(lineColor);
		}
		else
		{
			this.g.setColor(this.lColor);
		}
		if (strokeWidth)
		{
			this.g.setStroke(strokeWidth);
		}
		else
		{
			this.g.setStroke(this.stroke);
		}
	};

	this.drawGraph =function(x,y,degree)
	{
		this.initialize();
		var bturn=false;
		if (degree)
		{
			bturn=true;
		}
		for (var i=0;i<this.jsgData.length;i++)
		{
			var d=this.jsgData[i];

			if (d.shape==SHAPE_POINT)
			{
				this.setStrokeAndColor(d.strokeWidth, d.lineColor);
				if (d.data[3]==SHAPE_RECT)
				{
					if (bturn)
					{
						var d2=this.turnRect(x,y,d.data[0],d.data[1],d.data[2],d.data[2],d.strokeWidth,d.lineColor,d.fillColor,degree);
						this.g.fillPolygon(this.transformXs(d2.data[0]), this.transformYs(d2.data[1]));
					}
					else
					{
						this.g.fillRect(this.transformX(d.data[0]-d.data[2]/2), this.transformY(d.data[1]+d.data[2]/2),d.data[2]*this.xratio,d.data[2]*this.yratio);
					}
				}
				else
				{
					if (bturn)
					{
						var d2=this.turnEllipse(x,y,d.data[0],d.data[1],d.data[2],d.data[2],d.strokeWidth,d.lineColor,d.fillColor,degree);
						this.g.fillPolygon(this.transformXs(d2.data[0]), this.transformYs(d2.data[1]));
					}
					else
					{
						this.g.fillEllipse(this.transformX(d.data[0]-d.data[2]/2), this.transformY(d.data[1]+d.data[2]/2),d.data[2]*this.xratio,d.data[2]*this.yratio);
					}
				}
			}
			else if (d.shape==SHAPE_RECT)
			{
				if (bturn)
				{
					d=this.turnRect(x,y,d.data[0],d.data[1],d.data[2],d.data[3],d.strokeWidth,d.lineColor,d.fillColor,degree);
					if (d.fillColor)
					{
						this.g.setColor(d.fillColor);
						this.g.fillPolygon(this.transformXs(d.data[0]), this.transformYs(d.data[1]));
					}
					if (NO_LINE!=d.strokeWidth) {
						this.setStrokeAndColor(d.strokeWidth, d.lineColor);
						this.g.drawPolygon(this.transformXs(d.data[0]), this.transformYs(d.data[1]));
					}
				}
				else
				{
					if (d.fillColor)
					{
						this.g.setColor(d.fillColor);
						this.g.fillRect(this.transformX(d.data[0]-d.data[2]/2), this.transformY(d.data[1]+d.data[3]/2),d.data[2]*this.xratio,d.data[3]*this.yratio);
					}
					if (NO_LINE!=d.strokeWidth) {
						this.setStrokeAndColor(d.strokeWidth, d.lineColor);
						this.g.drawRect(this.transformX(d.data[0]-d.data[2]/2), this.transformY(d.data[1]+d.data[3]/2),d.data[2]*this.xratio,d.data[3]*this.yratio);
					}
				}
			}
			else if (d.shape==SHAPE_LINE)
			{
				this.setStrokeAndColor(d.strokeWidth, d.lineColor);
				if (bturn)
				{
					var xs=new Array(d.data[0],d.data[2]);
					var ys=new Array(d.data[1],d.data[3]);
					turnDegree(x,y,xs,ys,degree);
					this.g.drawLine(this.transformX(xs[0]), this.transformY(ys[0]),this.transformX(xs[1]), this.transformY(ys[1]));
				}
				else
				{
					this.g.drawLine(this.transformX(d.data[0]), this.transformY(d.data[1]),this.transformX(d.data[2]), this.transformY(d.data[3]));
				}
			}
			else if (d.shape==SHAPE_CURVE) {
				var v1=d.data[0];
				var v2=d.data[1];
				var fxy=d.data[2];
				var points=d.data[3];
				var vopen= d.data[4];
				var vstep=(v2-v1)/points;
				var v1s=new Array();
				var v2s=new Array();
				for (var v=v1;v<=v2;v+=vstep)
				{
					var sf=fxy; 
					var vf;
					if (d.data[5]!='x') {
						vf=eval(sf.replace(/y/g,v));
					} else {
						vf=eval(sf.replace(/x/g,v));
					}
					v1s[v1s.length]=v;
					v2s[v2s.length]=vf;
				}
				if (!vopen || vopen==ARC_OPEN) {
					this.setStrokeAndColor(d.strokeWidth, d.lineColor);
					if (d.data[5]!='x') {
						this.g.drawPolyline(this.transformXs(v2s), this.transformYs(v1s));
					} else {
						this.g.drawPolyline(this.transformXs(v1s), this.transformYs(v2s));
					}
				}else{
					v1s[v1s.length]=v2;
					if (d.data[6]) {
						v2s[v2s.length]=d.data[6];
					} else {
						v2s[v2s.length]=0;
					}
					v1s[v1s.length]=v1;
					if (d.data[6]) {
						v2s[v2s.length]=d.data[6];
					} else {
						v2s[v2s.length]=0;
					}
					if (d.fillColor)
					{
						this.g.setColor(d.fillColor);
						if (d.data[5]!='x'){
							this.g.fillPolygon(this.transformXs(v2s), this.transformYs(v1s));
						} else {
							this.g.fillPolygon(this.transformXs(v1s), this.transformYs(v2s));
						}
					}
					this.setStrokeAndColor(d.strokeWidth, d.lineColor);
					if (d.data[5]!='x'){
						this.g.drawPolygon(this.transformXs(v2s), this.transformYs(v1s));
					} else {
						this.g.drawPolygon(this.transformXs(v1s), this.transformYs(v2s));
					}
				}
			}
			else if (d.shape==SHAPE_POLYLINE)
			{
				var xs=d.data[0];
				var ys=d.data[1];
				if (bturn)
				{
					turnDegree(x,y,xs,ys,degree);
				}
				this.setStrokeAndColor(d.strokeWidth, d.lineColor);
				this.g.drawPolyline(this.transformXs(xs), this.transformYs(ys));
			}
			else if (d.shape==SHAPE_POLYGON)
			{
				var xs=d.data[0];
				var ys=d.data[1];
				if (bturn)
				{
					turnDegree(x,y,xs,ys,degree);
				}
				if (d.fillColor)
				{
					this.g.setColor(d.fillColor);
					this.g.fillPolygon(this.transformXs(xs), this.transformYs(ys));
				}
				if (NO_LINE!=d.strokeWidth) {
					this.setStrokeAndColor(d.strokeWidth, d.lineColor);
					this.g.drawPolygon(this.transformXs(xs), this.transformYs(ys));
				}
			}
			else if (d.shape==SHAPE_ELLIPSE)
			{
				if (bturn)
				{
					d=this.turnEllipse(x,y,d.data[0],d.data[1],d.data[2],d.data[3],d.strokeWidth,d.lineColor,d.fillColor,degree);
					if (d.fillColor)
					{
						this.g.setColor(d.fillColor);
						this.g.fillPolygon(this.transformXs(d.data[0]), this.transformYs(d.data[1]));
					}
					if (NO_LINE!=d.strokeWidth) {
						this.setStrokeAndColor(d.strokeWidth, d.lineColor);
						this.g.drawPolygon(this.transformXs(d.data[0]), this.transformYs(d.data[1]));
					}
				}
				else
				{
					if (d.fillColor)
					{
						this.g.setColor(d.fillColor);
						this.g.fillEllipse(this.transformX(d.data[0]-d.data[2]/2), this.transformY(d.data[1]+d.data[3]/2),d.data[2]*this.xratio,d.data[3]*this.yratio);
					}
					if (NO_LINE!=d.strokeWidth) {
						this.setStrokeAndColor(d.strokeWidth, d.lineColor);
						this.g.drawEllipse(this.transformX(d.data[0]-d.data[2]/2), this.transformY(d.data[1]+d.data[3]/2),d.data[2]*this.xratio,d.data[3]*this.yratio);
					}
				}
			}
			else if (d.shape==SHAPE_ARC)
			{
				// calc the xs and ys
				var a=d.data[2]/2; 
				var b=d.data[3]/2; 
				var last=d.data[5]; 
				var type=d.data[6];
				var xs=new Array();
				var ys=new Array();
				var ang = 0;
				for (var j=0; ang<last;j++)
				{
					ang = d.data[4]+j*ARC_STEP;
					if (ang>last)
					{
						ang=last;
					}
					xs[j]=d.data[0]+calcEllipseX(a,b,ang);
					ys[j]=d.data[1]+calcEllipseY(a,b,ang);
				}
				if (type==ARC_CHORD||type==ARC_PIE)
				{
					if (type==ARC_CHORD)
					{
						if (bturn)
						{
							turnDegree(x,y,xs,ys,degree);
						}
						if (d.fillColor)
						{
							this.g.setColor(d.fillColor);
							this.g.fillPolygon(this.transformXs(xs), this.transformYs(ys));
						}
					}
					else if (type && type==ARC_PIE)
					{
						xs[xs.length]=d.data[0];
						ys[ys.length]=d.data[1];
						if (d.fillColor)
						{
							this.g.setColor(d.fillColor);
							if (bturn)
							{
								turnDegree(x,y,xs,ys,degree);
								this.g.fillPolygon(this.transformXs(xs), this.transformYs(ys));
							}
							else
							{
								this.g.fillArc(this.transformX(d.data[0]-d.data[2]/2), this.transformY(d.data[1]+d.data[3]/2),d.data[2]*this.xratio,d.data[3]*this.yratio,d.data[4],d.data[5]);
							}
						}
					}
					else
					{
						if (bturn)
						{
							turnDegree(x,y,xs,ys,degree);
						}
					}
				}
				this.setStrokeAndColor(d.strokeWidth, d.lineColor);
				if (type==ARC_CHORD||type==ARC_PIE)
				{
					this.g.drawPolygon(this.transformXs(xs), this.transformYs(ys));
				}
				else
				{
					this.g.drawPolyline(this.transformXs(xs), this.transformYs(ys));
				}
			}
			else if (d.shape==SHAPE_LABEL)
			{
				this.setStrokeAndColor(d.strokeWidth, d.lineColor);
				if (bturn)
				{
					var xs=new Array();
					xs[0]=d.data[1];
					var ys=new Array();
					ys[0]=d.data[2];
					turnDegree(x,y,xs,ys,degree);
					d.data[1]=xs[0];
					d.data[2]=ys[0];
				}
				// two styles
				var nlen=d.data.length;
				if (nlen>=5)
				{
					this.g.drawStringRect(d.data[0], this.transformX(d.data[1]), this.transformY(d.data[2]), d.data[3]*this.xratio, d.data[4]);
				}
				else if (nlen>=3)
				{
					this.g.drawString(d.data[0], this.transformX(d.data[1]), this.transformY(d.data[2]));
				}
			}
			else if (d.shape==SHAPE_IMAGE)
			{
				this.setStrokeAndColor(d.strokeWidth, d.lineColor);
				var xs=new Array();
				var ys=new Array();
				xs[0]=d.data[1]-d.data[3]/2;
				ys[0]=d.data[2]+d.data[4]/2;
				if (bturn)
				{
					turnDegree(x,y,xs,ys,degree);
				}
				this.g.drawImage(d.data[0],this.transformX(xs[0]), this.transformY(ys[0]),d.data[3]*this.xratio,d.data[4]*this.yratio,d.data[5]);
			}
		}
		this.g.paint();
	};

	this.clear2 = function()
	{
		this.g.clear()
	};

	this.addPoint = function(x,y,type,size,fcolor)
	{
		this.jsgData[this.jsgData.length] = new jsGData(SHAPE_POINT, new Array(x,y,size,type), fcolor);
	};

	this.addLabel = function(x,y,text,width,align)
	{
		if (width && align)
		{
			this.jsgData[this.jsgData.length] = new jsGData(SHAPE_LABEL, new Array(text,x,y,width,align));
		}
		else
		{
			this.jsgData[this.jsgData.length] = new jsGData(SHAPE_LABEL, new Array(text,x,y));
		}
	};
	this.addLine = function(x1,y1,x2,y2,stroke,lcolor)
	{
		this.jsgData[this.jsgData.length] = new jsGData(SHAPE_LINE, new Array(x1,y1,x2,y2),lcolor,null,stroke);
	};

	this.turnRect = function(x0,y0,x,y,w,h,stroke,lcolor,fcolor,degree)
	{
		var xs=new Array(4);
		var ys=new Array(4);
		var a=w/2;
		var b=h/2;
		for (var i=0;i<2;i++)
		{
			for (var j=0;j<2;j++)
			{
				var idx=i*2+j;
				xs[idx]=x+a*Math.pow(-1,i-j);
				ys[idx]=y+b*Math.pow(-1,i);
			}
		}
		turnDegree(x0,y0,xs,ys,degree);
		return  new jsGData(SHAPE_POLYGON, new Array(xs,ys),lcolor,fcolor,stroke);
	};

	this.addRect = function(x,y,w,h,stroke,lcolor,fcolor,degree)
	{
		if (degree && degree%90 != 0)
		{
			this.jsgData[this.jsgData.length] = this.turnRect(x,y,x,y,w,h,stroke,lcolor,fcolor,degree);
		}
		else if (degree&& degree%180==90)
		{
			this.jsgData[this.jsgData.length] = new jsGData(SHAPE_RECT, new Array(x,y,h,w),lcolor,fcolor,stroke);
		}
		else
		{
			this.jsgData[this.jsgData.length] = new jsGData(SHAPE_RECT, new Array(x,y,w,h),lcolor,fcolor,stroke);
		}
	};

	this.turnEllipse = function(x0,y0,x,y,w,h,stroke,lcolor,fcolor,degree)
	{
		var xs=new Array();
		var ys=new Array();
		var a=w/2;
		var b=h/2;
		var deg=0;
		for (var i=0;deg<360;i++)
		{
			xs[i]=x+calcEllipseX(a,b,deg);
			ys[i]=y+calcEllipseY(a,b,deg);
			deg=(i+1)*ARC_STEP;
		}
		turnDegree(x0,y0,xs,ys,degree);
		return new jsGData(SHAPE_POLYGON, new Array(xs,ys),lcolor,fcolor,stroke);
	};

	this.addEllipse = function(x,y,w,h,stroke,lcolor,fcolor,degree)
	{
		if (degree && degree%90 != 0)
		{
			this.jsgData[this.jsgData.length] = this.turnEllipse(x,y,x,y,w,h,stroke,lcolor,fcolor,degree);
		}
		else if (degree&& degree%180==90)
		{
			this.jsgData[this.jsgData.length] = new jsGData(SHAPE_ELLIPSE, new Array(x,y,h,w),lcolor,fcolor,stroke);
		}
		else
		{
			this.jsgData[this.jsgData.length] = new jsGData(SHAPE_ELLIPSE, new Array(x,y,w,h),lcolor,fcolor,stroke);
		}
	};

	this.addCurveXY = function(x1,x2,fs,points,flag,stroke,lcolor,fcolor,ylevel)
	{
		this.jsgData[this.jsgData.length] = new jsGData(SHAPE_CURVE, new Array(x1,x2,fs,points,flag,'x',ylevel),lcolor,fcolor,stroke);
	}
	this.addCurveYX = function(y1,y2,fs,points,flag,stroke,lcolor,fcolor,xlevel)
	{
		this.jsgData[this.jsgData.length] = new jsGData(SHAPE_CURVE, new Array(y1,y2,fs,points,flag,'y',xlevel),lcolor,fcolor,stroke);
	}
	this.addPolyline = function(xs,ys,stroke,lcolor,degree,x0,y0,xc,yc)
	{
		if (degree)
		{
			var x=0;
			var y=0;
			if (x0 != null) {
				x += x0;
				for (var i=0;i<xs.length;i++)
				{
					xs[i] += x0;
				}
			}
			if (y0 != null) {
				y += y0;
				for (var i=0;i<ys.length;i++)
				{
					ys[i]+=y0;
				}
			}
			if (xc != null) {
				x+=xc;
			} else {
				x=0;
				for (var i=0;i<xs.length;i++)
				{
					x+=xs[i];
				}
				x=x/xs.length;
			}
			if (yc != null) {
				y+=yc;
			} else {
				y=0;
				for (var i=0;i<ys.length;i++)
				{
					y+=ys[i];
				}
				y=y/ys.length;
			}
			turnDegree(x,y,xs,ys,degree);
		} else {
			if (x0 != null) {
				for (var i=0;i<xs.length;i++)
				{
					xs[i] += x0;
				}
			}
			if (y0 != null) {
				for (var i=0;i<ys.length;i++)
				{
					ys[i]+=y0;
				}
			}
		}
		this.jsgData[this.jsgData.length] = new jsGData(SHAPE_POLYLINE, new Array(xs,ys),lcolor,null,stroke);
	};

	this.addPolygon = function(xs,ys,stroke,lcolor,fcolor,degree,x0,y0,xc,yc)
	{
		if (degree)
		{
			var x=0;
			var y=0;
			if (x0 != null) {
				x += x0;
				for (var i=0;i<xs.length;i++)
				{
					xs[i] += x0;
				}
			}
			if (y0 != null) {
				y += y0;
				for (var i=0;i<ys.length;i++)
				{
					ys[i]+=y0;
				}
			}
			if (xc != null) {
				x+=xc;
			} else {
				x=0;
				for (var i=0;i<xs.length;i++)
				{
					x+=xs[i];
				}
				x=x/xs.length;
			}
			if (yc != null) {
				y+=yc;
			} else {
				y=0;
				for (var i=0;i<ys.length;i++)
				{
					y+=ys[i];
				}
				y=y/ys.length;
			}
			turnDegree(x,y,xs,ys,degree);
		} else {
			if (x0 != null) {
				for (var i=0;i<xs.length;i++)
				{
					xs[i] += x0;
				}
			}
			if (y0 != null) {
				for (var i=0;i<ys.length;i++)
				{
					ys[i]+=y0;
				}
			}
		}
		this.jsgData[this.jsgData.length] = new jsGData(SHAPE_POLYGON, new Array(xs,ys),lcolor,fcolor,stroke);
	};

	this.addArc = function(x,y,r,ang1,ang2,type,stroke,lcolor,fcolor)
	{
		this.jsgData[this.jsgData.length] = new jsGData(SHAPE_ARC, new Array(x,y,r,r,ang1,ang2,type),lcolor,fcolor,stroke);
	};
	this.addRegularPolygon = function(x,y,size,sides,stroke,lcolor,fcolor,degree)
	{
		// calc xs and ys
		var xs=new Array(sides);
		var ys=new Array(sides);
		var ang=2*Math.PI/sides;
		var ang0=Math.PI*3/2-ang/2;
		if (degree)
		{
			ang0+=degree*Math.PI/180;
		}
		for (var i=0;i<sides;i++)
		{
			xs[i]=x+size*Math.cos(ang0+i*ang);
			ys[i]=y+size*Math.sin(ang0+i*ang);
		}
		this.jsgData[this.jsgData.length] = new jsGData(SHAPE_POLYGON, new Array(xs,ys),lcolor,fcolor,stroke);
	};
}

function turnDegree(x,y,xs,ys,degree)
{
	if (!degree) return;
	for (var i=0;i<xs.length;i++)
	{
		var dx=xs[i]-x;
		var dy=ys[i]-y;
		var ang=Math.atan2(dy,dx);
		if (ang<0)
		{
			ang+=2*Math.PI;
		}
		ang+=degree*Math.PI/180;
		var len=Math.sqrt(dx*dx+dy*dy);
		xs[i]=x+len*Math.cos(ang);
		ys[i]=y+len*Math.sin(ang);
	}
}
function calcEllipseX(a,b,ang)
{
	var x;
	if (ang%180==90)
	{
		x=0;
	}
	else
	{
		var k=Math.tan(ang*Math.PI/180);
		var s1=Math.ceil((ang%360)/90);
		if (s1>3 || s1<2)
		{
			x=Math.sqrt((a*a*b*b)/(k*k*a*a+b*b));
		}
		else 
		{
			x=-Math.sqrt((a*a*b*b)/(k*k*a*a+b*b));
		}
	}
	return x;
}

function calcEllipseY(a,b,ang)
{
	var y;
	if (ang%180==0)
	{
		y=0;
	}
	else
	{
		var k;
		if (ang%180==90)
		{
			k=0;
		}
		else
		{
			k=1/Math.tan(ang*Math.PI/180);
		}
		var s1=Math.ceil((ang%360)/90);
		if (s1<=2)
		{
			y=Math.sqrt((a*a*b*b)/(k*k*b*b+a*a));
		}
		else 
		{
			y=-Math.sqrt((a*a*b*b)/(k*k*b*b+a*a));
		}
	}
	return y;
}

function drawAxial(g,width,height,xstart,xend,xstep,points,xmargin)
{
	g.setPrintable(true);
	// calc the drawing step
	var ns=Math.floor((xend-xstart)/xstep);
	var nmargin=1;
	if (xmargin)
	{
		nmargin=xmargin
	}
	var us=Math.floor(width/(ns+2*nmargin));
	var uh=Math.floor(height/4);
	if (uh>8)
	{
		uh = 8;
	}
	var nm=height/2;
	
	// draw the axial
	g.setColor(COLOR_BLACK);
	g.setFont("arial","12px",Font.PLAIN); 
	g.setStroke(2);
	g.drawLine(0,nm,width,nm);
	// draw both end arrows
	var xs=[0,us/2,us/2];
	var ys=[nm,nm+uh,nm-uh];
	g.fillPolygon(xs,ys);
	xs=[width-us/2,width-us/2,width];
	ys=[nm+uh,nm-uh,nm];
	g.fillPolygon(xs,ys);

	// draw the marks
	g.setColor(COLOR_GRAY);
	for (var i=0;i<=ns;i++)
	{
		// draw a vertical line mark
		g.drawLine((i+nmargin)*us,nm+uh,(i+nmargin)*us,nm-uh);
		// draw the number 
		var ms=""+(xstart+i*xstep);
		g.drawStringRect(ms,(i+nmargin-0.5)*us,(nm+uh+5),us,"center");
	}
	// draw the points
	var psize=8;
	if (points)
	{
		for (var i=0; i<points.length;i++)
		{
			if (i%2==0)
			{
				if (points[i]>=xstart && points[i]<=xend)
				{
					// draw a small circle
                    var idx=Math.floor(i/2)%COLOR_MARKS.length;
					g.setColor(COLOR_MARKS[idx]);
				    var xp=((points[i]-xstart)/xstep+nmargin)*us;
				    g.fillEllipse(xp-psize/2+1,nm-psize/2,psize,psize);
					// draw the mark
					if ((i+1)<points.length)
					{
						g.setColor(COLOR_BLACK);
						g.drawStringRect(points[i+1],xp-0.5*us,(nm-uh-15),us,"center");
						i++;
					}
				}
			}
		}
	}
	g.paint();
}

function drawBar(g,width,height,data,seriespergroup,title,margin)
{
	g.setPrintable(true);
	// check how many data
	var n; 
	if (seriespergroup>1)
	{
		n = data.length/(1+2*seriespergroup);
	}
	else
	{
		n = data.length/2;
	}
	// get maximum bar height 
	var vmax = 0;
	for (var i=0;i<n;i++)
	{
		if (seriespergroup>1)
		{
			for (var j=0;j<seriespergroup;j++)
			{
				var idx =i*(data.length/n)+1+2*j+1;
				if (data[idx]>vmax)
				{
					vmax=data[idx];
				}
			}
		}
		else if (data[2*i+1]>vmax)
		{
			vmax=data[2*i+1];
		}
	}
	// draw the title
	if (title)
	{
		g.setColor(COLOR_BLACK);
		g.setFont("arial","12px",Font.BOLD); 
		g.drawStringRect(title,0,5,width,"center");
	}
	// draw the outer rectangle
	g.setColor(COLOR_GRAY);
	g.setStroke(1);
	var x0,y0,xm,ym;

	if (margin)
	{
		x0=margin;
		y0=2*margin;
		xm=width-x0;
		ym=height-y0;
		g.drawRect(x0,y0,xm-x0,ym-y0);
	}
	else
	{
		x0=5;
		y0=2*5;
		xm=width-x0;
		ym=height-y0;
		g.drawRect(x0,y0,xm-x0,ym-y0);
	}
	// draw the bars
	var wd=10;
	var w0=Math.floor((xm-x0-(n*2)*wd)/(n*seriespergroup));
	for (var i=0;i<n;i++)
	{
		if (seriespergroup>1)
		{
			for (var j=0;j<seriespergroup;j++)
			{
				var idx=i*(data.length/n)+1+2*j+1;
				var h=data[idx]*(ym-y0-2*wd)/vmax;

				var x=x0+((xm-x0)/n)*i+wd+j*w0;
				var y=ym-h;
				g.setColor(COLOR_MARKS[j%COLOR_MARKS.length]);
				g.drawRect(x,y,w0,h);
				g.fillRect(x,y,w0,h);
				g.setColor(COLOR_BLACK);
				var s=""+data[idx];
				g.setFont("arial","11px",Font.PlAIN); 
				g.drawStringRect(s,x,y-13,w0,"center");
				g.drawStringRect(data[idx-1],x,ym,w0,"center");
			}
			// draw category 
			g.setFont("arial","12px",Font.PlAIN); 
			g.drawStringRect(data[i*(data.length/n)],x0+((xm-x0)/n)*i,ym+15,(xm-x0)/n,"center");
		}
		else
		{
		   	var h=data[2*i+1]*(ym-y0-2*wd)/vmax;
			var x=x0+((xm-x0)/n)*i+wd;
			var y=ym-h;
			g.setColor(COLOR_MARKS[i%COLOR_MARKS.length]);
			g.drawRect(x,y,w0,h);
			g.fillRect(x,y,w0,h);
			g.setColor(COLOR_BLACK);
			var s=""+data[2*i+1];
			g.setFont("arial","11px",Font.PlAIN); 
			g.drawStringRect(s,x,y-13,w0,"center");
			g.drawStringRect(data[2*i],x,ym,w0,"center");
		}
	}
	g.paint();
}

function drawPie(g,width,height,data,title,totaldegree,margin)
{
	g.setPrintable(true);
	// draw the outer rectangle
	g.setColor(COLOR_GRAY);
	g.setStroke(1);
	lmargin=5;
	if (margin)
	{
		lmargin=margin;
	}
	g.drawRect(lmargin,lmargin,width-2*lmargin,height-2*lmargin);

	// draw the title
	if (title)
	{
		g.setColor(COLOR_BLACK);
		g.setFont("arial","12px",Font.BOLD); 
		g.drawStringRect(title,lmargin,5+lmargin,width-2*lmargin,"center");
	}

	// draw the pies 
	var n=Math.floor(data.length/2);
	var startangle=0;
	var total=0;
	for (var i=0;i<n;i++)
	{
	   	total+=data[2*i+1];
	}
	var d=width-2*lmargin;
	if (d>(height-2*lmargin-10))
	{
		d=height-2*lmargin-10;
	}
	d=d*0.9;
	var x=(width-d)/2;
	var y=(height-d)/2+lmargin;
	var degrees=360;
	if(totaldegree && totaldegree>0 && totaldegree<360)
	{
		degrees=totaldegree;
	}

	g.setFont("arial","11px",Font.PlAIN); 
	for (var i=0;i<n;i++)
	{
		g.setColor(COLOR_MARKS[i%COLOR_MARKS.length]);
		var piesize=(data[2*i+1]/total)*degrees;
		g.fillArc(x,y,d,d,startangle,startangle+piesize);
		startangle+=piesize;
		var mangle=(startangle-piesize/2)*2*Math.PI/360;
		var x0=x+d/2+(d/2)*Math.cos(mangle);
		var y0=y+d/2-(d/2)*Math.sin(mangle);
		g.setColor(COLOR_BLACK);
		if ((mangle>0 && mangle<Math.PI/2) || mangle>Math.PI*3/2)
		{
			g.drawStringRect(data[2*i],x0,y0,(width-lmargin-x0),"center");
			g.drawLine(x0,y0,x0+(width-lmargin-x0)/2,y0);
			g.drawLine(x0+(width-lmargin-x0)/2,y0,x0+(width-lmargin-x0)/2,y0+2);
		}
		else
		{
			g.drawStringRect(data[2*i],lmargin,y0,(x0-lmargin),"center");
			g.drawLine(x0,y0,lmargin+(x0-lmargin)/2,y0);
			g.drawLine(lmargin+(x0-lmargin)/2,y0,lmargin+(x0-lmargin)/2,y0+2);
		}
	}
	g.paint();
}
function drawXY(g,width,height,xstart,xend,xstep,fxys,xmarkstep,ymarkstep,title,margin,showxgrid,showygrid)
{
	g.setPrintable(true);
	g.setColor(COLOR_GRAY);
	g.setStroke(1);
	var lmark=15;
	var lmargin=5;
	if (margin)
	{
		lmargin=margin;
	}

	// draw the title
	if (title)
	{
		g.setColor(COLOR_BLACK);
		g.setFont("arial","12px",Font.BOLD); 
		g.drawStringRect(title,lmargin,5+lmargin,width-2*lmargin,"center");
	}

	var y1=15+2*lmargin;
	var y2=height-lmargin-10;
	var x1=lmargin+lmark;
	var x2=width-lmargin;
	// draw the outer rectangle
	g.drawRect(x1,y1,x2-x1,y2-y1);

	var fss=fxys.split('|');
	var ymin=0;
	var ymax=0;
	var slegends = new Array();
	var xdata = new Array();
	var ydata = new Array();
	for (var idx=0;idx<fss.length;idx++)
	{
		var xs=new Array();
		var ys=new Array();

		var sps=fss[idx].split('='); 
		var fxy;
		var slegend=null;
		if (sps.length>=2)
		{
			slegend=sps[0];
			fxy=sps[1];
		}
		else
		{
			slegend="";
			fxy=sps[0];
		}
		slegends[idx]=slegend;
		for (var x=xstart;x<=xend;x+=xstep)
		{
			var sy=fxy; 
			var y=eval(sy.replace(/x/g,x));
			var n=(x-xstart)/xstep;
			if (idx==0 && n==0)
			{
				ymin=y;
				ymax=y;
			}
			else
			{
				if (ymin>y)
				{
					ymin = y;
				}
				if (ymax<y)
				{
					ymax = y;
				}
			}
			xs[n]=x;
			ys[n]=y;
		}
		xdata[idx]=xs;
		ydata[idx]=ys;
	}
	
	for (var idx=0;idx<slegends.length;idx++)
	{
		var xs=xdata[idx];
		var ys=ydata[idx];
		var slegend=slegends[idx];

		// normalize the data
		if (ymin>0)
		{
			ymin=0;
		}
		// normalize y to the range of y2 to y1
		for (var i=0;i<ys.length;i++)
		{
			var y=ys[i];
			ys[i]=y2-((y-ymin)/(ymax-ymin))*(y2-y1);
		}
		// normalize x to the range of x1 to x2 
		for (var i=0;i<xs.length;i++)
		{
			var x=xs[i];
			xs[i]=x1+((x-xstart)/(xend-xstart))*(x2-x1);
		}
	
		g.setColor(COLOR_MARKS[idx%COLOR_MARKS.length]);
		g.drawPolyline(xs,ys);
		// draw legend 
		if (slegend)
		{
			g.fillRect(x1+(idx%2)*(x2-x1)/2,height+Math.floor(idx/2)*15,10,10);
			g.setColor(COLOR_BLACK);
			g.setFont("arial","9px",Font.PLAIN); 
			g.drawStringRect('--- '+slegend,x1+(idx%2)*(x2-x1)/2+15,height+Math.floor(idx/2)*15,(x2-x1)/2-15,"left");
		}
	}
	// draw x-axis
	g.setColor(COLOR_GRAY);
	y0=y2-((0-ymin)/(ymax-ymin))*(y2-y1);
	g.drawLine(x1,y0,x2,y0);
	if (xmarkstep>0)
	{
		var xp=x1+((0-xmarkstep)/(xend-xstart))*(x2-x1); 
		for (var xx=xstart;xx<=xend;xx+=xmarkstep)
		{
			var x=x1+((xx-xstart)/(xend-xstart))*(x2-x1); 
			g.setColor(COLOR_GRAY);
			if (showxgrid)
			{
				g.drawLine(x,y1,x,y2);
			}
			else
			{
				g.drawLine(x,y0-5,x,y0+5);
			}
			g.drawStringRect(xx,(xp+x)/2,y0+2,x-xp,"center");
			xp=x;
		}
	}
	// draw y axis
	if (ymarkstep>0)
	{
		var yp=y2+(ymarkstep/(ymax-ymin))*(y2-y1); 
		var y11=ymin;
		if (ymin<0)
		{
			y11=-Math.floor(-ymin/ymarkstep)*ymarkstep;
		}
		for (var yy=y11;yy<=ymax;yy+=ymarkstep)
		{
			var y=y2-((yy-ymin)/(ymax-ymin))*(y2-y1); 
			g.setColor(COLOR_GRAY);
			if (yy!=0)
			{
				if (showygrid)
				{
					g.drawLine(x1,y,x2,y);
				}
				else
				{
					g.drawLine(x1,y,x1+5,y);
				}
				g.drawStringRect(yy,0,y-5,x1,"right");
			}
			yp=y;
		}
	}
	g.paint();
}

