// polygonzo.js
// Copyright (c) 2008 Ernest Delgado and Michael Geary
// Free Beer and Free Speech License (any OSI license)
// http://freebeerfreespeech.org/
// http://ernestdelgado.com/
// http://mg.to/

//function LatLngToPixel( map, offsetX, offsetY ) {
//	var pi = Math.PI, log = Math.log, round = Math.round, sin = Math.sin,
//		pi180 = pi / 180,
//		offset = 1 << 28,
//		radius = offset / pi,
//		zoom = map.getZoom(),
//		shift = 21 - zoom,
//		bigX0 = lngToBigX( 0 ),
//		bigY0 = latToBigY( 0 ),
//		zeroPoint = map.fromLatLngToDivPixel( new GLatLng(0,0) );
//	offsetX += zeroPoint.x;
//	offsetY  += zeroPoint.y;
//		
//	function lngToBigX( lng ) {
//		return round( offset + radius * lng * pi180 );
//	}
//
//	function latToBigY( lat ) {
//		var s = sin( lat * pi180 );
//		return round( offset - radius * log( ( 1 + s ) / ( 1 - s ) ) / 2 );
//	}
//	
//	return function( lat, lng ) {
//		return {
//			x: ( ( lngToBigX(lng) - bigX0 ) >> shift ) + offsetX,
//			y: ( ( latToBigY(lat) - bigY0 ) >> shift ) + offsetY
//		}
//	}
//}

function PolyGonzo( a ) {
	var map, pane, canvas, ctx;
	
	var msie = /MSIE/.test(navigator.userAgent)  &&  ! window.opera;
	if( msie  &&  ! document.namespaces.pgz_vml_ ) {
		document.namespaces.add( 'pgz_vml_', 'urn:schemas-microsoft-com:vml' );
		document.createStyleSheet().cssText = 'pgz_vml_\\:*{behavior:url(#default#VML)}';
	}
	
	var pg = new GOverlay;
	
	pg.initialize = function( map_ ) {
		map = map_;
		pane = map.getPane( G_MAP_MAP_PANE );
		canvas = document.createElement('canvas');
		canvas.style.position = "absolute";
		if( ! msie ) ctx = canvas.getContext('2d');
		pane.appendChild( canvas );
	};
	
	pg.remove = function() {
		pane.removeChild( canvas );
	};

	pg.redraw = function( b, force ) {
		if( ! force ) return;  // don't redraw unless forced
		
		var mapSize = map.getSize();
		var zoom = map.getZoom();
		var margin = { x: mapSize.width / 3, y: mapSize.height / 3 };
		var canvasSize = { width: mapSize.width + margin.x * 2, height: mapSize.height + margin.y * 2 };
		
		var offset = {
			x: canvas.offsetParent.offsetParent.offsetLeft,
			y: canvas.offsetParent.offsetParent.offsetTop
		};
		
		canvas.width = canvasSize.width;
		canvas.height = canvasSize.height;
		
		canvas.style.width = canvasSize.width + 'px';
		canvas.style.height = canvasSize.height + 'px';	
		
		canvas.style.left = ( - offset.x - margin.x ) + 'px';
		canvas.style.top = ( - offset.y - margin.y ) + 'px';
		
		var offsetX = margin.x + offset.x, offsetY = margin.y + offset.y;
		
		if( msie ) {
			canvas.firstChild && canvas.removeChild( canvas.firstChild );
			
			var vml = [], iVml = 0;
			eachShape( offsetX, offsetY, function( offsetX, offsetY, place, shape, coords, nCoords, fillColor, fillOpacity, strokeColor, strokeOpacity, strokeWidth, round ) {
				
				vml[iVml++] = '<pgz_vml_:shape style="position:absolute;width:10;height:10;" coordorigin="';
				vml[iVml++] = -round(offsetX*10);
				vml[iVml++] = ' ';
				vml[iVml++] = -round(offsetY*10);
				vml[iVml++] = '" coordsize="100 100" path=" m ';
				
				var coord = coords[0];
				vml[iVml++] = round( coord[0] * 10 );
				vml[iVml++] = ',';
				vml[iVml++] = round( coord[1] * 10 );
				
				for( var iCoord = 0, coord;  coord = coords[++iCoord]; ) {
					vml[iVml++] = ' l ';
					vml[iVml++] = round( coord[0] * 10 );
					vml[iVml++] = ',';
					vml[iVml++] = round( coord[1] * 10 );
				}
				
				vml[iVml++] = ' x "><pgz_vml_:stroke color="';
				vml[iVml++] = strokeColor;
				vml[iVml++] = '" opacity="';
				vml[iVml++] = strokeOpacity;
				vml[iVml++] = '" joinstyle="miter" miterlimit="10" endcap="flat" weight="';
				vml[iVml++] = strokeWidth;
				vml[iVml++] = 'px" /><pgz_vml_:fill color="';
				vml[iVml++] = fillColor;
				vml[iVml++] = '" opacity="';
				vml[iVml++] = fillOpacity;
				vml[iVml++] = '" /></pgz_vml_:shape>';
			});
			vml = vml.join('');
			log( 'joined VML' );
			
			//log( htmlEscape( vml.join('') ) );
			var el = canvas.ownerDocument.createElement('div');
			el.style.width =  canvas.clientWidth + 'px';
			el.style.height = canvas.clientHeight + 'px';
			el.style.overflow = 'hidden';
			el.style.position = 'absolute';
			canvas.appendChild( el );
			el.insertAdjacentHTML( "beforeEnd", '<div>' + vml/*.join('')*/ + '</div>' );
			log( 'inserted VML' );
		}
		else {
			ctx.clearRect( 0, 0, canvasSize.width, canvasSize.height );
			eachShape( offsetX, offsetY, function( offsetX, offsetY, place, shape, coords, nCoords, fillColor, fillOpacity, strokeColor, strokeOpacity, strokeWidth, round ) {
				var c = ctx;
				c.beginPath();
				
				var coord = coords[0];
				c.moveTo( round( coord[0] + offsetX ) + .5, round( coord[1] + offsetY ) + .5 );
				
				for( var iCoord = 0, coord;  coord = coords[++iCoord]; ) {
					c.lineTo( round( coord[0] + offsetX ) + .5, round( coord[1] + offsetY ) + .5 );
				}
				c.closePath();
				
				c.globalAlpha = strokeOpacity;
				c.strokeStyle = strokeColor;
				c.lineWidth = '' + strokeWidth;
				c.stroke();
				
				c.globalAlpha = fillOpacity;
				c.fillStyle = fillColor;
				c.fill()
			});
		}
		
		function eachShape( offsetX, offsetY, callback ) {
			var pi = Math.PI, log = Math.log, round = Math.round, sin = Math.sin,
				offset = 1 << 28,
				offset180 = offset / 180,
				pi180 = pi / 180,
				radius = offset / pi,
				zoom = map.getZoom(),
				shift = 21 - zoom,
				zeroPoint = map.fromLatLngToDivPixel( new GLatLng(0,0) );
			offsetX += zeroPoint.x;
			offsetY  += zeroPoint.y;
			
			var totalShapes = 0, totalPoints = 0;
			var places = a.places, nPlaces = places.length;
			//nPlaces = 1; ////
			
			for( var iPlace = 0;  iPlace < nPlaces;  ++iPlace ) {
				var place = places[iPlace], shapes = place.shapes, nShapes = shapes.length;
				totalShapes += nShapes;
				//nShapes = 1; ////
				
				var
					fillColor = place.fillColor,
					fillOpacity = place.fillOpacity,
					strokeColor = place.strokeColor,
					strokeOpacity = place.strokeOpacity,
					strokeWidth = place.strokeWidth;
				
				for( var iShape = 0;  iShape < nShapes;  ++iShape ) {
					var shape = shapes[iShape], points = shape.points, nPoints = points.length;
					totalPoints += nPoints;
					var coords = ( shape.coords = shape.coords || [] )[zoom];
					if( ! coords ) {
						coords = shape.coords[zoom] = new Array( nPoints );
						for( var iPoint = -1, point;  point = points[++iPoint]; ) {
							// Maps API code for comparison
							//var dp = map.fromLatLngToDivPixel( new GLatLng( point[1], point[0] ) );
							//coords[iPoint] = [ dp.x - zeroPoint.x, dp.y - zeroPoint.y ];
							
							// Fast code
							var s = sin( point[1] * pi180 );
							coords[iPoint] = [
								point[0] * offset180  >>  shift,
								-radius * log( (1+s)/(1-s) ) / 2  >>  shift
							];
						}
					}
					callback( offsetX, offsetY, place, shape, coords, nPoints, fillColor, fillOpacity, strokeColor, strokeOpacity, strokeWidth, round );
				}
			}
			_log( totalShapes, 'shapes,', totalPoints, 'points' );
		}
	};
	
	return pg;
}
