var map;
var pointMap = {};
pointMap.inflectionLng = -101.9	// the centerpoint of the body
pointMap.isFront = true;
pointMap.mapTypeIndex = 0;
pointMap.markers = {};




var mouth = new GMarker(new GLatLng(70,-90));


// ====== Create the Euclidean Projection for the flat map ======
// == Thanks go to: http://www.econym.demon.co.uk/googlemaps/
// == Constructor ==
function EuclideanProjection(a)
{
  this.pixelsPerLonDegree=[];
  this.pixelsPerLonRadian=[];
  this.pixelOrigo=[];
  this.tileBounds=[];
  var b=256;
  var c=1;
  for(var d=0;d<a;d++)
  {
    var e=b/2;
    this.pixelsPerLonDegree.push(b/360);
    this.pixelsPerLonRadian.push(b/(2*Math.PI));
    this.pixelOrigo.push(new GPoint(e,e));
    this.tileBounds.push(c);
    b*=2;
    c*=2
  }
}

// == Attach it to the GProjection() class ==
EuclideanProjection.prototype=new GProjection();


// == A method for converting latitudes and longitudes to pixel coordinates == 
EuclideanProjection.prototype.fromLatLngToPixel=function(a,b)
{
  var c=Math.round(this.pixelOrigo[b].x+a.lng()*this.pixelsPerLonDegree[b]);
  var d=Math.round(this.pixelOrigo[b].y+(-2*a.lat())*this.pixelsPerLonDegree[b]);
  return new GPoint(c,d);
}

// == a method for converting pixel coordinates to latitudes and longitudes ==
EuclideanProjection.prototype.fromPixelToLatLng=function(a,b,c)
{
  var d=(a.x-this.pixelOrigo[b].x)/this.pixelsPerLonDegree[b];
  var e=-0.5*(a.y-this.pixelOrigo[b].y)/this.pixelsPerLonDegree[b];
  return new GLatLng(e,d,c);
}

// == a method that checks if the y value is in range, and wraps the x value ==
EuclideanProjection.prototype.tileCheckRange=function(a,b,c)
{
  var d=this.tileBounds[b];
  if (a.y<0||a.y>=d) {
    return false;
  }
  if(a.x<0||a.x>=d){
    a.x=a.x%d;
    if(a.x<0){
      a.x+=d;
    }
  }
  return true
}

// == a method that returns the width of the tilespace ==      
EuclideanProjection.prototype.getWrapWidth=function(zoom) 
{
  return this.tileBounds[zoom]*256;
}



function getCustomMapType(name, imagePath)
{
	var copyCollection = new GCopyrightCollection('');
	var copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90, -180), new GLatLng(90, 180)), 0, "&copy;2007 <a href='http://0009.org/'>0009.ORG</a>");
	copyCollection.addCopyright(copyright);

	var tilelayers = [new GTileLayer(copyCollection, 0, 17)];
	tilelayers[0].getTileUrl = CustomGetTileUrl;
	tilelayers[0].imagePath = imagePath;

	var custommap = new GMapType(tilelayers, new EuclideanProjection(18), name, {errorMessage:""});
	return custommap;
}

function getOverlayedMapType(name, imagePath, overlayImagePath)
{
	var copyCollection = new GCopyrightCollection('EasyHex');
	var copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90, -180), new GLatLng(90, 180)), 0, "&copy;2007 <a href='http://0009.org/'>0009.org</a>");
	copyCollection.addCopyright(copyright);

	var tilelayers = [new GTileLayer(copyCollection, 0, 17), new GTileLayer(copyCollection, 0, 17)];
	tilelayers[0].getTileUrl = CustomGetTileUrl;
	tilelayers[0].imagePath = imagePath;
	tilelayers[1].getTileUrl = CustomGetOverlayTileUrl;
	tilelayers[1].imagePath = overlayImagePath;
	tilelayers[1].getOpacity = function () {return 0.4;};

	var custommap = new GMapType(tilelayers, new EuclideanProjection(18), name, {errorMessage:""});
	return custommap;
}



function load() 
{
  if (GBrowserIsCompatible()) 
  {
    // var mouth = new GMarker(new GLatLng(73,-105));
  	var lat = parseInt(document.getElementById("hdLat").value);
  	var lng = parseInt(document.getElementById("hdLng").value);
  	var zoom = parseInt(document.getElementById("hdZoom").value);
    map = new GMap2(document.getElementById("map"));
    map.setCenter(new GLatLng(lat, lng));
    map.enableDoubleClickZoom();
    map.enableContinuousZoom();    
    //map.enableScrollWheelZoom();

  	for (var a=0; a< map.getMapTypes().length; a++)
  	{
  		map.removeMapType(map.getMapTypes()[0]);
  	}

  	// Front types		
  	map.addMapType(getCustomMapType("Front Skin", "front_skin"));
  	map.addMapType(getCustomMapType("Front Muscle", "front_muscle"));
  	map.addMapType(getCustomMapType("Front Skeleton", "front_skeleton"));
  	map.addMapType(getOverlayedMapType("Front Skeleton", "front_skin", "front_skeleton"));
  	map.addMapType(getOverlayedMapType("Front Skeleton", "front_muscle", "front_skeleton"));
	
  	// Back types
    // map.addMapType(getCustomMapType("Back Skin", "back_skin"));
    // map.addMapType(getCustomMapType("Back Muscle", "back_muscle"));
    // map.addMapType(getCustomMapType("Back Skeleton", "back_skeleton"));
    // map.addMapType(getOverlayedMapType("Back Skeleton", "back_skin", "back_skeleton"));
    // map.addMapType(getOverlayedMapType("Back Skeleton", "back_muscle", "back_skeleton"));
	
  	// lop off the last straggling map type.  (can't ever remove the last one, so this one is left over from above)	
  	map.removeMapType(map.getMapTypes()[0]);

  	map.setMapType(map.getMapTypes()[0]);
  	document.getElementById("map").style.backgroundColor="#fff";
    
    GEvent.addListener(map, "moveend", function() 
  		{  
  			var center = map.getCenter();  
        // console.log('center '+center);
  		}
  	);
    
    GEvent.addListener(map, "zoomend", function(oldLevel, newLevel) 
  		{  
    		if (newLevel < 1)
  			{
  				map.setZoom(1);
  			}
  			if (newLevel > 5)
  			{
  				map.setZoom(5);
  			}
  			UpdateMarkers();
  		}
  	);

    GEvent.addListener(map, "click", function(marker, point) 
  		{  
        // console.log('click '+point);
  			vuduPin = new GMarker(point, {draggable:true, bouncy:true, bounceGravity:.35, clickable:false})
  			map.addOverlay(vuduPin);
        var mess = new Array(
          'May <a href="http://0009.org/zombies?city=portland" target="_blank">Zombies</a> Eat Your Brain',
          'The <a href="http://0009.org/zombies?city=atlanta" target="_blank">undead</a> are coming after you!',
          '<a href="http://0009.org/zombies?city=san francisco" target="_blank">I Curse Thee!</a>',
          'Ouch!',
          'Stop!!',
          'No Really',
          'Shit, God, PLEASE!!!',
          'FUCK YOU!!',
          'If you think you will get away with this, well, you are just wrong!',
          'Mean People Suck! And That Means You!',
          'Not There, anywhere but there',
          'Oooooh, yeah, ok, ok!',
          'Ok, I guess I do deserve this, a little',
          'You Suck!!!!',
          'You\'re Opening a Can of WhoopASS.',
          'D I E ! ! !',
          'Bastard.',
          'OK, You Win, 9 <i>is</i> greater than infinity, Jeez.',
          'Relax Yo.',
          'Oh My, that tickles a little',
          'I\'ll NEVER tell you where the jewels are hidden.',
          'Did I mention yet that THIS REALLY FUCKING HURTS!!!?',
          'Stop Stabbing Me With Needles!',
          'This is TORTURE!',
          'You are a Monster',
          'Just because I am a Voodoo doll DOES NOT mean you can treat me this way',
          'What are you doing?',
          'I know where you LIVE',
          'Do NOT do that again, I\m Serious!',
          'You are So DEAD!',
          'Listen, this VooDoo stuff is really quite dangerous.',
          'I am NOT joking when I say that you\'ll be sorry!'
        );
        var max = mess.length;
        var num = Math.floor((Math.random() * max));

        mouth.openInfoWindowHtml(mess[num]);


  			
        if (marker && marker.point)
        // if (false)
  			{
  			  

			
          // dead

  			}
  		}
  	);


  	if (knownPoints)
  	{
      // DrawMeridians();
  		DrawPoints();
      // AutoCenter();
  	}
	
  	overlay_change(document.getElementById("selOverlayID"));
  	front_change(document.getElementById("selFront"));
  	mapType_change(document.getElementById("selMapTypeID"));
  	
	  if (zoom) map.setZoom(zoom);
	  map.addOverlay(mouth);
	  mouth.openInfoWindowHtml('You wouldn\'t dare');
	  
  } // end browser check
}

function UpdateMarkers()
{
	for (var key in knownPoints)
	{
		UpdateMarker(knownPoints[key].marker);
	}
}

function DrawPoints()
{
	for (var key in knownPoints)
	{
		//hidePointMarker(key);
		
		var point = knownPoints[key];
		DrawPoint(point, point.lat, point.lng, true);
    // DrawPoint(point, point.backlat, point.backlng, false);
	}
}

function DrawPoint(point, lat, lng, isFront)
{
	if (lat && lng && (isFront==pointMap.isFront))
	{
    // var marker = point.marker;
    // if (!marker)
		if (true)
		{
		  
			marker = new GMarker(new GLatLng(lat, lng), {draggable: true});
			


  
  
			// WARNING:  This looks like a guaranteed memory leak here:
			marker.point = point;
			point.marker = marker;
			
      // marker.labelDiv = document.createElement("DIV");
      // marker.labelDiv.className = "markerLabel"
      // var anchor = document.createElement("A");
      // anchor.className = "navlink";
      // marker.labelDiv.appendChild(anchor);
		}
		map.addOverlay(marker);
		marker.openInfoWindowHtml("Stab me into the doll");
	}
}

function UpdateMarker(marker)
{
	if (!marker || !marker.labelDiv || !marker.point)
	{
		return;
	}
	
	if (marker.point.IsVisible())
	{
		marker.labelDiv.style.visibility = "visible";
		if (marker.labelDiv.childNodes.length == 1)
		{
			var nameHtml = marker.point.shortName.replace("-", " ");
			var anchor = marker.labelDiv.childNodes[0];
			//anchor.href="/Points/" + marker.point.shortName.replace("-", "_");
			anchor.innerHTML = nameHtml;
		}
		
		marker.labelDiv.style.position = "absolute";
		var offsetPoint = map.fromLatLngToDivPixel(marker.getPoint());
		var x = (offsetPoint.x > map.getSize().x) ? offsetPoint.x - map.getSize().x : offsetPoint.x
		marker.labelDiv.style.left = x + "px";
		marker.labelDiv.style.top = offsetPoint.y + "px";
		map.getPane(G_MAP_FLOAT_SHADOW_PANE).appendChild(marker.labelDiv);
	}
	else
	{
		marker.labelDiv.style.visibility = "hidden";
	}
}


// function DrawMeridians()
// {
//  var lastPoint = null;
//  var frontVertices;
//  var backVertices;
//  for (var key in knownPoints)
//  {
//    var point = knownPoints[key];
//    if (!point)
//    {
//      continue;
//    }
//    
//    if (lastPoint == null || lastPoint.meridianID != point.meridianID)
//    {
//      DrawMeridianLine(frontVertices, lastPoint, true);
//      DrawMeridianLine(backVertices, lastPoint, false);
//      frontVertices = new Array();
//      backVertices = new Array();
//    }
// 
//    // TODO - fill the gap left when switching from front to back
//    
//    PushVertex(frontVertices, point.lat, point.lng); 
//    PushVertex(backVertices, point.backlat, point.backlng); 
//    lastPoint = point;
//  }
//  DrawMeridianLine(frontVertices, lastPoint, true);
//  DrawMeridianLine(backVertices, lastPoint, false);
// }

function PushVertex(vertices, lat, lng)
{
	if (lat && lng)
	{
		vertices.push(new GLatLng(lat, lng));
	}
}

// function DrawMeridianLine(vertices, point, isFront)
// {
//  var opacity = (isFront == pointMap.isFront) ? 0.6 : 0.15;
//  if (vertices && vertices.length > 1)
//  {
//    var color = "#cccccc";
//    if (point && meridians[point.meridianID])
//    {
//      color = meridians[point.meridianID].color;
//    }
//    var polyline = new GPolyline(vertices, color, 5, opacity );
//    map.addOverlay(polyline);        
// 
//  }
// }

function GetInflectedLng(lng)
{
	var d = pointMap.inflectionLng - lng;
	return 2 * pointMap.inflectionLng - lng;
}


function CustomGetTileUrl(a,b) 
{
	return CustomGetLayerTileUrl(a,b, 0);
}

function CustomGetOverlayTileUrl(a, b)
{
	return CustomGetLayerTileUrl(a,b, 1);
}

function CustomGetLayerTileUrl(a,b, layerIndex) 
{
	var imagePath = map.getCurrentMapType().getTileLayers()[layerIndex].imagePath;
	var z = 17 - b;
	
	if (a.x>13 || a.y>27)
	{
		return "http://www.rootdown.us/tiles/white.gif";
	}
	var f = "http://www.rootdown.us/tiles/" + imagePath + "/" + z + "/" + a.x + "_" + a.y + "_" + z + ".gif";
	
	return f;
}


function setMapType(index)
{
	pointMap.mapTypeIndex = index;
	resetMapType();
	//map.setMapType(map.getMapTypes()[index]);
}

function setMapTypeInner(index)
{
	map.setMapType(map.getMapTypes()[index]);
}

function resetMapType()
{
	var calculatedIndex = parseInt(pointMap.mapTypeIndex);
	if (!pointMap.isFront)
	{
		calculatedIndex += 5;
	}
	setMapTypeInner(calculatedIndex);
}

function redrawOverlays()
{
	var sel = document.getElementById("selOverlayID");
	map.clearOverlays();
	switch(parseInt(sel.options[sel.selectedIndex].value))
	{
		case 0:
      // DrawMeridians();
			DrawPoints();	
			break;
		
		case 1:
      // DrawMeridians(); 
			break;
		
		case 2:
			DrawPoints();	
			break;
		
		case 3:
			break;
	}
	UpdateMarkers();

}

//
// Clicks and Events
//

function zoomIn(overlay, point)
{
	var newZoom = parseInt(map.getZoom()) + 1
	if (point)
	{
		map.setCenter(point, newZoom);
	}
	else
	{
		map.zoomIn();
		//map.setZoom(newZoom);
	}
}

function zoomOut()
{
	map.zoomOut();
	//map.setZoom(parseInt(map.getZoom()) - 1);
}

function overlay_change(sel)
{
	redrawOverlays();
	sel.blur();
}      

function front_change(sel)
{
	pointMap.isFront = (sel.selectedIndex == 0);
	resetMapType();	
	redrawOverlays();
	sel.blur();
}      

function mapType_change(sel)
{
	setMapType(parseInt(sel.options[sel.selectedIndex].value));
	sel.blur();
}      


//
// Objects
//
function AccuPoint(pointID, shortName, marker, lat, lng, backlat, backlng, meridianID)
{
	this.pointID = pointID;
	this.shortName = shortName;
	this.marker = marker;
	this.lat = lat;
	this.lng = lng;
	this.backlat = backlat;
	this.backlng = backlng;
	this.meridianID = meridianID;
	
}
AccuPoint.prototype.IsVisible = function()
{
	if (pointMap.isFront)
	{
		return (this.lat != null);
	}
	else
	{
		return (this.backlat != null);
	}
}

function Meridian(meridianID, name, color)
{
	this.meridianID = meridianID;
	this.name = name;
	this.color = color;
}



//
// Utility
//

var canClearDump = false
function dump(text)
{
	var txt = document.getElementById("txt");
	if (!txt) 
	{
		return;
	}
	
	if (canClearDump)
	{
		txt.value = "";
	}
	txt.value += text + "\r\n";
	
	canClearDump = false;
	setTimeout("canClearDump = true", 100);
}
	
function logMulti()
{
	var line = "";
	var isFirst = true;
	for (var a=0; a<logMulti.arguments.length; a++)
	{
		if (!isFirst)
		{
			line += ", ";
		}
		line += logMulti.arguments[a];
		isFirst = false;
	}

	dump(line);
}
