/*********************************************************
** distance.js: manipulates the mapdistance route finder
** copyright 2004, Andy Allen, All Rights Reserved
*********************************************************/


var map, route, label;
var scaleBegin, scaleEnd;
var controlPanelPosition = 2;
var decimalPlaces = 1, MAX_DECIMALS = 5;
var possibleColors = new Array('#8B008B', '#000000', '#FFFFFF', '#FF0000', '#FFA500', '#FFFF00', '#00FF00', '#0000FF', '#00FFFF');
var pencilColors = new Array(  'white',   'white',   'black',   'white',   'black',   'black',   'black',   'white',   'black');
var markerIx = 0;
var markerColor = possibleColors[markerIx], markerSize = 6;
var showLines = true, lineWeight = 3.5, lineColor = possibleColors[markerIx];
var bPointRemovalMode = false;
var bPointInsertMode = false;
var cursorForPlotting = "url(NewCrossHair.cur)";
//var cursorForPlotting = "crosshair";
var opts = new Array();

function init() {
	label = document.all["distance"];
	map = document.all["mapImage"];
	route = new clickPath();
	
	var clickEvent = new Object();
	clickEvent.clientX = 1;
	clickEvent.clientY = 1;
	scaleBegin = new clickLoc(clickEvent);
	scaleEnd = new clickLoc(clickEvent);
				
	opts = splitUrl(); 
	if (opts['map'] == 'none' || opts['map'] == 'nomap') {
		map.src = 'img/spacer.gif';
	} else if (opts['map']) {
		map.src = opts['map'];
	} else { 
		map.src = "img/bikemap072.jpg";
		writeUnits(25);
		scaleEnd.x = 1011;
	}
	
	if (opts['units']) {
		writeUnits(parseFloat(opts['units']));
	}
	if (opts['scale']) {
		scaleEnd.x = parseFloat(opts['scale']);
		if (!(opts["units"])) writeUnits(1);
	}
	
	document.all["switchColor"].style.background = markerColor;
	moveControlPanel();
}

function calculateDistance() {
	var totDistance = 0;
	for (var i = 1; i < route.path.length; i++) {
		totDistance += parseFloat(pixelsBetween(route.path[i - 1], route.path[i]));
	}
	var labelText = pixelsToUnits(totDistance);
	return labelText.replace('NaN','0');
}

function pixelsBetween(a, b) { 
	try      { 
		var xDiff = a.x - b.x - (b.scrollX - a.scrollX);
		var yDiff = a.y - b.y - (b.scrollY - a.scrollY);
		var dist = Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2));
		return dist;
	}
	catch(e) { return 0; }
}

function findNearestLine(c) {
	if (route.path.length < 2) return Infinity; 
	
	var minDistance = Infinity;	
	var nearestLineOrigin = -1;
	for (var ix = 0; ix < route.path.length - 1; ix++) {
		var distanceFromNearestIntercept = pixelsToLine(c, ix);
		if (distanceFromNearestIntercept < minDistance) {
			minDistance = distanceFromNearestIntercept;
			nearestLineOrigin = ix; 
		}
	}
	return nearestLineOrigin;
}

function pixelsToLine(c, lineIx) {
	var distanceFromNearestIntercept;
	if (route.path.length < 2) return Infinity;
	
	
	var A = route.path[lineIx]; 
	var B = route.path[lineIx + 1];
	var P;
	var r;
	var aX = A.x + A.scrollX;
	var aY = A.y + A.scrollY;
	var bX = B.x + B.scrollX;
	var bY = B.y + B.scrollY;
	var cX = c.x + c.scrollX;
	var cY = c.y + c.scrollY;
	var L = pixelsBetween(A,B);
    
	r = ((aY - cY) * (aY - bY) - (aX - cX) * (bX - aX)) / Math.pow(L,2);
	
	var pEvent = new Object();
	pEvent.clientX = aX + r * (bX - aX);
	pEvent.clientY = aY + r * (bY - aY);
	P = new clickLoc(pEvent);
	P.scrollX = 0;
	P.scrollY = 0;
	
	if (r > 1 || r < 0) {
		if (pixelsBetween(c, A) <= pixelsBetween(c, B))
			P = A;
		else
			P = B;
	}
	
	distanceFromNearestIntercept = pixelsBetween(c, P);
	return distanceFromNearestIntercept;
}

function pixelsToUnits(pixels) { 
	return fixDecimal((pixels * readUnits() / pixelsBetween(scaleBegin, scaleEnd)), decimalPlaces); 
}

function fixDecimal(number, scale) {
	var factor = Math.pow(10,scale);
	var fixedNum = Math.round(factor * number) / factor + "";
	if (fixedNum.lastIndexOf('.') == -1) fixedNum += ".";
	while (fixedNum.length - fixedNum.lastIndexOf('.') < (scale + 1)) fixedNum += "0"; 
	return fixedNum;
}

function adjustDecimal(by) {
	if (decimalPlaces + parseInt(by) >= 0 && decimalPlaces + parseInt(by) <= MAX_DECIMALS) {
		decimalPlaces += parseInt(by);
		label.innerText = calculateDistance();
	}
}

function readUnits() { 
	return document.forms["frm"].elements["units"].value; 
}

function writeUnits(u) { 
	document.forms["frm"].elements["units"].value = u; 
}

function grabScaleBegin() {
	scaleBegin = new clickLoc(event);
	map.onclick=grabScaleEnd;
}

function grabScaleEnd() {
	scaleEnd = new clickLoc(event);
	map.onclick=grabPoint;
	label.innerText = calculateDistance();
}

function grabPoint() { 
	if (bPointRemovalMode) switchFromPointRemovalMode();
	
	var c = new clickLoc(event);
	route.addPoint(c);
	label.innerText = calculateDistance();
	renderPoint(c, showLines);
}

function removeLastPointFromPath() {
	route.path.length--;
	label.innerText = calculateDistance();
}

function switchToPointRemovalMode() {
	switchFromPointInsertMode();
	for (var ix = 0; ix < route.path.length; ix++) {
		var pt = document.getElementById("path_" + ix + "_marker");
		pt.onmouseover = highlightPoint;
		pt.onmouseout = unhighlightPoint;
		pt.onclick = removePoint;
		pt.style.cursor = "hand";
	}
	document.all["switchColor"].style.background = "limegreen";
	document.all["switchColor"].style.color = "black";
	document.all["switchColor"].onclick = switchFromPointRemovalMode;
	document.all["removeIntermediatePoint"].style.background = possibleColors[markerIx];
	document.all["removeIntermediatePoint"].style.color = pencilColors[markerIx];
	document.all["removeIntermediatePoint"].onclick = switchFromPointRemovalMode;
	document.all["insertIntermediatePoint"].style.background = "limegreen";
	document.all["insertIntermediatePoint"].style.color = "black";
	bPointRemovalMode = true;
}

function switchFromPointRemovalMode() {
	if (!(bPointRemovalMode)) return;
	xmlToRoute(routeToXml());
	document.all["switchColor"].style.background = possibleColors[markerIx];
	document.all["switchColor"].style.color = pencilColors[markerIx];
	document.all["switchColor"].onclick = changeRouteColor;
	document.all["removeIntermediatePoint"].style.background = "limegreen";
	document.all["removeIntermediatePoint"].style.color = "black";
	document.all["removeIntermediatePoint"].onclick = switchToPointRemovalMode;
	bPointRemovalMode = false;
}

function switchToPointInsertMode() {
	switchFromPointRemovalMode();
	if (route.path.length < 2) {
		switchFromPointInsertMode();
		return; 
	}
	
	for (var ix = 0; ix < route.path.length; ix++) {
		var pt = document.getElementById("path_" + ix + "_marker");
		pt.onclick = insertPoint;
		if (ix > 0) {
			var ln = document.getElementById("path_" + ix + "_line");
			ln.onclick = insertPoint;
		}
	}
	map.onclick = insertPoint;
	document.all["switchColor"].style.background = "limegreen";
	document.all["switchColor"].style.color = "black";
	document.all["switchColor"].onclick = switchFromPointInsertMode;
	document.all["removeIntermediatePoint"].style.background = "limegreen";
	document.all["removeIntermediatePoint"].style.color = "black";
	document.all["insertIntermediatePoint"].style.background = possibleColors[markerIx];
	document.all["insertIntermediatePoint"].style.color = pencilColors[markerIx];
	document.all["insertIntermediatePoint"].onclick = switchFromPointInsertMode;
	bPointInsertMode = true;
}

function switchFromPointInsertMode() {
	if (!(bPointInsertMode)) return;
	xmlToRoute(routeToXml());
	map.onclick = grabPoint;
	document.all["switchColor"].style.background = possibleColors[markerIx];
	document.all["switchColor"].style.color = pencilColors[markerIx];
	document.all["switchColor"].onclick = changeRouteColor;
	document.all["insertIntermediatePoint"].style.background = "limegreen";
	document.all["insertIntermediatePoint"].style.color = "black";
	document.all["insertIntermediatePoint"].onclick = switchToPointInsertMode;
	bPointInsertMode = false;
}

function highlightPoint() {
	var es = event.srcElement.style;
	es.width = (markerSize * 2);
	es.height = (markerSize * 2);
	es.left = parseInt(es.left) - parseInt(markerSize / 2);
	es.top  = parseInt(es.top) - parseInt(markerSize / 2);
}

function unhighlightPoint() {
	var es = event.srcElement.style;
	es.width = (markerSize);	
	es.height = (markerSize);
	es.left = parseInt(es.left) + parseInt(markerSize / 2);
	es.top  = parseInt(es.top) + parseInt(markerSize / 2);	
}

function removePoint() {
	try {
		var e = event.srcElement;
		var elementId = e.id.substring(e.id.indexOf('_') + 1, e.id.lastIndexOf('_'));
		var routeDoc = new ActiveXObject("MSXML2.DomDocument");
		routeDoc.async = false;
		routeDoc.loadXML(routeToXml());
		var badPoint = routeDoc.selectSingleNode('/route/point[@index="' + elementId + '"]');
		routeDoc.selectSingleNode("/route").removeChild(badPoint);
		xmlToRoute(routeDoc.xml);
		switchToPointRemovalMode();
	} catch(e) {
		alert(e.description);
	}
}

function insertPoint() {
	var c = new clickLoc(event);
	if (route.path.length < 2) {
		switchFromPointInsertMode();
		grabPoint();
		return; 
	}
	
	var nearestLine = findNearestLine(c);
	for (ix = route.path.length; ix > nearestLine; ix--) {
		route.path[ix] = route.path[ix - 1];
	}
	route.path[nearestLine + 1] = c;
	
	xmlToRoute(routeToXml());
	switchToPointInsertMode();
}



function resetRoute() {
	route = new clickPath();
	label.innerText = calculateDistance();
	clearPointsAndLines();
}

function renderPoint(point, withLine, ix) {
	var canvas = document.all["routeMarkers"]
	var markerOffset = parseInt(markerSize - 1);
	var markerTop = point.y - markerOffset + document.body.scrollTop;
	var markerLeft = point.x - markerOffset + document.body.scrollLeft;	
	var newPointIndex = ix || parseInt(route.path.length - 1);
	
	var marker = document.createElement('v:oval');
	marker.id = "path_" + newPointIndex + "_marker";
	marker.style.position = 'absolute';
	marker.style.top = markerTop + 'px';
	marker.style.left = markerLeft + 'px';
	marker.style.width = marker.style.height = markerSize + 'px';
	marker.style.zIndex = '100';
	marker.style.cursor = cursorForPlotting;
	marker.fillcolor = markerColor;
	marker.onclick = grabPoint;
	canvas.appendChild(marker);

	if (withLine && route.path.length > 1) {
		var prevPoint = route.path[newPointIndex - 1];
		var prevTop = prevPoint.y - markerOffset + prevPoint.scrollY;
		var prevLeft = prevPoint.x - markerOffset + prevPoint.scrollX;
		
		var line = document.createElement('v:line');
		line.id = "path_" + parseInt(newPointIndex) + "_line";
		line.style.position = 'absolute';
		line.style.top = '2px';
		line.style.left = '2px';
		line.style.zIndex = '90';
		line.style.cursor = cursorForPlotting;
		line.from = (prevLeft + 1) + 'px,' + (prevTop + 1) + 'px';
		line.to = (markerLeft + 1) + 'px,' + (markerTop + 1) + 'px';
		line.strokecolor = lineColor;
		line.strokeweight = lineWeight + 'px';
		line.onclick = grabPoint;
		
		var stroke = document.createElement('v:stroke');
		stroke.dashstyle = 'solid';
		line.appendChild(stroke);
		canvas.appendChild(line);
	}
}

function removeLastPoint() {
	var pointIx = route.path.length - 1;
	if (pointIx < 0) return;
	var canvas = document.getElementById("routeMarkers");
	
	if (pointIx > 0) {
		var oLineNode = document.getElementById("path_" + pointIx + "_line");
		canvas.removeChild(oLineNode);
	}
	var oMarkerNode = document.getElementById("path_" + pointIx + "_marker");
	canvas.removeChild(oMarkerNode);
	removeLastPointFromPath();		
}

function removeLine(ix) {
	var canvas = document.getElementById("routeMarkers");
	var oBadLine = document.getElementById("path_" + ix + "_line");
	canvas.removeChild(oBadLine);		
}

function drawLine(ix, from, to) {
	var canvas = document.all["routeMarkers"]
	var markerOffset = parseInt(markerSize - 1);
	var fromMarkerTop = from.y - markerOffset + document.body.scrollTop;
	var fromMarkerLeft = from.x - markerOffset + document.body.scrollLeft;
	var toMarkerTop = to.y - markerOffset + document.body.scrollTop;
	var toMarkerLeft = to.x - markerOffset + document.body.scrollLeft;

	var line = document.createElement('v:line');
	line.id = "path_" + ix + "_line";
	line.style.position = 'absolute';
	line.style.top = '2px';
	line.style.left = '2px';
	line.style.zIndex = '90';
	line.style.cursor = cursorForPlotting;
	line.from = (fromMarkerLeft + 1) + 'px,' + (fromMarkerTop + 1) + 'px';
	line.to = (toMarkerLeft + 1) + 'px,' + (toMarkerTop + 1) + 'px';
	line.strokecolor = lineColor;
	line.strokeweight = lineWeight + 'px';
	line.onclick = grabPoint;
	var stroke = document.createElement('v:stroke');
	stroke.dashstyle = 'solid';
	line.appendChild(stroke);
	canvas.appendChild(line);
	
}

function clearPointsAndLines() { 
	document.all["routeMarkers"].innerHTML = ''; 
}

function changeRouteColor() {
	markerIx = ++markerIx % (possibleColors.length);
	markerColor = possibleColors[markerIx];
	lineColor = possibleColors[markerIx];
	document.all["switchColor"].style.background = possibleColors[markerIx];
	document.all["switchColor"].style.color = pencilColors[markerIx];
	xmlToRoute(routeToXml());
}

function moveControlPanel() {
	if (controlPanelPosition == 1) {
		document.all['controls'].style.left = document.body.scrollLeft + 2;
		document.all['controls'].style.top = document.body.scrollTop + 2;
	} else {
		document.all['controls'].style.left = document.body.scrollLeft + document.body.offsetWidth - parseInt(document.all['controls'].style.width) - 23;
		document.all['controls'].style.top = document.body.scrollTop + document.body.offsetHeight - parseInt(document.all['controls'].style.height) - 23;
	}
	positionTextArea();
	setTimeout('moveControlPanel()',500); 
}

function positionTextArea() {
	document.all["xmlTextArea"].style.left = document.body.scrollLeft + 4;
	document.all["xmlTextArea"].style.top = map.height + 4;
	document.all["xmlTextArea"].style.visibility = 'visible';
}

function switchControlPosition() {
	if (controlPanelPosition == 1) {
		controlPanelPosition = 2;
		document.all["changePosition"].innerText = "ë";
	} else {
		controlPanelPosition = 1;
		document.all["changePosition"].innerText = "î";
	}
}

function showHelp() { 
	window.open('othermaps.html', '_helpWindow', "width=600,scrollbars=yes,status=no,toolbar=no,menubar=no,resizable=yes,directories=no");
}

function clickPath() { 
	this.path = new Array();
	this.addPoint = _addPoint;
}

function _addPoint(loc) { 
	this.path[this.path.length] = loc; 
}

function clickLoc(e) {
	this.x = e.clientX || 0;
	this.y = e.clientY || 0;
	this.scrollX = document.body.scrollLeft;
	this.scrollY = document.body.scrollTop;
}

function routeToXml() {
	try {
		var routeDoc = new ActiveXObject("MSXML2.DomDocument");
		routeDoc.async = false;
		
		routeDoc.loadXML('<route/>');
		routeDoc.selectSingleNode("/route").setAttribute("map", document.all["mapImage"].src);
		
		var begin = routeDoc.selectSingleNode("/route").appendChild(routeDoc.createElement("scaleBegin"));
		begin.setAttribute("x", scaleBegin.x);
		begin.setAttribute("scrollX", scaleBegin.scrollX);
		begin.setAttribute("y", scaleBegin.y);
		begin.setAttribute("scrollY", scaleBegin.scrollY);
		
		var end   = routeDoc.selectSingleNode("/route").appendChild(routeDoc.createElement("scaleEnd"));
		end.setAttribute("x", scaleEnd.x);
		end.setAttribute("scrollX", scaleEnd.scrollX);
		end.setAttribute("y", scaleEnd.y);
		end.setAttribute("scrollY", scaleEnd.scrollY);
		
		routeDoc.selectSingleNode("/route").appendChild(routeDoc.createElement("units")).text = readUnits();
		
		routeDoc.selectSingleNode("/route").appendChild(routeDoc.createElement("markerColor")).text = markerColor;
		routeDoc.selectSingleNode("/route").appendChild(routeDoc.createElement("lineColor")).text = lineColor;
		
		for (var i = 0; i < route.path.length; i++) {
			var pt = route.path[i];
			var pathPoint = routeDoc.selectSingleNode("/route").appendChild(routeDoc.createElement("point"));
			pathPoint.setAttribute("index", i);
			pathPoint.setAttribute("x", (pt.x + pt.scrollX));
			pathPoint.setAttribute("y", (pt.y + pt.scrollY));
		}
		
		return routeDoc.xml;
	} catch(e) {
		alert("Error saving route (" + e.description + ").");
	}
}

function xmlToRoute(xml) {
	try {
		var routeDoc = new ActiveXObject("MSXML2.DomDocument");
		routeDoc.async = false;
		routeDoc.loadXML(xml);
		
		resetRoute();
		
		if (routeDoc.selectSingleNode("/route").getAttribute("map")) 
			map.src = routeDoc.selectSingleNode("/route").getAttribute("map"); 
		
		var beginLoc = new clickLoc(new Object());
		beginLoc.x = routeDoc.selectSingleNode("/route/scaleBegin").getAttribute("x");
		beginLoc.y = routeDoc.selectSingleNode("/route/scaleBegin").getAttribute("y");
		beginLoc.scrollX = routeDoc.selectSingleNode("/route/scaleBegin").getAttribute("scrollX");
		beginLoc.scrollY = routeDoc.selectSingleNode("/route/scaleBegin").getAttribute("scrollY");
		scaleBegin = beginLoc;
		
		var endLoc = new clickLoc(new Object());
		endLoc.x = routeDoc.selectSingleNode("/route/scaleEnd").getAttribute("x");
		endLoc.y = routeDoc.selectSingleNode("/route/scaleEnd").getAttribute("y");
		endLoc.scrollX = routeDoc.selectSingleNode("/route/scaleEnd").getAttribute("scrollX");
		endLoc.scrollY = routeDoc.selectSingleNode("/route/scaleEnd").getAttribute("scrollY");
		scaleEnd = endLoc;
		
		writeUnits(routeDoc.selectSingleNode("/route/units").text);
		
		markerColor = (routeDoc.selectNodes("/route/markerColor").length > 0) ? routeDoc.selectSingleNode("/route/markerColor").text : markerColor;
		lineColor = (routeDoc.selectNodes("/route/lineColor").length > 0) ? routeDoc.selectSingleNode("/route/lineColor").text : lineColor;
		var selectedButton;
		if (bPointRemovalMode) {
			selectedButton = document.all["removeIntermediatePoint"];
		}
		else if (bPointInsertMode) {
			selectedButton = document.all["insertIntermediatePoint"];
		}
		else {
			selectedButton = document.all["switchColor"];
		}
		selectedButton.style.background = markerColor;
		for (var i = 0; i < possibleColors.length; i++) {
			if (markerColor == possibleColors[i]) {
				markerIx = i;
				selectedButton.style.color = pencilColors[markerIx];
			}
		}
			
		var pointNodes = routeDoc.selectNodes("/route/point");
		for (var i = 0; i < pointNodes.length; i++) {
			var loc = new clickLoc(new Object());
			loc.x = pointNodes[i].getAttribute("x") - document.body.scrollLeft;
			loc.y = pointNodes[i].getAttribute("y") - document.body.scrollTop;
			route.addPoint(loc);
			renderPoint(loc, showLines);
		}
		label.innerText = calculateDistance();
		
	} catch (e) {
		alert("Error loading route document (" + e.description + ").");
	}
}

function ding() {
	alert(event.srcElement.id);
}
