/* This notice must be untouched at all times.

wz_jsgraphics.js    v. 3.03
The latest version is available at
http://www.walterzorn.com
or http://www.devira.com
or http://www.walterzorn.de

Copyright (c) 2002-2004 Walter Zorn. All rights reserved.
Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )
Last modified: 28. 1. 2008

Performance optimizations for Internet Explorer
by Thomas Frank and John Holdsworth.
fillPolygon method implemented by Matthieu Haller.

High Performance JavaScript Graphics Library.
Provides methods
- to draw lines, rectangles, ellipses, polygons
	with specifiable line thickness,
- to fill rectangles, polygons, ellipses and arcs
- to draw text.
NOTE: Operations, functions and branching have rather been optimized
to efficiency and speed than to shortness of source code.

LICENSE: LGPL

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License (LGPL) as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA,
or see http://www.gnu.org/copyleft/lesser.html
*/


var jg_ok, jg_ie, jg_fast, jg_dom, jg_moz;


function _chkDHTM(x, i)
{
	x = document.body || null;
	jg_ie = x && typeof x.insertAdjacentHTML != "undefined" && document.createElement;
	jg_dom = (x && !jg_ie &&
		typeof x.appendChild != "undefined" &&
		typeof document.createRange != "undefined" &&
		typeof (i = document.createRange()).setStartBefore != "undefined" &&
		typeof i.createContextualFragment != "undefined");
	jg_fast = jg_ie && document.all && !window.opera;
	jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";
	jg_ok = !!(jg_ie || jg_dom);
}

function _pntCnvDom()
{
	var x = this.wnd.document.createRange();
	x.setStartBefore(this.cnv);
	x = x.createContextualFragment(jg_fast? this._htmRpc() : this.htm);
	if(this.cnv) this.cnv.appendChild(x);
	this.htm = "";
}

function _pntCnvIe()
{
	if(this.cnv) this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this._htmRpc() : this.htm);
	this.htm = "";
}

function _pntDoc()
{
	this.wnd.document.write(jg_fast? this._htmRpc() : this.htm);
	this.htm = '';
}

function _pntN()
{
	;
}

function _mkDiv(x, y, w, h)
{
	this.htm += '<div style="position:absolute;'+
		'left:' + x + 'px;'+
		'top:' + y + 'px;'+
		'width:' + w + 'px;'+
		'height:' + h + 'px;'+
		'clip:rect(0,'+w+'px,'+h+'px,0);'+
		'background-color:' + this.color +
		(!jg_moz? ';overflow:hidden' : '')+
		';"><\/div>';
}

function _mkDiv(x, y, w, h, title)
{
	this.htm += '<div style="position:absolute;'+
		'left:' + x + 'px;'+
		'top:' + y + 'px;'+
		'width:' + w + 'px;'+
		'height:' + h + 'px;'+		
		'clip:rect(0,'+w+'px,'+h+'px,0);'+
		'background-color:' + this.color +
		(!jg_moz? ';overflow:hidden' : '')+
		';" title="' + title + '"><\/div>';
}

function _mkDivIe(x, y, w, h)
{
	this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';
}

function _mkDivPrt(x, y, w, h)
{
	this.htm += '<div style="position:absolute;'+
		'border-left:' + w + 'px solid ' + this.color + ';'+
		'left:' + x + 'px;'+
		'top:' + y + 'px;'+
		'width:0px;'+
		'height:' + h + 'px;'+
		'clip:rect(0,'+w+'px,'+h+'px,0);'+
		'background-color:' + this.color +
		(!jg_moz? ';overflow:hidden' : '')+
		';"><\/div>';
}

var _regex =  /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;
function _htmRpc()
{
	return this.htm.replace(
		_regex,
		'<div style="overflow:hidden;position:absolute;background-color:'+
		'$1;left:$2;top:$3;width:$4;height:$5"></div>\n');
}

function _htmPrtRpc()
{
	return this.htm.replace(
		_regex,
		'<div style="overflow:hidden;position:absolute;background-color:'+
		'$1;left:$2;top:$3;width:$4;height:$5;border-left:$4px solid $1"></div>\n');
}

function _mkLin(x1, y1, x2, y2)
{
	if(x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1;

	if(dx >= dy)
	{
		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx,
		ox = x;
		while(dx > 0)
		{--dx;
			++x;
			if(p > 0)
			{
				this._mkDiv(ox, y, x-ox, 1);
				y += yIncr;
				p += pru;
				ox = x;
			}
			else p += pr;
		}
		this._mkDiv(ox, y, x2-ox+1, 1);
	}

	else
	{
		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy,
		oy = y;
		if(y2 <= y1)
		{
			while(dy > 0)
			{--dy;
				if(p > 0)
				{
					this._mkDiv(x++, y, 1, oy-y+1);
					y += yIncr;
					p += pru;
					oy = y;
				}
				else
				{
					y += yIncr;
					p += pr;
				}
			}
			this._mkDiv(x2, y2, 1, oy-y2+1);
		}
		else
		{
			while(dy > 0)
			{--dy;
				y += yIncr;
				if(p > 0)
				{
					this._mkDiv(x++, oy, 1, y-oy);
					p += pru;
					oy = y;
				}
				else p += pr;
			}
			this._mkDiv(x2, oy, 1, y2-oy+1);
		}
	}
}

function _mkLin2D(x1, y1, x2, y2)
{
	if(x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1;

	var s = this.stroke;
	if(dx >= dy)
	{
		if(dx > 0 && s-3 > 0)
		{
			var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;
			_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
		}
		else var _s = s;
		var ad = Math.ceil(s/2);

		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx,
		ox = x;
		while(dx > 0)
		{--dx;
			++x;
			if(p > 0)
			{
				this._mkDiv(ox, y, x-ox+ad, _s);
				y += yIncr;
				p += pru;
				ox = x;
			}
			else p += pr;
		}
		this._mkDiv(ox, y, x2-ox+ad+1, _s);
	}

	else
	{
		if(s-3 > 0)
		{
			var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;
			_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
		}
		else var _s = s;
		var ad = Math.round(s/2);

		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy,
		oy = y;
		if(y2 <= y1)
		{
			++ad;
			while(dy > 0)
			{--dy;
				if(p > 0)
				{
					this._mkDiv(x++, y, _s, oy-y+ad);
					y += yIncr;
					p += pru;
					oy = y;
				}
				else
				{
					y += yIncr;
					p += pr;
				}
			}
			this._mkDiv(x2, y2, _s, oy-y2+ad);
		}
		else
		{
			while(dy > 0)
			{--dy;
				y += yIncr;
				if(p > 0)
				{
					this._mkDiv(x++, oy, _s, y-oy+ad);
					p += pru;
					oy = y;
				}
				else p += pr;
			}
			this._mkDiv(x2, oy, _s, y2-oy+ad+1);
		}
	}
}

function _mkLinDott(x1, y1, x2, y2)
{
	if(x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1,
	drw = true;
	if(dx >= dy)
	{
		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx;
		while(dx > 0)
		{--dx;
			if(drw) this._mkDiv(x, y, 1, 1);
			drw = !drw;
			if(p > 0)
			{
				y += yIncr;
				p += pru;
			}
			else p += pr;
			++x;
		}
	}
	else
	{
		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy;
		while(dy > 0)
		{--dy;
			if(drw) this._mkDiv(x, y, 1, 1);
			drw = !drw;
			y += yIncr;
			if(p > 0)
			{
				++x;
				p += pru;
			}
			else p += pr;
		}
	}
	if(drw) this._mkDiv(x, y, 1, 1);
}

function _mkOv(left, top, width, height)
{
	var a = (++width)>>1, b = (++height)>>1,
	wod = width&1, hod = height&1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	ox = 0, oy = b,
	aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
	st = (aa2>>1)*(1-(b<<1)) + bb2,
	tt = (bb2>>1) - aa2*((b<<1)-1),
	w, h;
	while(y > 0)
	{
		if(st < 0)
		{
			st += bb2*((x<<1)+3);
			tt += bb4*(++x);
		}
		else if(tt < 0)
		{
			st += bb2*((x<<1)+3) - aa4*(y-1);
			tt += bb4*(++x) - aa2*(((y--)<<1)-3);
			w = x-ox;
			h = oy-y;
			if((w&2) && (h&2))
			{
				this._mkOvQds(cx, cy, x-2, y+2, 1, 1, wod, hod);
				this._mkOvQds(cx, cy, x-1, y+1, 1, 1, wod, hod);
			}
			else this._mkOvQds(cx, cy, x-1, oy, w, h, wod, hod);
			ox = x;
			oy = y;
		}
		else
		{
			tt -= aa2*((y<<1)-3);
			st -= aa4*(--y);
		}
	}
	w = a-ox+1;
	h = (oy<<1)+hod;
	y = cy-oy;
	this._mkDiv(cx-a, y, w, h);
	this._mkDiv(cx+ox+wod-1, y, w, h);
}

function _mkOv2D(left, top, width, height)
{
	var s = this.stroke;
	width += s+1;
	height += s+1;
	var a = width>>1, b = height>>1,
	wod = width&1, hod = height&1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
	st = (aa2>>1)*(1-(b<<1)) + bb2,
	tt = (bb2>>1) - aa2*((b<<1)-1);

	if(s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))
	{
		var ox = 0, oy = b,
		w, h,
		pxw;
		while(y > 0)
		{
			if(st < 0)
			{
				st += bb2*((x<<1)+3);
				tt += bb4*(++x);
			}
			else if(tt < 0)
			{
				st += bb2*((x<<1)+3) - aa4*(y-1);
				tt += bb4*(++x) - aa2*(((y--)<<1)-3);
				w = x-ox;
				h = oy-y;

				if(w-1)
				{
					pxw = w+1+(s&1);
					h = s;
				}
				else if(h-1)
				{
					pxw = s;
					h += 1+(s&1);
				}
				else pxw = h = s;
				this._mkOvQds(cx, cy, x-1, oy, pxw, h, wod, hod);
				ox = x;
				oy = y;
			}
			else
			{
				tt -= aa2*((y<<1)-3);
				st -= aa4*(--y);
			}
		}
		this._mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);
		this._mkDiv(cx+a+wod-s, cy-oy, s, (oy<<1)+hod);
	}

	else
	{
		var _a = (width-(s<<1))>>1,
		_b = (height-(s<<1))>>1,
		_x = 0, _y = _b,
		_aa2 = (_a*_a)<<1, _aa4 = _aa2<<1, _bb2 = (_b*_b)<<1, _bb4 = _bb2<<1,
		_st = (_aa2>>1)*(1-(_b<<1)) + _bb2,
		_tt = (_bb2>>1) - _aa2*((_b<<1)-1),

		pxl = new Array(),
		pxt = new Array(),
		_pxb = new Array();
		pxl[0] = 0;
		pxt[0] = b;
		_pxb[0] = _b-1;
		while(y > 0)
		{
			if(st < 0)
			{
				pxl[pxl.length] = x;
				pxt[pxt.length] = y;
				st += bb2*((x<<1)+3);
				tt += bb4*(++x);
			}
			else if(tt < 0)
			{
				pxl[pxl.length] = x;
				st += bb2*((x<<1)+3) - aa4*(y-1);
				tt += bb4*(++x) - aa2*(((y--)<<1)-3);
				pxt[pxt.length] = y;
			}
			else
			{
				tt -= aa2*((y<<1)-3);
				st -= aa4*(--y);
			}

			if(_y > 0)
			{
				if(_st < 0)
				{
					_st += _bb2*((_x<<1)+3);
					_tt += _bb4*(++_x);
					_pxb[_pxb.length] = _y-1;
				}
				else if(_tt < 0)
				{
					_st += _bb2*((_x<<1)+3) - _aa4*(_y-1);
					_tt += _bb4*(++_x) - _aa2*(((_y--)<<1)-3);
					_pxb[_pxb.length] = _y-1;
				}
				else
				{
					_tt -= _aa2*((_y<<1)-3);
					_st -= _aa4*(--_y);
					_pxb[_pxb.length-1]--;
				}
			}
		}

		var ox = -wod, oy = b,
		_oy = _pxb[0],
		l = pxl.length,
		w, h;
		for(var i = 0; i < l; i++)
		{
			if(typeof _pxb[i] != "undefined")
			{
				if(_pxb[i] < _oy || pxt[i] < oy)
				{
					x = pxl[i];
					this._mkOvQds(cx, cy, x, oy, x-ox, oy-_oy, wod, hod);
					ox = x;
					oy = pxt[i];
					_oy = _pxb[i];
				}
			}
			else
			{
				x = pxl[i];
				this._mkDiv(cx-x, cy-oy, 1, (oy<<1)+hod);
				this._mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
				ox = x;
				oy = pxt[i];
			}
		}
		this._mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);
		this._mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
	}
}

function _mkOvDott(left, top, width, height)
{
	var a = (++width)>>1, b = (++height)>>1,
	wod = width&1, hod = height&1, hodu = hod^1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
	st = (aa2>>1)*(1-(b<<1)) + bb2,
	tt = (bb2>>1) - aa2*((b<<1)-1),
	drw = true;
	while(y > 0)
	{
		if(st < 0)
		{
			st += bb2*((x<<1)+3);
			tt += bb4*(++x);
		}
		else if(tt < 0)
		{
			st += bb2*((x<<1)+3) - aa4*(y-1);
			tt += bb4*(++x) - aa2*(((y--)<<1)-3);
		}
		else
		{
			tt -= aa2*((y<<1)-3);
			st -= aa4*(--y);
		}
		if(drw && y >= hodu) this._mkOvQds(cx, cy, x, y, 1, 1, wod, hod);
		drw = !drw;
	}
}

function _mkRect(x, y, w, h)
{
	var s = this.stroke;
	this._mkDiv(x, y, w, s);
	this._mkDiv(x+w, y, s, h);
	this._mkDiv(x, y+h, w+s, s);
	this._mkDiv(x, y+s, s, h-s);
}

function _mkRectDott(x, y, w, h)
{
	this.drawLine(x, y, x+w, y);
	this.drawLine(x+w, y, x+w, y+h);
	this.drawLine(x, y+h, x+w, y+h);
	this.drawLine(x, y, x, y+h);
}

function jsgFont()
{
	this.PLAIN = 'font-weight:normal;';
	this.BOLD = 'font-weight:bold;';
	this.ITALIC = 'font-style:italic;';
	this.ITALIC_BOLD = this.ITALIC + this.BOLD;
	this.BOLD_ITALIC = this.ITALIC_BOLD;
}
var Font = new jsgFont();

function jsgStroke()
{
	this.DOTTED = -1;
}
var Stroke = new jsgStroke();

function jsGraphics(cnv, wnd)
{
	this.setColor = function(x)
	{
		this.color = x.toLowerCase();
	};

	this.setStroke = function(x)
	{
		this.stroke = x;
		if(!(x+1))
		{
			this.drawLine = _mkLinDott;
			this._mkOv = _mkOvDott;
			this.drawRect = _mkRectDott;
		}
		else if(x-1 > 0)
		{
			this.drawLine = _mkLin2D;
			this._mkOv = _mkOv2D;
			this.drawRect = _mkRect;
		}
		else
		{
			this.drawLine = _mkLin;
			this._mkOv = _mkOv;
			this.drawRect = _mkRect;
		}
	};

	this.setPrintable = function(arg)
	{
		this.printable = arg;
		if(jg_fast)
		{
			this._mkDiv = _mkDivIe;
			this._htmRpc = arg? _htmPrtRpc : _htmRpc;
		}
		else this._mkDiv = arg? _mkDivPrt : _mkDiv;
	};

	this.setFont = function(fam, sz, sty)
	{
		this.ftFam = fam;
		this.ftSz = sz;
		this.ftSty = sty || Font.PLAIN;
	};

	this.drawPolyline = this.drawPolyLine = function(x, y)
	{
		for (var i=x.length - 1; i;)
		{--i;
			this.drawLine(x[i], y[i], x[i+1], y[i+1]);
		}
	};

	this.fillRect = function(x, y, w, h)
	{
		this._mkDiv(x, y, w, h);
	};
	
	this.fillRectTitle = function(x, y, w, h, title)
	{
		this._mkDiv(x, y, w, h, title);
	};


	this.drawPolygon = function(x, y)
	{
		this.drawPolyline(x, y);
		this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);
	};

	this.drawEllipse = this.drawOval = function(x, y, w, h)
	{
		this._mkOv(x, y, w, h);
	};

	this.fillEllipse = this.fillOval = function(left, top, w, h)
	{
		var a = w>>1, b = h>>1,
		wod = w&1, hod = h&1,
		cx = left+a, cy = top+b,
		x = 0, y = b, oy = b,
		aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
		st = (aa2>>1)*(1-(b<<1)) + bb2,
		tt = (bb2>>1) - aa2*((b<<1)-1),
		xl, dw, dh;
		if(w) while(y > 0)
		{
			if(st < 0)
			{
				st += bb2*((x<<1)+3);
				tt += bb4*(++x);
			}
			else if(tt < 0)
			{
				st += bb2*((x<<1)+3) - aa4*(y-1);
				xl = cx-x;
				dw = (x<<1)+wod;
				tt += bb4*(++x) - aa2*(((y--)<<1)-3);
				dh = oy-y;
				this._mkDiv(xl, cy-oy, dw, dh);
				this._mkDiv(xl, cy+y+hod, dw, dh);
				oy = y;
			}
			else
			{
				tt -= aa2*((y<<1)-3);
				st -= aa4*(--y);
			}
		}
		this._mkDiv(cx-a, cy-oy, w, (oy<<1)+hod);
	};

	this.fillArc = function(iL, iT, iW, iH, fAngA, fAngZ)
	{
		var a = iW>>1, b = iH>>1,
		iOdds = (iW&1) | ((iH&1) << 16),
		cx = iL+a, cy = iT+b,
		x = 0, y = b, ox = x, oy = y,
		aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
		st = (aa2>>1)*(1-(b<<1)) + bb2,
		tt = (bb2>>1) - aa2*((b<<1)-1),
		// Vars for radial boundary lines
		xEndA, yEndA, xEndZ, yEndZ,
		iSects = (1 << (Math.floor((fAngA %= 360.0)/180.0) << 3))
				| (2 << (Math.floor((fAngZ %= 360.0)/180.0) << 3))
				| ((fAngA >= fAngZ) << 16),
		aBndA = new Array(b+1), aBndZ = new Array(b+1);
		
		// Set up radial boundary lines
		fAngA *= Math.PI/180.0;
		fAngZ *= Math.PI/180.0;
		xEndA = cx+Math.round(a*Math.cos(fAngA));
		yEndA = cy+Math.round(-b*Math.sin(fAngA));
		_mkLinVirt(aBndA, cx, cy, xEndA, yEndA);
		xEndZ = cx+Math.round(a*Math.cos(fAngZ));
		yEndZ = cy+Math.round(-b*Math.sin(fAngZ));
		_mkLinVirt(aBndZ, cx, cy, xEndZ, yEndZ);

		while(y > 0)
		{
			if(st < 0) // Advance x
			{
				st += bb2*((x<<1)+3);
				tt += bb4*(++x);
			}
			else if(tt < 0) // Advance x and y
			{
				st += bb2*((x<<1)+3) - aa4*(y-1);
				ox = x;
				tt += bb4*(++x) - aa2*(((y--)<<1)-3);
				this._mkArcDiv(ox, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
				oy = y;
			}
			else // Advance y
			{
				tt -= aa2*((y<<1)-3);
				st -= aa4*(--y);
				if(y && (aBndA[y] != aBndA[y-1] || aBndZ[y] != aBndZ[y-1]))
				{
					this._mkArcDiv(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
					ox = x;
					oy = y;
				}
			}
		}
		this._mkArcDiv(x, 0, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
		if(iOdds >> 16) // Odd height
		{
			if(iSects >> 16) // Start-angle > end-angle
			{
				var xl = (yEndA <= cy || yEndZ > cy)? (cx - x) : cx;
				this._mkDiv(xl, cy, x + cx - xl + (iOdds & 0xffff), 1);
			}
			else if((iSects & 0x01) && yEndZ > cy)
				this._mkDiv(cx - x, cy, x, 1);
		}
	};

/* fillPolygon method, implemented by Matthieu Haller.
This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.
C source of GD 1.8.4 found at http://www.boutell.com/gd/

THANKS to Kirsten Schulz for the polygon fixes!

The intersection finding technique of this code could be improved
by remembering the previous intertersection, and by using the slope.
That could help to adjust intersections to produce a nice
interior_extrema. */
	this.fillPolygon = function(array_x, array_y)
	{
		var i;
		var y;
		var miny, maxy;
		var x1, y1;
		var x2, y2;
		var ind1, ind2;
		var ints;

		var n = array_x.length;
		if(!n) return;

		miny = array_y[0];
		maxy = array_y[0];
		for(i = 1; i < n; i++)
		{
			if(array_y[i] < miny)
				miny = array_y[i];

			if(array_y[i] > maxy)
				maxy = array_y[i];
		}
		for(y = miny; y <= maxy; y++)
		{
			var polyInts = new Array();
			ints = 0;
			for(i = 0; i < n; i++)
			{
				if(!i)
				{
					ind1 = n-1;
					ind2 = 0;
				}
				else
				{
					ind1 = i-1;
					ind2 = i;
				}
				y1 = array_y[ind1];
				y2 = array_y[ind2];
				if(y1 < y2)
				{
					x1 = array_x[ind1];
					x2 = array_x[ind2];
				}
				else if(y1 > y2)
				{
					y2 = array_y[ind1];
					y1 = array_y[ind2];
					x2 = array_x[ind1];
					x1 = array_x[ind2];
				}
				else continue;

				 //  Modified 11. 2. 2004 Walter Zorn
				if((y >= y1) && (y < y2))
					polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);

				else if((y == maxy) && (y > y1) && (y <= y2))
					polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
			}
			polyInts.sort(_CompInt);
			for(i = 0; i < ints; i+=2)
				this._mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);
		}
	};

	this.drawString = function(txt, x, y)
	{
		this.htm += '<div style="position:absolute;white-space:nowrap;'+
			'left:' + x + 'px;'+
			'top:' + y + 'px;'+
			'font-family:' +  this.ftFam + ';'+
			'font-size:' + this.ftSz + ';'+
			'color:' + this.color + ';' + this.ftSty + '">'+
			txt +
			'<\/div>';
	};

/* drawStringRect() added by Rick Blommers.
Allows to specify the size of the text rectangle and to align the
text both horizontally (e.g. right) and vertically within that rectangle */
	this.drawStringRect = function(txt, x, y, width, halign)
	{
		this.htm += '<div style="position:absolute;overflow:hidden;'+
			'left:' + x + 'px;'+
			'top:' + y + 'px;'+
			'width:'+width +'px;'+
			'text-align:'+halign+';'+
			'font-family:' +  this.ftFam + ';'+
			'font-size:' + this.ftSz + ';'+
			'color:' + this.color + ';' + this.ftSty + '">'+
			txt +
			'<\/div>';
	};

	this.drawImage = function(imgSrc, x, y, w, h, a)
	{
		this.htm += '<div style="position:absolute;'+
			'left:' + x + 'px;'+
			'top:' + y + 'px;'+
			// w (width) and h (height) arguments are now optional.
			// Added by Mahmut Keygubatli, 14.1.2008
			(w? ('width:' +  w + 'px;') : '') +
			(h? ('height:' + h + 'px;'):'')+'">'+
			'<img src="' + imgSrc +'"'+ (w ? (' width="' + w + '"'):'')+ (h ? (' height="' + h + '"'):'') + (a? (' '+a) : '') + '>'+
			'<\/div>';
	};

	this.clear = function()
	{
		this.htm = "";
		if(this.cnv) this.cnv.innerHTML = "";
	};

	this._mkOvQds = function(cx, cy, x, y, w, h, wod, hod)
	{
		var xl = cx - x, xr = cx + x + wod - w, yt = cy - y, yb = cy + y + hod - h;
		if(xr > xl+w)
		{
			this._mkDiv(xr, yt, w, h);
			this._mkDiv(xr, yb, w, h);
		}
		else
			w = xr - xl + w;
		this._mkDiv(xl, yt, w, h);
		this._mkDiv(xl, yb, w, h);
	};
	
	this._mkArcDiv = function(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects)
	{
		var xrDef = cx + x + (iOdds & 0xffff), y2, h = oy - y, xl, xr, w;

		if(!h) h = 1;
		x = cx - x;

		if(iSects & 0xff0000) // Start-angle > end-angle
		{
			y2 = cy - y - h;
			if(iSects & 0x00ff)
			{
				if(iSects & 0x02)
				{
					xl = Math.max(x, aBndZ[y]);
					w = xrDef - xl;
					if(w > 0) this._mkDiv(xl, y2, w, h);
				}
				if(iSects & 0x01)
				{
					xr = Math.min(xrDef, aBndA[y]);
					w = xr - x;
					if(w > 0) this._mkDiv(x, y2, w, h);
				}
			}
			else
				this._mkDiv(x, y2, xrDef - x, h);
			y2 = cy + y + (iOdds >> 16);
			if(iSects & 0xff00)
			{
				if(iSects & 0x0100)
				{
					xl = Math.max(x, aBndA[y]);
					w = xrDef - xl;
					if(w > 0) this._mkDiv(xl, y2, w, h);
				}
				if(iSects & 0x0200)
				{
					xr = Math.min(xrDef, aBndZ[y]);
					w = xr - x;
					if(w > 0) this._mkDiv(x, y2, w, h);
				}
			}
			else
				this._mkDiv(x, y2, xrDef - x, h);
		}
		else
		{
			if(iSects & 0x00ff)
			{
				if(iSects & 0x02)
					xl = Math.max(x, aBndZ[y]);
				else
					xl = x;
				if(iSects & 0x01)
					xr = Math.min(xrDef, aBndA[y]);
				else
					xr = xrDef;
				y2 = cy - y - h;
				w = xr - xl;
				if(w > 0) this._mkDiv(xl, y2, w, h);
			}
			if(iSects & 0xff00)
			{
				if(iSects & 0x0100)
					xl = Math.max(x, aBndA[y]);
				else
					xl = x;
				if(iSects & 0x0200)
					xr = Math.min(xrDef, aBndZ[y]);
				else
					xr = xrDef;
				y2 = cy + y + (iOdds >> 16);
				w = xr - xl;
				if(w > 0) this._mkDiv(xl, y2, w, h);
			}
		}
	};

	this.setStroke(1);
	this.setFont("verdana,geneva,helvetica,sans-serif", "12px", Font.PLAIN);
	this.color = "#000000";
	this.htm = "";
	this.wnd = wnd || window;

	if(!jg_ok) _chkDHTM();
	if(jg_ok)
	{
		if(cnv)
		{
			if(typeof(cnv) == "string")
				this.cont = document.all? (this.wnd.document.all[cnv] || null)
					: document.getElementById? (this.wnd.document.getElementById(cnv) || null)
					: null;
			else if(cnv == window.document)
				this.cont = document.getElementsByTagName("body")[0];
			// If cnv is a direct reference to a canvas DOM node
			// (option suggested by Andreas Luleich)
			else this.cont = cnv;
			// Create new canvas inside container DIV. Thus the drawing and clearing
			// methods won't interfere with the container's inner html.
			// Solution suggested by Vladimir.
			this.cnv = this.wnd.document.createElement("div");
			this.cnv.style.fontSize=0;
			this.cont.appendChild(this.cnv);
			this.paint = jg_dom? _pntCnvDom : _pntCnvIe;
		}
		else
			this.paint = _pntDoc;
	}
	else
		this.paint = _pntN;

	this.setPrintable(false);
}

function _mkLinVirt(aLin, x1, y1, x2, y2)
{
	var dx = Math.abs(x2-x1), dy = Math.abs(y2-y1),
	x = x1, y = y1,
	xIncr = (x1 > x2)? -1 : 1,
	yIncr = (y1 > y2)? -1 : 1,
	p,
	i = 0;
	if(dx >= dy)
	{
		var pr = dy<<1,
		pru = pr - (dx<<1);
		p = pr-dx;
		while(dx > 0)
		{--dx;
			if(p > 0)    //  Increment y
			{
				aLin[i++] = x;
				y += yIncr;
				p += pru;
			}
			else p += pr;
			x += xIncr;
		}
	}
	else
	{
		var pr = dx<<1,
		pru = pr - (dy<<1);
		p = pr-dy;
		while(dy > 0)
		{--dy;
			y += yIncr;
			aLin[i++] = x;
			if(p > 0)    //  Increment x
			{
				x += xIncr;
				p += pru;
			}
			else p += pr;
		}
	}
	for(var len = aLin.length, i = len-i; i;)
		aLin[len-(i--)] = x;
};

function _CompInt(x, y)
{
	return(x - y);
}


function getWidthInPixel(str) {
		var newSpan = document.createElement('span');
		newSpan.style.fontSize = "10px";		
		newSpan.style.fontFamily = "verdana";		
		newSpan.style.fontStyle = "normal";			
		newSpan.style.fontWieght = "normal";		
		newSpan.innerHTML = str;
		
		document.body.appendChild(newSpan);		
		var iStringWidth = newSpan.offsetWidth;
		//alert("first");
		//newSpan.removeNode(true);
		//removeChildNodes(newSpan);
		document.body.removeChild(newSpan);
		if(iStringWidth==0)
		  iStringWidth=str.length*6+6;
		//alert(iStringWidth);
		return iStringWidth;

	}
	
	/*function getWidthInPixel(str) {
		var newSpan = document.createElement('div');
		newSpan.style.fontSize = "10px";		
		newSpan.id="version";
		newSpan.style.fontFamily = "verdana";		
		newSpan.style.fontStyle = "normal";			
		newSpan.style.fontWeight = "normal";		
		newSpan.innerHTML = str;
		//alert("Start of the execution");
		document.body.appendChild(newSpan);
		var x = document.getElementById('version');
		
		var iStringWidth =x.offsetWidth;
		
		//newSpan.removeNode(true);
		//removeChildNodes(newSpan);
		document.body.removeChild(newSpan);	
		//alert("End of the execution");	
		return iStringWidth;

	}
	*/
	function removeChildNodes(anode) {
		while (anode.hasChildNodes()) {
			anode.removeChild(anode.lastChild);
		}
	}

	function drawBox(xpos, ypos, jg, txt, title) {	
		var length = 70;
		var height = 20;	
		
		jg.setColor("#ffffff"); // blue
  		jg.fillRectTitle(xpos, ypos, length, height, title);
		jg.setColor("#000000");
		var startX = xpos + (length - getWidthInPixel(txt)) /2;
		var startY = ypos + (height - 10)/2 -1;
		jg.drawString(txt, startX, startY);
		jg.setColor("#6C9D94");
		jg.drawRect(xpos, ypos, length, height);
	}
	
	function drawSmallBox(xpos, ypos, jg, txt, title) {
		var length = 50;
		var height = 20;
		jg.setColor("#6C9D94"); // blue
  		jg.fillRectTitle(xpos, ypos, length, height, title);
		jg.setColor("#000000");
		var startX = xpos + (length - getWidthInPixel(txt)) /2;
		var startY = ypos + (height - 10)/2;
		jg.drawString(txt, startX, startY);
		jg.setColor("#6C9D94");
		jg.drawRect(xpos, ypos, length, height);
	}
	
	function drawPartner(xpos, ypos, jg, txt, title) {
		var length = 50;
		var height = 20;
		jg.setColor("#015B4E"); // blue
  		jg.fillRectTitle(xpos, ypos, length, height, title);
		jg.setColor("#ffffff");
		var startX = xpos + (length - getWidthInPixel(txt)) /2;
		var startY = ypos + (height - 10)/2;
		jg.drawString(txt, startX, startY);
		jg.setColor("#6C9D94");
		jg.drawRect(xpos, ypos, length, height);
	}
	
	function drawSecondPhaseAgency(xpos, ypos, jg, txt, title) {
		var length = 50;
		var height = 20;
		jg.setColor("#D7E5E2"); // blue
  		jg.fillRectTitle(xpos, ypos, length, height, title);
		jg.setColor("#000000");
		var startX = xpos + (length - getWidthInPixel(txt)) /2;
		var startY = ypos + (height - 10)/2;
		jg.drawString(txt, startX, startY);
		jg.setColor("#6C9D94");
		jg.drawRect(xpos, ypos, length, height);
	}
	
	
	
	function drawAgencies(container_name) {
	  var jg = new jsGraphics(container_name);  
  	  jg.setFont("verdana","10px",Font.NORMAL);  		
	  drawBox(70, 10, jg, "MP", "Public Prosecution Office");
	  drawBox(145, 10, jg, "COURT", "Court");
	  drawBox(220, 10, jg, "CE", "Chief Executive");
	  drawBox(295, 10, jg, "SAAL", "Legislative Assembly");
	  
	  drawBox(120, 50, jg, "OCE", "Office of The Chief Executive");
	  drawBox(320, 50, jg, "SCE", "Executive Council");
	  jg.setColor("#6C9D94");
	  jg.drawLine(230, 30, 230, 40);
	  jg.drawLine(230, 40, 160, 40);
	  jg.drawLine(160,40, 160, 50);
	  //jg.setStroke(Stroke.DOTTED); 
	  jg.drawLine(280, 30, 280, 40);
	  jg.drawLine(280, 40, 355, 40);
	  jg.drawLine(355, 40, 355, 50);
	  //jg.setStroke(1);
	  //LINE  from CE to SS
	  jg.drawLine(255, 30, 255, 100);
	  
	  drawBox(615, 100, jg, "CA", "Commission of Audit");
	  drawBox(540, 100, jg, "CCAC", "Commission Againts Corruption");
	  drawBox(465, 100, jg, "STPW", "Secretariat for Transport and Public Works");
	  drawBox(390, 100, jg, "SSAC", "Secretariat for Social Affairs and Culture");  
	  drawBox(220, 100, jg, "SS", "Secretariat for Security");
	  drawBox(145, 100, jg, "SEF", "Secretariat for Economy and Finance");
	  drawBox(70, 100, jg, "SAJ", "Secretariat for Administration and Justice");
	  
	  //long horizontal line
	  jg.setColor("#6C9D94");
	  jg.drawLine(5, 80, 500, 80);
	  jg.drawLine(500, 80, 500, 100);
	  jg.drawLine(5, 80, 5, 260);
	  //top vertical lines started from long hr
	  jg.drawLine(105, 80, 105, 100);
	  jg.drawLine(180, 80, 180, 100);
	  jg.drawLine(425, 80, 425, 100);
	  jg.drawLine(500, 80, 500, 100); 
	   
	  jg.drawLine(315, 80, 315, 135); 
	  jg.drawLine(355, 135, 355, 145);  
	  jg.drawLine(275, 135, 355, 135);
	  jg.drawLine(275, 135, 275, 145);
	  
	  jg.drawLine(290, 110, 315, 110);
	  
	  //most left hr
	  jg.drawLine(5, 235, 15, 235);
	  jg.drawLine(5, 210, 15, 210);
	  jg.drawLine(5, 260, 15, 260);
	  //second vertical line and associared horizontal
	  jg.drawLine(80, 120, 80,385);
	  jg.drawLine(80, 385, 90,385);
	  jg.drawLine(80, 360, 90,360);
	  jg.drawLine(80, 335, 90,335);
	  jg.drawLine(80, 310, 90,310);
	  jg.drawLine(80, 285, 90,285);
	  jg.drawLine(80, 260, 90,260);
	  jg.drawLine(80, 235, 90,235);
	  jg.drawLine(80, 210, 90,210);
	  jg.drawLine(80, 185, 90,185);
	  //third vertical line and associared horizontal
	  jg.drawLine(155, 120, 155,460);
	  jg.drawLine(155, 460, 165,460);  
	  jg.drawLine(155, 460, 165,460);
	  jg.drawLine(155, 435, 165,435);
	  jg.drawLine(155, 410, 165,410);
	  jg.drawLine(155, 385, 165,385);
	  jg.drawLine(155, 360, 165,360);
	  jg.drawLine(155, 335, 165,335);
	  jg.drawLine(155, 310, 165,310);
	  jg.drawLine(155, 285, 165,285);
	  jg.drawLine(155, 260, 165,260);
	  jg.drawLine(155, 235, 165,235);
	  jg.drawLine(155, 210, 165,210);
	  jg.drawLine(155, 185, 165,185);
	  //4th vertical line and hr
	  jg.drawLine(230, 120, 230,335);
	  jg.drawLine(230, 335, 240,335);  
	  jg.drawLine(230, 310, 240,310);
	  jg.drawLine(230, 285, 240,285);
	  jg.drawLine(230, 260, 240,260);
	  jg.drawLine(230, 235, 240,235);
	  jg.drawLine(230, 210, 240,210);
	  jg.drawLine(230, 185, 240,185);
	  //5th vertical line and hr
	  jg.drawLine(300, 165, 300,260);
	  jg.drawLine(300, 260, 290,260);
	  jg.drawLine(300, 235, 290,235);   
	  //6th vertical line and hr
	  jg.drawLine(400, 120, 400,460);
	  jg.drawLine(400, 460, 410,460);
	  jg.drawLine(400, 435, 410,435);
	  jg.drawLine(400, 410, 410,410);
	  jg.drawLine(400, 385, 410,385);
	  jg.drawLine(400, 360, 410,360);
	  jg.drawLine(400, 335, 410,335);
	  jg.drawLine(400, 310, 410,310);
	  jg.drawLine(400, 285, 410,285);
	  jg.drawLine(400, 260, 410,260);
	  jg.drawLine(400, 235, 410,235);
	  jg.drawLine(400, 210, 410,210);
	  jg.drawLine(400, 185, 410,185);
	  
	  //7th vertical line and hr
	  jg.drawLine(475, 120, 475,460);  
	  jg.drawLine(475, 460, 485,460);
	  jg.drawLine(475, 435, 485,435);
	  jg.drawLine(475, 410, 485,410);
	  jg.drawLine(475, 385, 485,385);
	  jg.drawLine(475, 360, 485,360);
	  jg.drawLine(475, 335, 485,335);
	  jg.drawLine(475, 310, 485,310);
	  jg.drawLine(475, 285, 485,285);
	  jg.drawLine(475, 260, 485,260);
	  jg.drawLine(475, 235, 485,235);
	  jg.drawLine(475, 210, 485,210);
	  jg.drawLine(475, 185, 485,185);
	  
	   
	  drawBox(240, 145, jg, "SPU", "Unitary Police Service");
	  drawBox(320, 145, jg, "SA", "Macao Customs Service");
	  
	  drawSmallBox(90, 175, jg, "OSAJ", "Office of the Secretary for Admnistration and Justice");
	  drawSmallBox(165, 175, jg, "OSEF", "Office of the Secretary for Economy and Finance");
	  drawSmallBox(240, 175, jg, "OSS", "Office of the Secretary for Security");
	  drawSmallBox(410, 175, jg, "OSSC", "Office of the Secretary for Social Affairs and Culture");
	  drawSmallBox(485, 175, jg, "OSTP", "Office of the Secretary for Transport and Public Works");
	  
	  drawSmallBox(15, 200, jg, "GCS", "Government Information Bureau");
	  drawPartner(90, 200, jg, "SAFP", "Public Administration and Civil Service Bureau");
	  drawSecondPhaseAgency(165, 200, jg, "DSE", "Macao Economic Services");
	  drawSecondPhaseAgency(240, 200, jg, "DSFSM", "Public Security Forces Affairs Bureau");
	  drawSmallBox(410, 200, jg, "SS", "Health Bureau");
	  drawSecondPhaseAgency(485, 200, jg, "DSSOPT", "Land, Public Works and Transport Bureau");
	  
	  drawSmallBox(15, 225, jg, "CEEDS", "Research Centre for Sustainable Development Strategies");
	  drawSecondPhaseAgency(90, 225, jg, "DSAJ", "Legal Affairs Bureau");
	  drawPartner(165, 225, jg, "DSF", "Finance Services Bureau");
	  drawSmallBox(240, 225, jg, "CPSP", "Public Security Police Force");
	  drawSmallBox(410, 225, jg, "DSEJ", "Education and Youth Affairs Bureau");
	  drawSmallBox(485, 225, jg, "DSCC", "Cartography and Cadastre Bureau");
	  
	  drawSmallBox(15, 250, jg, "GPDP", "Gabinete para a Protecao de Dados Perssoais");
	  drawSmallBox(90, 250, jg, "DSI", "Identification Bureau");
	  drawSmallBox(165, 250, jg, "DSEC", "Statistics and Cencus Bureau");
	  drawSmallBox(240, 250, jg, "PJ", "Judiciary Police");
	  drawSmallBox(410, 250, jg, "IC", "Cultural Affairs Bureau");
	  drawSmallBox(485, 250, jg, "MA", "Maritime Administration");
	  
	  drawPartner(15, 275, jg, "FM", "Macao Foundation");
	  drawSmallBox(90, 275, jg, "IO", "Printing Bureau");
	  drawSmallBox(165, 275, jg, "DSAL", "Labour Affairs Bureau");
	  drawSmallBox(240, 275, jg, "EPM", "Macao Prison");
	  drawSecondPhaseAgency(410, 275, jg, "DST", "Macao Government Tourist Office");
	  drawPartner(485, 275, jg, "DSC", "Macao Post");
	  
	  drawSmallBox(15, 300, jg, "METOE", "Macao Economic and Trade Office to the European Union");
	  drawSmallBox(90, 300, jg, "GADI", "International Law Office");
	  drawSmallBox(165, 300, jg, "DICJ", "Gaming Inspection and Coordination Bureau");
	  drawSmallBox(240, 300, jg, "CB", "Fire Services Bureau");
	  drawSmallBox(410, 300, jg, "IAS", "Social Welfare Bureau");
	  drawSmallBox(485, 300, jg, "SMG", "Meteorological and Geogphysical Bureau");
	  
	  drawSmallBox(15, 325, jg, "METOL", "Macao Economic and Trade Office in Lisbon");
	  drawSecondPhaseAgency(90, 325, jg, "IACM", "Civic and  Municipal Affairs Bureau");
	  drawSecondPhaseAgency(165, 325, jg, "FSS", "Social Security Fund");
	  drawSmallBox(240, 325, jg, "ESFSM", "Academy of Public Security Forces");
	  drawSmallBox(410, 325, jg, "ID", "Macao Sport Development Board");
	  drawSmallBox(485, 325, jg, "IH", "Housing Bureau");
	  
	  drawSmallBox(15, 350, jg, "OMSARB", "Office of Macao Special Administrative Region in Beijing");
	  drawSmallBox(90, 350, jg, "CFJJ", "Legal anf Judicial Training Centre");
	  drawSmallBox(165, 350, jg, "PF", "Pension Fund"); 
	  drawSmallBox(410, 350, jg, "TESO", "Tertiary Education Services Centre");
	  drawPartner(485, 350, jg, "DSRT", "Bureau of Telecommunications Regulation");
	  
	  drawSmallBox(15, 375, jg, "METWTO", "Macao Economic and Trade Office to the World Trade Organization");
	  drawSmallBox(90, 375, jg, "LRO", "Law Reform Office");
	  drawSmallBox(165, 375, jg, "CC", "Consumer Council"); 
	  drawPartner(410, 375, jg, "IFT", "Institute for Tourism Study");
	  drawSmallBox(485, 375, jg, "GDI", "Infrastructure Development Office");
	  
	  drawSmallBox(165, 400, jg, "GASPF", "Supporting Office to the Secretariat of China and Portugese"); 
	  drawSmallBox(410, 400, jg, "CCC", "Macao Tourism and Casino Career Center");
	  drawSmallBox(485, 400, jg, "GDSE", "Energy Sector Development Office");
	  
	  drawSmallBox(165, 425, jg, "FIO", "Financial Intelligence Office"); 
	  drawSmallBox(410, 425, jg, "CGPM", "Macao Grand Prix Committee");
	  drawSmallBox(485, 425, jg, "GIT", "Gabinete para as Intra-estrutura de Transportes");
	  
	  drawSmallBox(165, 450, jg, "GRH", "Human Resources Office"); 
	  drawSmallBox(410, 450, jg, "MTPIC", "Macao Tourism Promotion and Information Centre in Portugal");
	  drawSmallBox(485, 450, jg, "CA", "Environmental Protection Committee");
	  
	  drawSmallBox(165, 475, jg, "IPIM", "Macao Trade and Invesment Promotion Institute"); 
	  drawPartner(410, 475, jg, "UM", "University of Macau");
	  drawSmallBox(485, 475, jg, "AACM", "Civil Aviation Authority");
	  
	  drawSmallBox(165, 500, jg, "AMCM", "Macao Monetary Authority"); 
	  drawPartner(410, 500, jg, "IPM", "Macao Polytechnic Institute");
	  
	  jg.paint();  
	}