if(! GBrowserIsCompatible()) 
    alert("Sorry, this page needs a fancier web browser.  We recommend Firefox");

var map;


var mouseX=0;
var mouseY=0;

var unsaved=false;
var editMode=false;

function note_unsaved () {
    if(! unsaved){
	unsaved=true;
	document.getElementById("savebutton").disabled=false;
    }
}

function check_saved () {
    return !unsaved || confirm("Exit without saving changes?");
}

function Track(colour,_points) {
    this.calcBounds = function () { 
	var p=this.points;
	var last=p[0];
	this._km=0;
	for(var i=0; i<p.length; i++) {
	    // a latitude degree is about 110km.  a longitude degree is
	    // 68km at this latitude
	    this._km+=Math.sqrt(Math.pow(68*(p[i].x-last.x),2) +
				Math.pow(110*(p[i].y-last.y),2));
	    last=p[i];
	    if(p[i].x<this.minLng) this.minLng=p[i].x;
	    if(p[i].y<this.minLat) this.minLat=p[i].y;
	    if(p[i].x>this.maxLng) this.maxLng=p[i].x;
	    if(p[i].y>this.maxLat) this.maxLat=p[i].y;
	}
    };

    this.colour=colour;
    this.points=_points;
    this.polyline=null;
    this.sup=Object;
    //this.datasource=url;
    this.minLat=180; this.maxLat=0; this.minLng=170; this.maxLng=-170;
    this._km=0;
    this.center = function () {
	if(this.minLat>this.maxLat) this.calcBounds();
	if(this.minLat>this.maxLat) {
	    // still no sensible answer?  must be an empty map
	    // centre it on hyde park
	    return new GPoint(-0.1525425910949707,51.50307952226442);
	}
	return new GPoint((this.minLng+this.maxLng)/2,
			  (this.minLat+this.maxLat)/2);
    };
    this.size = function () {
	if(this.minLat>this.maxLat) this.calcBounds();
	return new GSize((this.maxLng-this.minLng),
			 (this.maxLat-this.minLat));
    };
    this.km = function () {
	if(this.km<=0) this.calcBounds();
	return this._km;
    };
    this.miles = function () { return this.km()*5.0/8; };
    this.sup();
}
Track.prototype=new Object;

var tracks;

function updateTitle(title) {
    if(editMode)
	document.getElementById("map_title").value=title;
    var n= document.getElementById("title_ro");
    if(n)
	n.replaceChild(document.createTextNode(title), n.firstChild);
}

var data_filename=null;
function loadMap(filename,edit_p) {
    data_filename=filename;
    var request=GXmlHttp.create();
    tracks=new Array(0);
    request.open("GET","http://www.londonskate.com/routes/"+filename,
		 false);
    request.send(null);
    var el = request.responseXML.documentElement;
    var tr = el.getElementsByTagName("track");
    for (var i = 0; i < tr.length; i++) {
	var points=new Array(0);
	p=tr[i].getElementsByTagName("point");
	for(var j=0;j<p.length;j++) {
	    var point = new DPoint
		(parseFloat(p[j].getAttribute("lon")),
		 parseFloat(p[j].getAttribute("lat")));
	    points.push(point);
	    if(p[j].getAttribute("arrow")) {
		point.arrow=true;
	    }
	    if(p[j].hasChildNodes()) {
		point.text=p[j].firstChild.nodeValue;
	    }
	}
	var col=tr[i].getAttribute("colour");
	if(!col) col=tr[i].getAttribute("color");
	tracks.push(new Track(col,points));
    }
    editMode=edit_p;
    if(editMode) showMarkers();
    else drawLines();
    sel_track=tracks[0];
    updateTitle(el.getElementsByTagName("title")[0].firstChild.nodeValue);
    unsaved=false;
    map.centerAndZoom(tracks[0].center(),3);
    if(editMode)
	document.getElementById("savebutton").disabled='true';
}
// this whole ajax thing seems to be so much bollocks at least insofar
// as it doesn't provide a simple way to send xml /to/ the server.
function saveMap () {
    var password=document.getElementById("map_password").value;
    var post=GXmlHttp.create();
    var title=document.getElementById("map_title").value;
    var out="<map><title>"+title+"</title>\n";
    for(var i=0;i<tracks.length;i++) {
	out+='<track colour="'+tracks[i].colour+'">\n';
	var p=tracks[i].points;
	for(var j=0;j<p.length;j++) {
	    out+='<point lon="'+p[j].x+'" lat="'+p[j].y+'"';
	    if(p[j].arrow) {
		out+=' arrow="arrow"';
	    }
	    if(p[j].text) {
		out+=">\n"+p[j].text+"</point>\n";
	    } else {
		out+=' />\n';
	    }
	}
	out+="</track>\n";
    }
    out+="</map>\n";
    post.open("PUT","http://maps.telent.net/filer.cgi/"+data_filename+"?password="+encodeURIComponent(password),
	      false);
    post.send(out);
    alert(post.responseText);
    if(post.status == 200) {
	unsaved=false;
	document.getElementById("savebutton").disabled='true';
    }
}

function makeArrowIcon(direction) {
    var icon=new GIcon();
    icon.image="/images/arrow_"+direction+".png";
//    icon.shadow="shadow.png";
    icon.iconSize=new GSize(32,32);
//    icon.shadowSize=new GSize(18,18);
    icon.iconAnchor=new GPoint(16,16);
    return icon;
}

var arrow_icon=new Array(8);
arrow_icon[0]=makeArrowIcon("w");
arrow_icon[1]=makeArrowIcon("nw");
arrow_icon[2]=makeArrowIcon("n");
arrow_icon[3]=makeArrowIcon("ne");
arrow_icon[4]=makeArrowIcon("e");
arrow_icon[5]=makeArrowIcon("se");
arrow_icon[6]=makeArrowIcon("s");
arrow_icon[7]=makeArrowIcon("sw");

var arrows=new Array(0);
var arrow_overlays=new Array(0);

function showMarkers() {
    map.clearOverlays();
    drawLines();
    for(var j=0;j<tracks.length;j++) {
	var p=tracks[j].points;
	for(var i=0;i<p.length;i++) {
	    var m = new DMarker(p[i],tracks[j],false,p[i].text);
	    map.addOverlay(m);
	}
    }
}

function DMarker(point,track,arrow,popup) {
    this.track=track;
    this.arrow=arrow;
    this.sup=GMarker ; // XMarker;
    this.trackIndex=function () {
	var p=this.track.points;
	for(var i=0;i<p.length;i++) {
	    if(p[i] == this.point) {
		return i;
	    }
	}
	return undefined;
    };   
    this.sup(point);
    // this.sup(point,null,popup && "&nbsp;[]");
}
DMarker.prototype=new GMarker; // XMarker;

function DPoint(x,y,text,arrow) {
    this.text=text;
    // arrow instanceof GMarker; displayed between this point and the next
    this.arrow=arrow; 
    this.sup=GPoint;
    this.sup(x,y);
}
DPoint.prototype=new GPoint;


function showInputWindow() {
    var textthing=document.getElementById("textarea").firstChild;
    var style = document.getElementById("input").style;
    style.left=""+mouseX+"px";
    style.top=""+mouseY+"px";
    style.visibility ='visible';
}
function hideInputWindow() {
    document.getElementById("input").style.visibility='hidden';
}

function showNodeMenu() {
    var style = document.getElementById("menu").style;
    style.left=""+mouseX+"px";
    style.top=""+mouseY+"px";
    document.getElementById("textarea").value=sel_marker.point.text;
    style.visibility ='visible';
}
function hideNodeMenu() {
    document.getElementById("menu").style.visibility='hidden';
}
function changeText() {
    var text=document.getElementById("textarea").value;
    var i=sel_marker.trackIndex();
    m=new DMarker(sel_marker.point,sel_marker.track,sel_marker.arrow,
		  (text.length>0));
    sel_marker.point.text=text;
    sel_track.points[i]=m;
    sel_marker=m;
}

var sel_marker=null;
var sel_track=null;

function findIndexOfMarker(marker) {
    if(marker instanceof DMarker) return marker.trackIndex();
    else return undefined;
}
function deleteMarker() {
    var i= findIndexOfMarker(sel_marker);
    var stuff=sel_marker.track.points;
    if(i) {
	if(stuff[i].arrow) map.removeOverlay(stuff[i].arrow);
	stuff.splice(i,1);
	map.removeOverlay(sel_marker);
	sel_marker=null;
	drawLines();
    }
    hideNodeMenu();
    note_unsaved();
}

function insertMarker() {
    var i= findIndexOfMarker(sel_marker);
    var stuff=sel_marker.track.points;
    var p1=stuff[i];
    var p2=stuff[i+1];
    var x=(p1.x+p2.x)/2;
    var y=(p1.y+p2.y)/2;
    var point=new DPoint(x,y);

    stuff.splice(i+1,0,point);
    map.addOverlay(new DMarker(point,sel_track,false));
    hideNodeMenu();
    sel_marker=null;
    drawLines();
    note_unsaved();
}

function arrowForDirection(dx,dy) {
    var offset=Math.PI;
    var down_p = (dy<0) ;
    dy=Math.abs(dy);
    // javascript atan has a range of -pi/2 to pi/2
    // in atan(x/y) it will threfore be strange when y<0.  So, we must
    // check ourselves for downward-pointing arrows
    // -5pi/8 -> -3pi/8 =>   W
    // -3pi/8 -> -pi/8   => NW / SW
    // -pi/8  -> pi/8  => N / S
    // pi/8 -> 3pi/8  => NE  / SE
    // 3pi/8 -> 5pi/8 -> E
    var index=Math.atan(dx/dy) * 8/Math.PI;
    if(index>3)  return arrow_icon[4];
    if(index>1)  return arrow_icon[(down_p ? 5 : 3)];
    if(index>-1) return arrow_icon[(down_p ? 6 : 2)];
    if(index>-3) return arrow_icon[(down_p ? 7 : 1)];
    return arrow_icon[0] ;
}

function insertArrow (points,i) {
    var p1=points[i];
    var p2=points[i+1];
    var point=new GPoint((p1.x+p2.x)/2, (p1.y+p2.y)/2);
    var icon=arrowForDirection(p2.x-p1.x,p2.y-p1.y);
    var a=new GMarker(point,icon);
    map.addOverlay(a);
    return a;
}

function arrowAtMarker() {
    var p=sel_marker.track.points;
    var i= sel_marker.trackIndex();
    p[i].arrow=insertArrow(p,i);
    hideNodeMenu();
    sel_marker=null;
    note_unsaved();
}

function moveMarker() {
    var i= findIndexOfMarker(sel_marker);
    hideNodeMenu();
    note_unsaved();
}

function drawLine(track) {
    if(track.polyline) map.removeOverlay(track.polyline);
    var distance=0;
    var j=0;
    track.polyline=new GPolyline(track.points,track.colour,5,0.5);
    map.addOverlay(track.polyline);
    var p=track.points;
    var last=p[0];
    for(var i=0;i<p.length;i++) {
    if(p[i].arrow) {
	    if(p[i].arrow instanceof GMarker) map.removeOverlay(p[i].arrow);
	    p[i].arrow=insertArrow(p,i);
	}
	if(p[i].text && !editMode) {
	    var m=new GMarker(p[i]);
	    var text=p[i].text;
	    map.addOverlay(m);
	    GEvent.addListener(m, "click", function() {
		m.openInfoWindowHtml(text);
	    }); 
	}
    }
    track.calcBounds();
}

function drawLines () {
    var distance=0;
    for(var l=0;l<tracks.length;l++) {
	drawLine(tracks[l]);
	distance+=tracks[l].km();
    }
//    document.getElementById("distance").value=Math.round(distance*10)/10;
//    document.getElementById("miles").value=Math.round(distance*50/8)/10;

}

function init() {
    var map_div=document.getElementById("map");
    map_div.onmousemove = function(e) { 
	if(!e) var e=window.event;
	mouseX=e.clientX;
	mouseY=e.clientY;
    }
    map = new GMap(document.getElementById("map"));
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());
    map.addControl(new GScaleControl());
    map.centerAndZoom(new GPoint(-0.15106201171875,51.50286581276556),
		      4);
    
    GEvent.addListener(map, "click",
		       function(overlay,point) {
	if(! editMode) return;
	if(overlay) {
	    sel_marker=overlay;
	    sel_track=sel_marker.track;
	    showNodeMenu();
	} else if(sel_marker) {
	    var i = findIndexOfMarker(sel_marker);
	    sel_marker.point.x=point.x;
	    sel_marker.point.y=point.y;
	    sel_marker.track.points[i].x=point.x;
	    sel_marker.track.points[i].y=point.y;
	    sel_marker.redraw(true);
	    sel_marker=null;
	    hideNodeMenu();
	    note_unsaved();
	} else {
	    note_unsaved();
	    sel_track.points.push(point);
	    map.addOverlay(new DMarker(point,sel_track,false));
	}
	drawLines();
    });
}

function mapResizeEventHandler()
{
	if (window.attachEvent) {
	  window.attachEvent("onresize", mapResize, false);
	  } else {
	  window.addEventListener("resize", mapResize, false);
	}
}

function mapResize()
{
	var width, height;
	width = document.body.clientWidth - 250;
	height = document.getElementById("map_td").clientHeight - 10;
	if (width < 500)
	{
		width = 500;
	}
	document.getElementById("map").style.width = width;
	document.getElementById("map").style.height = "98%";
//	map.onResize();
}

