
//search for TBD to find areas that still need porting!

/*
  to use the jsDraw 2d functions we need three key things:
  1) conversion from lat/lon into pixel position
  2) ability to shift/update all items (or the canvas) when pan occurs,
  and to take into account the canvas pan even on creation
  3) the ability to delete all items on zoom / redraw

need to convert heatcharts so they use the new mutables, labels etc
 */
var usejs=1; //set this to allow use of any jsDraw functions
var heatcolours=[
"#000049","#00006e","#00008c","#0000a6",
"#0000be","#0000d3","#0000e7","#0000ff",
"#0049ff","#006eff","#008cff","#00a6ff",
"#00beff","#00d3ff","#00e7ff","#00fffa",
"#00ffe7","#00ffd3","#00ffbe","#00ffa6",
"#00ff8c","#00ff6e","#00ff49","#00ff00",
"#49ff00","#6eff00","#8cff00","#a6ff00",
"#beff00","#d3ff00","#e7ff00","#faff00",
"#ffe700","#ffd300","#ffbe00","#ffa600",
"#ff8c00","#ff6e00","#ff4900","#ff0000",
"#ff4949","#ff6e6e","#ff8c8c","#ffa6a6",
"#ffbebe","#ffd3d3","#ffe7e7","#ffffff"];

function newPoint(ptlist,ptime,lat,lon,alt,speed)
{
    var pt=new Object();
    pt.time=ptime;
    pt.latitude=lat;
    pt.longitude=lon;
    pt.altitude=alt;
    pt.speed=speed;
    ptlist.push(pt);    
}

function newPath(pathlist,modes,callsign,ft,lt,colour,p1,p2,p3,p4,ptlist)
{
    var newpath=new Object();
    newpath.mode_s=modes;
    newpath.callsign=callsign;
    newpath.firsttime=ft;
    newpath.lasttime=lt;
    newpath.colour=colour;
    newpath.bbox=new Array(p1,p2,p3,p4);
    newpath.points=ptlist;
    pathlist.push(newpath);    
}

function newGRect(map,x1,y1,x2,y2,no_out,col,opac)
{
    var p = new GPolygon([ new GLatLng(x1,y1),new GLatLng(x1,y2),new GLatLng(x2,y2),new GLatLng(x2,y1)],
			 "#FF0000",no_out,no_out,col,opac);
    map.addOverlay(p);
    map.allheats.push(p);
}


function jsPtFromLLPt(map,pt)
{
    var pix=map.fromLatLngToDivPixel(new GLatLng(pt.latitude,pt.longitude));
    return new jsPoint(pix.x,pix.y);
}

function jsPtFromLL(map,ll)
{
    var pix=map.fromLatLngToDivPixel(ll);
    return new jsPoint(pix.x,pix.y);
}

function jsLabel(map,pt,label)
{
    //use map.font in here
    //text,pt,font,color,wrap width,align
    //font object,#hex,wrap width,left/right/center/justify

    var lab=map.jsgr.drawText(label,jsPtFromLLPt(map,pt),map.font,map.labfg);
    map.jslabs.push(lab);
    return lab;
}

function jsGLabel(map,gpt,label,col)
{
    var fcol=(col==1)?map.labbg:map.labfg;
    var lab=map.jsgr.drawText(label,jsPtFromLL(map,gpt),map.font,fcol);
    map.jslabs.push(lab);
    return lab;
}

function jsLLLabel(map,lat,lon,label)
{
    //use map.font in here
    //text,pt,font,color,wrap width,align
    //font object,#hex,wrap width,left/right/center/justify
    var pt=map.fromLatLngToDivPixel(new GLatLng(lat,lon));  
    return jsLabel(map,pt,label);
}

function newLabel(map,lat,lon,label,col) //font,colour etc??
{
    var ob=new Object;
    ob.pt=new GLatLng(lat,lon);
    ob.label=label;
    ob.colour=(col==1)?1:0;
    map.labs.push(ob);
    //use jsGLabel to draw
}

/*
  put a chart of a given type ("col","row","pie") on the map
  at lat,lon with other corner at olat,olon OR size w,h using data
 */
function newChart(map,data,ctype,lat,lon,olat,olon,w,h,title)
{
    var ob=new Object;
    ob.otype="chart"; //so gendiv can choose right methods
    ob.pt=new GLatLng(lat,lon);
    if (olat!=0 || olon!=0)
    {
	ob.opt=new GLatLng(olat,olon);
    }
    else
    {
	ob.opt=null;
    }
    ob.w=w;
    ob.h=h;
    ob.data=data;
    ob.type=ctype;
    ob.title=title;
    map.charts.push(ob);
}

function newImage(map,url,lat,lon,olat,olon,w,h,title,callback,data)
{
    var ob=new Object;
    ob.otype="image"; //so gendiv can choose right methods
    ob.pt=new GLatLng(lat,lon);
    if (olat!=0 || olon!=0)
    {
	ob.opt=new GLatLng(olat,olon);
    }
    else
    {
	ob.opt=null;
    }
    ob.w=w;
    ob.h=h;
    ob.image_url=url;
    ob.title=title;
    ob.callback=callback;
    ob.data=data;
    map.charts.push(ob);
}

function newVideo(map,url,lat,lon,olat,olon,w,h,title)
{
    var ob=new Object;
    ob.otype="video"; //so gendiv can choose right methods
    ob.pt=new GLatLng(lat,lon);
    if (olat!=0 || olon!=0)
    {
	ob.opt=new GLatLng(olat,olon);
    }
    else
    {
	ob.opt=null;
    }
    ob.w=w;
    ob.h=h;
    ob.image_url=url;
    ob.title=title;
    map.charts.push(ob);
}

function labelAtLatLng(map,pt,label,colour,dx,dy)
{
    /* {{{ */

    //offset the point by the drag
    var newpt=new GLatLng(pt.lat()-map.dlat,pt.lng()-map.dlon);
    //convert to pixel
    var p = map.fromLatLngToDivPixel(newpt);

    var dv = document.createElement("DIV");
    var mapDiv=document.getElementById('map_canvas');   

    mapDiv.insertBefore(dv,null);
    dv.style.position = "absolute";
    dv.style.border = "none";
    dv.style.color = colour;
    dv.style.fontFamily='Arial';
    dv.style.fontSize='x-small';
    dv.innerHTML = label;    

    //apply anchor offset
    dv.style.left = (p.x+dx).toString() + "px";
    dv.style.top = (p.y+dy).toString() + "px";

    return dv;

    /* }}} */
}

// TLabel() GMaps API extension copyright 2005-2006 Tom Mangan
// http://gmaps.tommangan.us/tlabel.html
// free for non-commercial use
function TLabel(){}
TLabel.prototype.initialize=function(a){

 this.parentMap=a;
 var b=document.createElement('span');
 b.setAttribute('id',this.id);
 b.innerHTML=this.content;
 document.body.appendChild(b);
 b.style.position='absolute';
 b.style.zIndex=1;
 if(this.percentOpacity){this.setOpacity(this.percentOpacity);}
 this.w = document.getElementById(this.id).offsetWidth;
 this.h = document.getElementById(this.id).offsetHeight;
 if(!this.markerOffset){this.markerOffset=new GSize(0,0);}
 this.setPosition();

 a.alllabels.push(b);

 if (ISGOOGLE)
 {
     //this.mapTray=a.getPane(G_MAP_FLOAT_PANE); //was G_MAP_MAP_PANE (jb)
     //this.mapTray.appendChild(b);
     GEvent.bind(a,"zoomend",this,function(){this.setPosition()});
     GEvent.bind(a,"moveend",this,function(){this.setPosition()});
 }
 else
 {
     //need somewhere else to attach this list (for deletion!)
     //var sp=this.setPosition;
     //var th=this;
     GEvent.addListener(a,"zoomend",function(){this.setPosition()},this);
     GEvent.addListener(a,"moveend",function(){this.setPosition()},this);
     //GEvent.addListener(a,"dragend",function(){this.setPosition()},this);
     //GEvent.addListener(a,"move",function(){this.setPosition()},this);
     //GEvent.addListener(a,"drag",function(){this.setPosition()},this);
 }

}

 TLabel.prototype.evhap=function(a){
     alert("evhap");
 }

 TLabel.prototype.setPosition=function(a){
 if(a){this.anchorLatLng=a;}

 var newpt=new GLatLng(this.anchorLatLng.lat()-this.parentMap.dlat,this.anchorLatLng.lng()-this.parentMap.dlon);

 var b=this.parentMap.fromLatLngToDivPixel(newpt);
 var x=parseInt(b.x);
 var y=parseInt(b.y);
 with(Math){switch(this.anchorPoint){
  case 'topLeft':break;
  case 'topCenter':x-=floor(this.w/2);break;
  case 'topRight':x-=this.w;break;
  case 'midRight':x-=this.w;y-=floor(this.h/2);break;
  case 'bottomRight':x-=this.w;y-=this.h;break;
  case 'bottomCenter':x-=floor(this.w/2);y-=this.h;break;
  case 'bottomLeft':y-=this.h;break;
  case 'midLeft':y-=floor(this.h/2);break;
  case 'center':x-=floor(this.w/2);y-=floor(this.h/2);break;
  default:break;
 }}
 var d=document.getElementById(this.id);
 d.style.left=x-this.markerOffset.width+'px';
 d.style.top=y-this.markerOffset.height+'px';
}
TLabel.prototype.setOpacity=function(b){
 if(b<0){b=0;} if(b>100){b=100;}
 var c=b/100;
 var d=document.getElementById(this.id);
 if(typeof(d.style.filter)=='string'){d.style.filter='alpha(opacity:'+b+')';}
 if(typeof(d.style.KHTMLOpacity)=='string'){d.style.KHTMLOpacity=c;}
 if(typeof(d.style.MozOpacity)=='string'){d.style.MozOpacity=c;}
 if(typeof(d.style.opacity)=='string'){d.style.opacity=c;}
}

GMap2.prototype.addTLabel=function(a){
 a.initialize(this);
}
//GMap2.prototype.removeTLabel=function(a){
// var b=document.getElementById(a.id);
// this.getPane(G_MAP_MAP_PANE).removeChild(b);
// delete(b);
//}

//////////////////////


var _mSvgForced = true;
var _mSvgEnabled = true;

// Subclassed VML/SVG Polyline
//
// Bill Chadwick May 2007
//
// Free for any use
//
// Adds 
//  click, mouseover and mouseout events
//  tooltip
//  dot or dash styling
//  dynamic setting of colour, opacity, weight and dash style  

var BDCCPolylineId;//counter for unique DOM Ids

// Constructor params exactly as GPolyline then a tooltip and dash which must be one of "dot" or "dash" or "solid"

function BDCCPolyline(points, color, weight, opacity, tooltip, dash) {	
    /* {{{  */

    this.tooltip = tooltip;
    this.dash = (dash != null) ? dash : "solid";
    this.color = color;
    this.weight = weight;
    this.opacity = opacity;
    this.lineStyle = 'single';
    
    //make a unique DOM id for this polyline
    if(BDCCPolylineId == null)
        BDCCPolylineId = 0;
    else
        BDCCPolylineId += 1;
    this.domid = "BDCCPolylineId" + BDCCPolylineId.toString();

    this.usesVml = (navigator.userAgent.indexOf("MSIE") != -1);

    GPolyline.call(this,points,color,weight,opacity,{"clickable":false});//call super class constructor 

/* }}} */
}
BDCCPolyline.prototype = new GPolyline(new Array(new GLatLng(0,0)));//subclass from GPolyline

// According to the GMap docs, GPolyline implements the GOverlay interface
// That is it implements the functions initialize, remove, copy and redraw
// Here we add to GPolyline's own implementation of these functions
//

BDCCPolyline.prototype.initialize = function(map) {
    /* {{{  */

    GPolyline.prototype.initialize.call(this,map); //super class
    //Initialise cant be used to cache the SVG path node or its parent svg node as both are recreated in redraw
    //For VML the shape node is recreated in redraw and all shapes have a common parent       
    this.map = map;   

/* }}} */
}

BDCCPolyline.prototype.remove = function() {
    GPolyline.prototype.remove.call(this); //super class
}

BDCCPolyline.prototype.copy = function(map) {
    return new BDCCPolyline(this.points,this.color,this.weight,this.opacity,this.tooltip,this.dash);
}

BDCCPolyline.prototype.redraw = function(force) {
    /* {{{  */

   GPolyline.prototype.redraw.call(this,force); //super class
   var dom = null;
   var i = 1;
   var prnt;
   
   if(this.usesVml){
        try{        
            var shps = document.getElementsByTagName("shape"); 
	  	    i = shps.length-1;
	  	    
	  	    //You could omit parent node checking if you only have one map per document
	  	    //Doing so will give a performance improvement	  	    
        	this.map.getPane(G_MAP_MAP_PANE).parentNode.id = "Cntnr" + this.domid;
        	
        	while((dom == null) && (i >= 0)){

            	dom = shps[i];//assume ours is the most recently added by the superclass redraw
            	prnt = dom.parentNode;
    			while(prnt != null){
                	if (prnt.id == "Cntnr" + this.domid) 
                    	break;
                	else
                    prnt = prnt.parentNode; 
            	}
            	if(prnt == null){
                	i -= 1;
				    dom = null;
			    }
            	else
                	break;
        	}

            if(dom != null){
                //we found our VML node
                if(this.tooltip != null){
                    dom.style.cursor = "help";//to show mouseover 
                    dom.title = this.tooltip;
                }
                dom.id = this.domid;//assign unique DOM id so we can modify attributes later   
            }
        }
        catch (ex)
        {
		    if(BDCCPolylineId == 0)
			    alert("The designer of this Google Maps web page has attempted to use VML graphics without including the necessary header material.");
        }
   }
   else{
        var shps = document.getElementsByTagName("path"); 
	    i = shps.length-1;
	    
	    //You could omit parent node checking if you only have one map per document
	  	//Doing so will give a performance improvement	  	    
        this.map.getPane(G_MAP_MAP_PANE).parentNode.setAttribute("id","Cntnr" + this.domid);

        while((dom == null) && (i >= 0)){
		
            dom = shps[i];//assume ours is the most recently added by the superclass redraw
            prnt = dom.parentNode;
		    while(prnt != null){
                if (prnt.id == "Cntnr" + this.domid)
                    break;
                else
                    prnt = prnt.parentNode; 
            }
            if(prnt == null){
                i -= 1;
		        dom = null;
		    }
            else
                break;
        }

        if(dom != null){
            //we found our SVG node

            if(this.tooltip != null){
                dom.style.cursor = "help";//to show mouseover 
                dom.setAttribute("title",this.tooltip);
            }
            dom.setAttribute("id",this.domid);//assign unique DOM id so we can modify attributes later
            dom.setAttribute("pointer-events","stroke");//only click on the line, not its bounding rectangle
        }
   }
   
   if(this.dredraw)
       window.clearTimeout(this.dredraw); 

   if(dom != null){
   
      //set up the appearance of our polyline
       this.setColor(this.color);
       //this.setDash(this.dash);
       this.setOpacity(this.opacity);
       this.setWeight(this.weight);
       this.setLineStyle(this.lineStyle);
       
       //set up event handlers
       var cclick = GEvent.callback(this,this.onClick);
       var cover = GEvent.callback(this,this.onOver);
       var cout = GEvent.callback(this,this.onOut);
   
       GEvent.clearInstanceListeners(dom);//safety 
       GEvent.addDomListener(dom,"click",function(event){cclick();});
       GEvent.addDomListener(dom,"mouseover",function(){cover();});
       GEvent.addDomListener(dom,"mouseout",function(){cout();});
   }
   else {
        //we could not paint because GMaps has not done its drawing yet, try a bit later
        var credraw = GEvent.callback(this,this.redraw);
        this.dredraw = window.setTimeout(function(force){credraw(true);},200); //the true here is vital
   }

/* }}} */
}

//event handlers
BDCCPolyline.prototype.onClick = function(){
    GEvent.trigger(this,"click");
}
BDCCPolyline.prototype.onOver = function(){
    GEvent.trigger(this,"mouseover");
}
BDCCPolyline.prototype.onOut = function(){
    GEvent.trigger(this,"mouseout");
}

//once the shape has been drawn, we can modify it with these setX functions;

BDCCPolyline.prototype.setColor = function(color) {
    /* {{{  */

    this.color = color;
    var dom = document.getElementById(this.domid); 
    if(!dom)
        return;
    if(this.usesVml){
        dom.stroke.color = this.color;
    }
    else{
        dom.setAttribute("stroke",this.color);
    }

/* }}} */
}
BDCCPolyline.prototype.getColor = function() {
    return this.color;
}

BDCCPolyline.prototype.getDash = function() {
    return this.dash;
}
//for VML only, use single, thinthin, thinthick, thickthin, thickbetweenthin
BDCCPolyline.prototype.setLineStyle = function(ls) {
    /* {{{  */

    this.lineStyle = ls;
    var dom = document.getElementById(this.domid); 
    if(!dom)
        return;
    if(this.usesVml){
        dom.stroke.linestyle = ls;
    }

/* }}} */
}
BDCCPolyline.prototype.getLineStyle = function() {
    return this.lineStyle;
}


BDCCPolyline.prototype.setWeight = function(weight) {
    /* {{{  */

    this.weight = weight;
    var dom = document.getElementById(this.domid); 
    if(!dom)
        return;
    if(this.usesVml){
        dom.stroke.weight = this.weight.toString()+"px";   
    }
    else{
        dom.setAttribute("stroke-width",this.weight.toString()+"px");
    }

/* }}} */
}

BDCCPolyline.prototype.getWeight = function() {
    return this.weight;
}

BDCCPolyline.prototype.setOpacity = function(opacity) {
    /* {{{  */

    this.opacity = opacity;
    var dom = document.getElementById(this.domid); 
    if(!dom)
        return;
    if(this.usesVml){
        dom.stroke.opacity = this.opacity;
    }
    else{
        dom.setAttribute("stroke-opacity",this.opacity);
    }

/* }}} */
}

BDCCPolyline.prototype.getOpacity = function() {
    return this.opacity;
}

// This shows range rings on the map. Interval is user choice or automatic
// Bill Chadwick Jan 2008

// point is the centre or origin of the rings which are drawn with colour, weight (width in pixels) and opacity (0-1). 
// The interval parameter is either
//	1 - null in which case the interval is automatic depending on zoom level, showing several rings on screen
//	2 - A single number specifying a fixed interval between rings in metres
//	3 - An array of ring spacings in metres 
// MaxRings is used for auto and fixed interval to limit the number of rings drawn, not used with an interval array
// if it is null, rings will be drawn to twice the map's diagonal
// if user labels are wanted, labels should be an array of length maxRings or the length of the interval array 
// if interval is an array, colour can be a matching length array

function BdccRangeRings(map, point, colour, weight, opacity, interval, maxRings, labels) {
    /* {{{  */

    this.colour = colour || "#0000FF";
    this.weight = weight || 3;
    this.opacity = opacity || 0.7;
    this.centre = point;
    this.interval = interval;
    this.maxRings = maxRings;
    this.labels = labels;

    this.map = map;
    this.circles = new Array();
    this.divs = new Array();//labels

    this.drawFirst = true;

    this.masterdiv=document.getElementById('map_canvas');   
    
    this.safeRedraw();

/*
    this.lstnMove = null;
    this.lstnStart = null;
    this.lstnType = null;

    //put in event triggers
    // We use the moveend event to trigger the redraw
    var rdrw = GEvent.callback(this,this.safeRedraw );
    this.lstnMove = GEvent.addListener(this.map,"moveend",function(){rdrw ();});

    // We use the map type change event to trigger a redraw too
    var rdrw2 = GEvent.callback(this,this.safeRedraw );
    this.lstnType = GEvent.addListener(this.map,"maptypechanged",function(){rdrw2 ();});

    // And undraw during moves - for speed
    var udrw = GEvent.callback(this,this.unDraw );
    this.lstnStart = GEvent.addListener(this.map,"movestart",function(){udrw ();});

*/

  /* }}} */  
}

BdccRangeRings.prototype.remove = function() {
    /* {{{  */

  	this.unDraw();

/*
	//remove handlers we use to trigger redraw / undraw
	try{
	    if(this.lstnMove != null)
		    GEvent.removeListener(this.lstnMove);
	    if(this.lstnStart != null)
		    GEvent.removeListener(this.lstnStart);
	    if(this.lstnType != null)
		    GEvent.removeType(this.lstnType);
		}
    catch(ex)
    {
    }
*/

/* }}} */
}

BdccRangeRings.prototype.unDraw = function() {
    /* {{{  */

    var div = this.masterdiv; //this.map.getPane(G_MAP_MARKER_SHADOW_PANE);

  try{

	var i = 0;				
	for(i=0; i< this.circles.length; i++)
		this.map.removeOverlay(this.circles[i]);		 			
  }
  catch(e){
  }

  try{
  
      	var i = 0;				
      for(i=0; i< this.divs.length; i++)
  	      div.removeChild(this.divs[i]);		 			
  }
  catch(e){
  }
  this.circles = new Array();	
  this.divs = new Array();	

/* }}} */
}

function gcdistance_km(latlon1,latlon2)
{
    /* {{{ */

    //working on unit sphere
    var lat1=latlon1.latRadians();
    var lon1=latlon1.lngRadians();
    var lat2=latlon2.latRadians();
    var lon2=latlon2.lngRadians();

    var theta=lon2-lon1;
    var dist=0.0;

    try{
	dist=Math.acos((Math.sin(lat1)*Math.sin(lat2))+(Math.cos(lat1)*Math.cos(lat2)*Math.cos(theta)));
    }
    catch(e){}
        
    if (dist<0.0) dist=dist+Math.PI;

    //convert to km
    dist=dist*6355.3;

    return dist;

    /* }}} */
}

// Redraw the rings based on the current projection and zoom level
BdccRangeRings.prototype.safeRedraw = function() {
    /* {{{  */

  //clear old
  this.unDraw();

  var bnds = this.map.getBounds();
  var sz = this.map.getSize();
  var pxDiag = Math.sqrt((sz.width*sz.width) + (sz.height*sz.height));
  var diagKm = gcdistance_km(bnds.getNorthEast(), bnds.getSouthWest());
  var pxPerKm = pxDiag/diagKm;
  var d;//km initial/min interval

  if(this.interval == null)
  {
  	//auto interval
    
	var width = sz.width / pxPerKm ;
  	var height = sz.height / pxPerKm;  
	var ww = Math.max(width,height); 
  
  	if(ww < 1.0)
		d = 0.1;
  	else if(ww < 2.0)
		d = 0.2;
  	else if(ww < 5.0)
		d = 0.5;
  	else if(ww < 10.0)
		d = 1.0;
  	else if(ww < 20.0)
    		d = 2.0;
  	else if(ww < 50.0)
    		d = 5.0;
  	else if(ww < 100.0)
    		d = 10.0;
  	else if(ww < 200.0)
    		d = 20.0;
  	else if(ww < 500.0)
    		d = 50.0;
  	else if(ww < 1000.0)
    		d = 100.0;
  	else if(ww < 2000.0)
    		d = 200.0;
  	else if(ww < 5000.0)
    		d = 500.0;
  	else 
    		d = 1000.0;
  }
  else if (this.interval.constructor.toString().indexOf("Array") == -1)
  	d = this.interval / 1000.0;// to km  
  else
	d = this.interval;//array of distances  	

  
  if (d.constructor.toString().indexOf("Array") == -1){

      var p = (d >= 10.0) ? 0 : 1;//precision for label distances in km

	if(this.maxRings == null){
		//draw the rings to no more than twice the screen diagonal, auto or fixed interval
		// no custom labels as # rings drawn varies
		for(var r = d; (r < (diagKm * 2)); r += d)
 		  this.drawCircle (r ,r.toFixed(p) + "km",this.colour);
	}
	else{
		//draw maxRings rings auto or fixed interval
		var r = d;
		for(var i = 0; i<this.maxRings; i++){
 		  this.drawCircle (r ,(this.labels == null)?r.toFixed(p) + "km":this.labels[i],this.colour); 
		  r += d;
		}
	}
  }
  else{
	// interval array used
	for(var i = 0; i<d.length; i++){
	    var c;
	    if (this.colour.constructor.toString().indexOf("Array") == -1)
	        c = this.colour;
	    else
		  c = this.colour[i];
 	    this.drawCircle (d[i]/1000.0 ,(this.labels == null)?d[i].toFixed(p)+ "km":this.labels[i],c); 
	}

  }

/* }}} */
}  

  // get a new GLatLng distanceMeters away on the compass bearing azimuthDegrees
  // from the GLatLng point - accurate to better than 200m in 140km (20m in 14km) in the UK

BdccRangeRings.prototype.PointAtRangeAndBearing = function (point, distanceMeters, azimuthDegrees) 
{
    /* {{{  */

    var latr = point.latRadians();
    var lonr = point.lngRadians();

    var coslat = Math.cos(latr); 
    var sinlat = Math.sin(latr); 
    var az = azimuthDegrees* Math.PI / 180.0;
    var cosaz = Math.cos(az); 
    var sinaz = Math.sin(az); 
    var dr = distanceMeters / 6378137.0; // distance in radians using WGS84 Equatorial Radius
    var sind = Math.sin(dr); 
    var cosd = Math.cos(dr);

    return new GLatLng(Math.asin((sinlat * cosd) + (coslat * sind * cosaz)) * 180.0 / Math.PI,
		       (Math.atan2((sind * sinaz), (coslat * cosd) - (sinlat * sind * cosaz)) + lonr) * 180.0 / Math.PI); 

/* }}} */
}


BdccRangeRings.prototype.drawCircle = function (rKm, label, colour)
{
    /* {{{  */
  var r = rKm * 1000.0;

  if (r < 0)
	return;

  if (r > (6378137.0 * Math.PI * 2))
	return;

    //var mapDiv = this.map.getPane(G_MAP_MARKER_SHADOW_PANE);
  var mapDiv=this.masterdiv;
  var c;
  var b;
  var pts = new Array();

  // use 40 segment polyline to approximate a circle

  for(b=0; b<=360; b+=9){
      var pt=this.PointAtRangeAndBearing(this.centre,r,b);
      pts.push(pt);


      //if ((b %45 == 0)&&(b!=360)){
      if (b==90){
	  //draw a label every 45 degrees
	  var pt=pts[pts.length-1];

	  var dx;
	  var dy;

	  dx = 3;
	  dy = 0; //-dv.offsetHeight * 0.5;
	  
	  dv=labelAtLatLng(this.map,pt,label,colour,dx,dy);
	  
	  this.divs.push(dv);
      }

  }


  var c = new GPolyline(pts,colour,this.weight,this.opacity);
  this.map.addOverlay(c);
  this.circles.push(c);

/* }}} */
} 

var mtUnique=0;
var glat=0.0;
var glon=0.0;
var altmax=100000;
var gwidthtype=0; //2=none,0=co2,1=pax
var garrdep=3; //1=arrive 2=depart 3=both
var gtod=3; //1=day 2=night 3=24 hours
var onlythis=null; //set this to callsign to display
var extrainfo=null; //goes in text box but not significant
var docurves=0; //set this to draw curves - only active if usejs==1
var speedmin=0;
var speedmax=-1;
var hourmin=0;
var hourmax=0;
var daymin=0;
var daymax=0;
var colourscheme=0; //by flight

function setOffset(map)
{
    var ll1=map.fromContainerPixelToLatLng(new GPoint(0,0));
    var ll2=map.fromDivPixelToLatLng(new GPoint(0,0));
    map.dlat=ll1.lat()-ll2.lat(); //subtract this from point before converting latlng to pixel!
    map.dlon=ll1.lng()-ll2.lng();
    map.xoff=0;
    map.yoff=0;

    if (usejs)
    {
	var pt=map.fromLatLngToDivPixel(ll1);
	map.xoff=-pt.x;
	map.yoff=-pt.y;
	map.jsgr.setOrigin(new jsPoint(-pt.x,-pt.y));
    }
}


function clearLabels(map,full)
{
    if (map.jslabs)
    {
	var mapDiv=document.getElementById('map_canvas');   

	for(var i=0; i<map.jslabs.length; i++)
	{
	    //map.jslabs[i].delete();
	    var ch=map.jslabs[i];
	    mapDiv.removeChild(ch);
	    delete(ch);
	}
	delete(map.jslabs); //the objects

	if (full)
	{
	    delete(map.labs);   //the specs
	    map.labs=new Array;
	}
    }
    map.jslabs=new Array;
}

function clearGenDiv(map,full)
{
    var mapDiv=getMapDiv(map);

    if (map.jscharts)
    {
	//var mapDiv=document.getElementById('map_canvas');   
	for(var i=0; i<map.jscharts.length; i++)
	{
	    var ch=map.jscharts[i];
	    mapDiv.removeChild(ch);
	    if (ch.shape)
	    {
		//mapDiv.removeChild(ch.shape);
		delete(ch.shape);
	    }
	    delete(ch);
	}
	delete(map.jscharts); //the objects

	if (full)
	{
	    delete(map.charts);   //the specs
	    map.charts=new Array;
	}
    }
    map.jscharts=new Array;

    if (map.bubble)
    {
	mapDiv.removeChild(map.bubble);
	delete(map.bubble);	
	map.bubble=null;
    }
}

function undrawMutables(map,unique,iszoom)
{
    //undraw before move makes things look silly

    //lose labels
    if (!INPANE || iszoom) 
    {
	clearLabels(map);
	clearGenDiv(map);
    }

    //undraw
    if (map.rings)
    {
	map.rings.remove();
	map.rings=null;
    }
}

function redrawMutables(map,unique,iszoom)
{
    //redraw things that dont track on their own during move!
    //this is in particular for labels!
    setOffset(map);

    //lose labels
    if (map.labs)
    {
	//redraw
	if (!INPANE)
	{
	    drawJSLabels(map,0);
	}
	else
	{
	    if (iszoom) drawJSLabels(map,0);
	}
    }

    if (map.charts)
    {
	//redraw
	if (!INPANE)
	{
	    drawGenDiv(map,0);
	}
	else
	{
	    if (iszoom) drawGenDiv(map,0);
	}
    }

    //redraw
    var cboGrid = document.getElementById('cboGrid'+unique);
    if (cboGrid && cboGrid.options[cboGrid.selectedIndex].value == 1){
	//put in range rings - make optional?
	map.rings = new BdccRangeRings(map, new GLatLng(glat,glon), "#0000FF",1,0.5,null,null);
    }
}

function redrawMap(map,unique)
{
    /* {{{ */
    //put intelligence in here to redraw the map!
    setOffset(map);

    //undraw
    if(map.rings)
    {
	map.rings.remove();
	map.rings=null
    }

    clearPaths(map);
    clearHeats(map);
    clearLabels(map,1);
    clearGenDiv(map,1);

    //redraw conditions
    
    //rings
    var cboGrid = document.getElementById('cboGrid'+unique);
    if (cboGrid.options[cboGrid.selectedIndex].value == 1){
	//put in range rings - make optional?
	map.rings = new BdccRangeRings(map, new GLatLng(glat,glon), "#0000FF",1,0.5,null,null);
    }

    //depart/arrive
    var wGrid = document.getElementById('wlto'+unique);
    var selval = wGrid.options[wGrid.selectedIndex].value;
    garrdep=selval;

    //time of day
    wGrid = document.getElementById('wtod'+unique);
    selval = wGrid.options[wGrid.selectedIndex].value;
    gtod=selval;

    //altitude
    var altfilt = document.getElementById('altfilt'+unique);
    selval = altfilt.options[altfilt.selectedIndex].value;
    altmax=100000;
    if (selval>0 && selval<11)
    {
      altmax=1000*selval;
    }
    else if (selval==11)
    {
      altmax=0;
    }

    //minspeed
    var minspdfilt = document.getElementById('minspdfilt'+unique);
    selval = minspdfilt.options[minspdfilt.selectedIndex].value;
    speedmin=0;
    if (selval>0 && selval<21)
    {
      speedmin=100+10*selval;
    }

    //maxspeed
    var maxspdfilt = document.getElementById('maxspdfilt'+unique);
    selval = maxspdfilt.options[maxspdfilt.selectedIndex].value;
    speedmax=0;
    if (selval>0 && selval<21)
    {
      speedmax=100+10*selval;
    }

    //time
    var minhrfilt = document.getElementById('minhrfilt'+unique);
    selval = minhrfilt.options[minhrfilt.selectedIndex].value;
    hourmin=0;
    if (selval>0 && selval<=24)
    {
	hourmin=selval*100;
    }    

    var maxhrfilt = document.getElementById('maxhrfilt'+unique);
    selval = maxhrfilt.options[maxhrfilt.selectedIndex].value;
    hourmax=0;
    if (selval>0 && selval<=25)
    {
	hourmax=selval*100;
	if (selval==25) hourmin=2359;
    }    

    var mindayfilt = document.getElementById('mindayfilt'+unique);
    selval = mindayfilt.options[mindayfilt.selectedIndex].value;
    daymin=0;
    if (selval>0 && selval<=31)
    {
	daymin=selval;
    }    

    var maxdayfilt = document.getElementById('maxdayfilt'+unique);
    selval = maxdayfilt.options[maxdayfilt.selectedIndex].value;
    daymax=0;
    if (selval>0 && selval<=31)
    {
	daymax=selval;
    }    

    var colourby = document.getElementById('colourby'+unique);
    colourscheme = parseInt(colourby.options[colourby.selectedIndex].value);

    //markers
    wGrid = document.getElementById('wmark'+unique);
    selval = wGrid.options[wGrid.selectedIndex].value;

    map.domarkers=selval;
	
    //redraw
    drawGenDiv(map,1);
    drawPaths(map,map.paths,map.domarkers);

    //heatcharts
    wGrid = document.getElementById('wheat'+unique);
    selval = wGrid.options[wGrid.selectedIndex].value;

    if (selval==1) 
      heatmap(map);

    if (selval==2)
      heightmap(map);

    /* }}} */
}

//deleted all control stuff
//bits for radar maps
function rmMapTypeControl(selrings,selpaths,selweight,sellto,seltod,selheat,user) {
    /* {{{  */
    if (mtUnique == null)
        mtUnique = 0;
    else
        mtUnique += 1;
    this.unique = mtUnique.toString();
    this.selrings=selrings;
    this.selpaths=selpaths;
    this.selweight=selweight;
    this.sellto=sellto;
    this.seltod=seltod;
    this.selheat=selheat;

    if (!user)
	user="flightpaths";

    this.user=user;
    /* }}} */
}

rmMapTypeControl.prototype = new GControl();

rmMapTypeControl.prototype.initialize = function(map) {
    /* {{{  */

    /*
      dont seem to be able to remove the rings if they were on before swap to satellite view      
     */
    if (usejs)
    {
	var mapDiv=document.getElementById('map_canvas');   
	var gr=new jsGraphics(mapDiv);
	map.jsgr=gr;
	//family,weight,size,style,variant
	//fontname,bold etc,"small"/%/size,normal/italic/oblique,normal/small-caps
	map.font=new jsFont("arial","bolder"); 
	map.bfont=new jsFont("arial","900"); 
	map.labfg=new jsColor("#000000");
	map.labbg=new jsColor("#fffff0");
	map.unique=this.unique;
	map.labs=new Array;
	map.charts=new Array;
    }

      map.rings=null;
      map.dlat=0.0;
      map.dlon=0.0;
      map.xoff=0;
      map.yoff=0;
      map.jslabs=null;
      map.jscharts=null;
      map.gpts=null;
      map.bubble=null;

      var tcontainer = document.createElement("div");
      tcontainer.style.fontFamily='Arial';
      tcontainer.style.fontSize='x-small';

      var hcontainer = document.createElement("div");
      hcontainer.style.fontFamily='Arial';
      hcontainer.style.fontSize='x-small';

      var container = document.createElement("div");
      container.style.fontFamily='Arial';
      container.style.fontSize='x-small';
      container.appendChild(tcontainer);
      container.appendChild(hcontainer);

      if (ISGOOGLE)
      {
	  var cboMap = document.createElement("SELECT");
	  cboMap.id = "cboMap" + this.unique;
	  var mts = map.getMapTypes();
	  for(var i=0;i < mts.length; i++)
	  {
	      var o = document.createElement("OPTION");
	      o.text=mts[i].getName();
	      o.value=i;
	      cboMap.options.add(o); 
	  }

	  /* {{{ map type */

	  cboMap.selectedIndex = 0;
	  cboMap.title ="Select the background map type";
	  container.appendChild(cboMap);

	  var unique = this.unique;
	  var rings = this.rings;

	  GEvent.addDomListener(cboMap, "change", function() {
	      var hadrings=null;
	      if(rings)
	      {
		  map.removeOverlay(rings);
		  hadrings=1;
		  rings=null;
	      };

	      var sel = document.getElementById("cboMap" + unique); 
	      var mt1 = map.getMapTypes()[sel.options[sel.selectedIndex].value];
	      map.setMapType(mt1);

	      if (hadrings)
	      {
		  rings = new BdccRangeRings(map, new GLatLng(glat,glon), "#0000FF",1,0.5,null,17);
		  map.addOverlay(rings);
	      }
	  });

	  /* }}} */
      }


    if (1) //this.user=="flightpaths")
    {
	//the lat,lon tracking box
      var llptr = document.createElement("INPUT");
      llptr.style.width = "200px";
      llptr.type = "Text";
      llptr.readOnly = true;
      llptr.id = "llPtr";
      tcontainer.appendChild(llptr);
      
      GEvent.addListener(map, "mousemove", function(point) {
	      var lat=Math.floor(point.lat()*1000000)/1000000.0;
	      var lng=Math.floor(point.lng()*1000000)/1000000.0;
	      var ws = "lat/lon "+lat+","+lng;
	      if (onlythis) ws=ws+"  Only: "+onlythis;
	      if (extrainfo) ws=ws+" time: "+extrainfo;
	      var ptr = document.getElementById('llPtr');
	      ptr.value = ws;
      });
    }

    if (this.user=="allco2")
    {
      if (this.selweight)
      {
	  /* {{{ co2/pax */

	  var wGrid = document.createElement("SELECT");
	  wGrid.id = "wGrid" + this.unique;
	  var o = document.createElement("OPTION");
	  o.text="Width=% Carbon Dioxide";
	  o.value=0;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Width=% Passengers";
	  o.value=1;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Same width";
	  o.value=2;
	  wGrid.options.add(o); 

	  wGrid.title ="Select value to weight lines";
	  container.appendChild(wGrid);  

	  var unique = this.unique;
	  GEvent.addDomListener(wGrid, "change", function() {
	      clearPaths(map);

	      var wGrid = document.getElementById('wGrid'+unique);
	      var selval = wGrid.options[wGrid.selectedIndex].value;
	      gwidthtype=selval;
	      
	      allarcs(map);
	   });

/* }}} */
      }
    }

    if (this.user=="flightpaths")
    {
	//all the flightpath specifics
      var ptr = document.createElement("INPUT");
      ptr.style.width = "120px";
      ptr.type = "Text";
      ptr.readOnly = true;
      ptr.id = "txtPtr";
      tcontainer.appendChild(ptr);

      if (this.selrings)
      {
	  /* {{{ range rings */

	  var cboGrid = document.createElement("SELECT");
	  cboGrid.id = "cboGrid" + this.unique;
	  var o = document.createElement("OPTION");
	  o.text="No Rings";
	  o.value=0;
	  cboGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Rings";
	  o.value=1;
	  cboGrid.options.add(o); 

	  cboGrid.title ="Select a grid or rings for the map";
	  container.appendChild(cboGrid);  

	  var unique = this.unique;
	  GEvent.addDomListener(cboGrid, "change", function() {
		  redrawMap(map,unique);
	   });

	  /* }}} */
      }

      if (this.sellto)
      {
	  /* {{{ directions */

	  var wGrid = document.createElement("SELECT");
	  wGrid.id = "wlto" + this.unique;
	  var o = document.createElement("OPTION");
	  o.text="Both Directions";
	  o.value=3;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Arrival";
	  o.value=1;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Departure";
	  o.value=2;
	  wGrid.options.add(o); 

	  wGrid.title ="Select Arrival/Departure";
	  container.appendChild(wGrid);  

	  GEvent.addDomListener(wGrid, "change", function() {
		  redrawMap(map,unique);
	   });

	  /* }}} */
      }

      if (this.seltod)
      {
	  /* {{{ time of day */

	  var wGrid = document.createElement("SELECT");
	  wGrid.id = "wtod" + this.unique;
	  var o = document.createElement("OPTION");
	  o.text="24 hours";
	  o.value=3;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Day";
	  o.value=1;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Night";
	  o.value=2;
	  wGrid.options.add(o); 

	  wGrid.title ="Select Time of Day";
	  container.appendChild(wGrid);  

	  var unique = this.unique;
	  GEvent.addDomListener(wGrid, "change", function() {
		  redrawMap(map,unique);
	   });

	  /* }}} */
      }

      if (this.selpaths)
      {
	  /* {{{ height filter */

	  //height filter
	  var altfilt = document.createElement("SELECT");
	  altfilt.id = "altfilt" + this.unique;
	  var o = document.createElement("OPTION");
	  o.text="All Paths";
	  o.value=0;
	  altfilt.options.add(o); 

	  var i;
	  for(i=1;i<11;i++)
	  {
	      var ob = document.createElement("OPTION");
	      //o.text<<"<"<<1000*i<<"ft"; //1000 ft";
	      var alt=i*1000;
	      ob.text="<"+alt.toString()+"ft";
	      ob.value=i;
	      altfilt.options.add(ob); 
	  }

	  var ob = document.createElement("OPTION");
	  ob.text="Path Off";
	  ob.value=11;
	  altfilt.options.add(ob); 

	  altfilt.title ="Select maximum altitude for paths";
	  container.appendChild(altfilt);

	  var unique = this.unique;
	  GEvent.addDomListener(altfilt, "change", function() {
	      onlythis=null;
	      extrainfo=null;
	      redrawMap(map,unique);
	   });

	  /* }}} */
      }  

      if (this.selheat)
      {
	  /* {{{ heatchart */

	  var wGrid = document.createElement("SELECT");
	  wGrid.id = "wheat" + this.unique;
	  var o = document.createElement("OPTION");
	  o.text="Heat Off";
	  o.value=0;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Heat=Flights";
	  o.value=1;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Heat=Min height";
	  o.value=2;
	  wGrid.options.add(o); 

	  wGrid.title ="Select Heat Chart";
	  container.appendChild(wGrid);  

	  var unique = this.unique;
	  GEvent.addDomListener(wGrid, "change", function() {
		  redrawMap(map,unique);
	   });

	  /* }}} */
      }

      if (1)
      {
	  /* {{{ markers */

	  var wGrid = document.createElement("SELECT");
	  wGrid.id = "wmark" + this.unique;
	  var o = document.createElement("OPTION");
	  o.text="Markers off";
	  o.value=0;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Markers on";
	  o.value=1;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Points";
	  o.value=2;
	  wGrid.options.add(o); 
	  var o = document.createElement("OPTION");
	  o.text="Speed+Alt";
	  o.value=3;
	  wGrid.options.add(o); 
	  wGrid.title ="Select Markers";
	  container.appendChild(wGrid);  

	  var unique = this.unique;
	  GEvent.addDomListener(wGrid, "change", function() {
		  redrawMap(map,unique);
	   });

	  /* }}} */
      }

      /* {{{ min speed filter */
      var minspdfilt = document.createElement("SELECT");
      minspdfilt.id = "minspdfilt" + this.unique;
      var o = document.createElement("OPTION");
      o.text="Min Speed";
      o.value=0;
      minspdfilt.options.add(o); 

      var i;
      for(i=1;i<21;i++)
      {
	  var ob = document.createElement("OPTION");
	  var spd=100+i*10;
	  ob.text="spd>"+spd.toString();
	  ob.value=i;
	  minspdfilt.options.add(ob); 
      }

      minspdfilt.title ="Select min speed";
      hcontainer.appendChild(minspdfilt);

      var unique = this.unique;
      GEvent.addDomListener(minspdfilt, "change", function() {
	  redrawMap(map,unique);
       });

      /* }}} */
      /* {{{ max speed filter */
      var maxspdfilt = document.createElement("SELECT");
      maxspdfilt.id = "maxspdfilt" + this.unique;
      var o = document.createElement("OPTION");
      o.text="Max Speed";
      o.value=0;
      maxspdfilt.options.add(o); 

      var i;
      for(i=1;i<21;i++)
      {
	  var ob = document.createElement("OPTION");
	  var spd=100+i*10;
	  ob.text="spd<"+spd.toString();
	  ob.value=i;
	  maxspdfilt.options.add(ob); 
      }

      maxspdfilt.title ="Select max speed";
      hcontainer.appendChild(maxspdfilt);

      var unique = this.unique;
      GEvent.addDomListener(maxspdfilt, "change", function() {
	  redrawMap(map,unique);
       });

      /* }}} */
      /* {{{ min day filter */

      var mindayfilt = document.createElement("SELECT");
      mindayfilt.id = "mindayfilt" + this.unique;
      var o = document.createElement("OPTION");
      o.text="Min Day";
      o.value=0;
      mindayfilt.options.add(o); 

      var i;
      for(i=1;i<31;i++)
      {
	  var ob = document.createElement("OPTION");
	  ob.text="day>"+i.toString();
	  ob.value=i;
	  mindayfilt.options.add(ob); 
      }

      mindayfilt.title ="Select min day";
      hcontainer.appendChild(mindayfilt);

      var unique = this.unique;
      GEvent.addDomListener(mindayfilt, "change", function() {
	  redrawMap(map,unique);
       });

      /* }}} */
      /* {{{ max day filter */
      var maxdayfilt = document.createElement("SELECT");
      maxdayfilt.id = "maxdayfilt" + this.unique;
      var o = document.createElement("OPTION");
      o.text="Max Day";
      o.value=0;
      maxdayfilt.options.add(o); 

      var i;
      for(i=1;i<31;i++)
      {
	  var ob = document.createElement("OPTION");
	  ob.text="day<"+i.toString();
	  ob.value=i;
	  maxdayfilt.options.add(ob); 
      }

      maxdayfilt.title ="Select max day";
      hcontainer.appendChild(maxdayfilt);

      var unique = this.unique;
      GEvent.addDomListener(maxdayfilt, "change", function() {
	  redrawMap(map,unique);
       });

      /* }}} */    
      /* {{{ min hour filter */

      var minhrfilt = document.createElement("SELECT");
      minhrfilt.id = "minhrfilt" + this.unique;
      var o = document.createElement("OPTION");
      o.text="Min Hour";
      o.value=0;
      minhrfilt.options.add(o); 

      var i;
      for(i=1;i<24;i++)
      {
	  var ob = document.createElement("OPTION");
	  var hr=i*100
	  ob.text="hr>"+hr.toString();
	  ob.value=i;
	  minhrfilt.options.add(ob); 
      }

      minhrfilt.title ="Select min hour";
      hcontainer.appendChild(minhrfilt);

      var unique = this.unique;
      GEvent.addDomListener(minhrfilt, "change", function() {
	  redrawMap(map,unique);
       });

      /* }}} */
      /* {{{ max hour filter */
      var maxhrfilt = document.createElement("SELECT");
      maxhrfilt.id = "maxhrfilt" + this.unique;
      var o = document.createElement("OPTION");
      o.text="Max Hour";
      o.value=0;
      maxhrfilt.options.add(o); 

      var i;
      for(i=1;i<25;i++)
      {
	  var ob = document.createElement("OPTION");
	  var hr=i*100
	  ob.text="hr<"+hr.toString();
	  ob.value=i;
	  maxhrfilt.options.add(ob); 
      }

      maxhrfilt.title ="Select max hour";
      hcontainer.appendChild(maxhrfilt);

      var unique = this.unique;
      GEvent.addDomListener(maxhrfilt, "change", function() {
	  redrawMap(map,unique);
       });

      /* }}} */
      /* {{{ colour by filter */
      var colourby = document.createElement("SELECT");
      colourby.id = "colourby" + this.unique;
      var o = document.createElement("OPTION");
      //whole path one colour
      o.text="Colour=Flight";
      o.value=0;
      colourby.options.add(o); 

      var ob = document.createElement("OPTION");
      ob.text="Colour=Time";
      ob.value=1;
      colourby.options.add(ob); 

      var ob = document.createElement("OPTION");
      ob.text="Colour=Carrier";
      ob.value=2;
      colourby.options.add(ob); 

      //each segment a different colour
      var ob = document.createElement("OPTION");
      ob.text="Colour=Height";
      ob.value=3;
      colourby.options.add(ob);

      var ob = document.createElement("OPTION");
      ob.text="Colour=Speed";
      ob.value=4;
      colourby.options.add(ob); 

      colourby.title ="Select colour for paths";
      hcontainer.appendChild(colourby);

      var unique = this.unique;
      GEvent.addDomListener(colourby, "change", function() {
	  redrawMap(map,unique);
       });

      /* }}} */

    }

    /*
      on zoom we seem to get a zoom then a move!
     */

      //do whatever redraws that wont track with zoom/drag automatically eg labels
      GEvent.addListener(map,"movestart",function(){
	//remember where things are meant to be?
	      undrawMutables(map,unique,0);
      });
    
      var unique = this.unique;
      GEvent.addListener(map,"moveend",function(){
	      //restore them
	      redrawMutables(map,unique,0);
      });

      var unique = this.unique;
      GEvent.addListener(map,"zoomend",function(){
	      //restore them
	      undrawMutables(map,unique,1);
	      redrawMutables(map,unique,1);
      });

      map.getContainer().appendChild(container);

      return container;

      /* }}} */
}

// By default, the control will appear in the top left corner of the
// map with 7 pixels of padding.
rmMapTypeControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(7, 7));
}

rmMapTypeControl.prototype.setRingCenter = function(lat,lon) {
    //not sure which "this" needs to have this data, so just make global (ugh)!
    glat=lat;
    glon=lon;
}



//google great circle example
function drawGreatCircle(map, latlng1, latlng2, colour, widthpax, widthco2)
{
    /* {{{ */

    var width=1.0;
    
    if (gwidthtype==0)
    {
	width=widthco2;
    }
    else if (gwidthtype==1)
    {
	width=widthpax;
    }

    var opacity=1.0;
    if (width<1.0)
    {
        opacity=width; //ie min width but fainter
	width=1.0;
    }

    var polyOptions = {geodesic:true};
    var polyline = new GPolyline([latlng1,latlng2], colour, width, opacity, polyOptions);
    map.addOverlay(polyline);
    map.allpaths.push(polyline);

    /* }}} */
}

//draw the paths
function makeMarker(map,pt,label,poly,url,doonly,extra)
{
    var mark1=null;
    if (0) //usejs)
    {
	/*
	  issues: not pretty, not centred, binding does not work, need to clear and redraw on move,#
	  does not delete ...
	 */
	var jpt=jsPtFromLL(map,pt);
	mark1 = map.jsgr.drawImage("smallmarker.png",jpt,8,8);
    }
    else
    {
	mark1 = new GMarker(pt,{title:label});
	map.addOverlay(mark1);
	map.allpaths.push(mark1);
    }

  if (url!="")
  {
      GEvent.addListener(mark1,"click",function(){location.href=url;});
  }
  else if (doonly)
  {
    //need to parse label to get callsign!
    GEvent.addListener(mark1,"click",
		       function(){
			   onlythis=label;
			   extrainfo=extra;
			   redrawMap(map,map.unique);
		       });
  }
}

function makeSmallMarker(map,pt,label,count)
{  
    var baseIcon; 
    if (ISGOOGLE)
    {
	baseIcon= new GIcon(G_DEFAULT_ICON);
    }
    else
    {
	baseIcon= new GIcon();
    }

    //baseIcon.image = "http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png";
    var d=0
    if (count>0)
    {
	baseIcon.image="smallmarker.png";
	if (count>1000) d=10;
	else if (count>100) d=5;
	else if (count>10) d=2;
	else d=-2;
    }
    else
    {
	baseIcon.image="nomarker.png";
    }
    baseIcon.shadow = null; //"http://www.google.com/mapfiles/shadow50.png";
    var s=8+d; //icon is actuaslly 8x8
    var s2=s/2;
    baseIcon.iconSize = new GSize(s,s);
    //baseIcon.shadowSize = new GSize(37, 34);
    baseIcon.iconAnchor = new GPoint(s2, s2);
    baseIcon.infoWindowAnchor = new GPoint(s2, s2);

    var mark1 = new GMarker(pt,{title:label, icon:baseIcon});
    map.addOverlay(mark1);
    map.allpaths.push(mark1);
}

function makePoly(map,pts,label,colour)
{
    //var newpoly = new BDCCPolyline(pts,colour,1,0.9,label);
    var newpoly = new GPolyline(pts,colour,1,0.9);

    map.addOverlay(newpoly);

    map.allpaths.push(newpoly);

    GEvent.addListener(newpoly,"click",function(){alert(newpoly.tooltip);});

    //TBD
    //GEvent.addListener(newpoly,"mouseover",function(){newpoly.setWeight(5);});
    //GEvent.addListener(newpoly,"mouseout",function(){newpoly.setWeight(1);});

    return newpoly;
}

function clearPaths(map)
{
  if (docurves)
  {
      //map.jsgr.clear();
      //not sure how to clear the curves!
  }

  if (!map.allpaths) return;
  var plen=map.allpaths.length;
  var index;
  for ( index=0; index<plen ; index++ )
  {
    var path=map.allpaths[index];
    map.removeOverlay(path);
  }
  map.allpaths=null;
}

function clearHeats(map)
{
    if (!map.allheats) return;
   var plen=map.allheats.length;
   var index;
   for ( index=0; index<plen ; index++ )
   {
       var path=map.allheats[index];
       map.removeOverlay(path);
   }
   map.allheats=null;

   plen=map.alllabels.length;
   for ( index=0; index<plen ; index++ )
   {
       var lab=map.alllabels[index];
       //?? how do you delete this ??
       //map.removeOverlay(path);
       //document.deleteElement(lab);
       delete(lab);
   }
   map.alllabels=null;

}

var INPANE=1; //set this to not recreate on panning

function newDiv(map,chart)
{
    /* {{{ */

    var p1 = map.fromLatLngToDivPixel(chart.pt); //newpt);

    var width,height;
    if (chart.opt!=null)
    {
	var p2 = map.fromLatLngToDivPixel(chart.opt);
	width=Math.abs(p1.x-p2.x);
	height=Math.abs(p1.y-p2.y);
    }
    else
    {
	width=chart.w;
	height=chart.h;
    }

    //pan offset
    if (!INPANE)
    {
	p1.x=p1.x+map.xoff;
	p1.y=p1.y+map.yoff;
    }

    var dv = document.createElement("DIV");
    var mapDiv;
    if (!INPANE)
    {
	mapDiv=document.getElementById('map_canvas');
    }
    else
    {
	mapDiv=getMapDiv(map);
    }
	
    //mapDiv.insertBefore(dv,null);
    mapDiv.appendChild(dv);

    //map.jscharts.push(dv);

    dv.style.position = "absolute";
    dv.style.border = "none";
    //dv.style.color = "red"; //colour;
    //dv.style.fontFamily='Arial';
    //dv.style.fontSize='x-small';
    //dv.innerHTML = label;    

    //apply anchor offset
    dv.style.left = (p1.x-width/2).toString() + "px";
    dv.style.top = (p1.y-height/2).toString() + "px";
    dv.jbwidth=width;
    dv.jbheight=height;
    return dv;

    /* }}} */
}

function drawChart(map,chart)
{
    /* {{{ */

    var dv=newDiv(map,chart)
    var width=dv.jbwidth;
    var height=dv.jbheight;

    var cht;

    switch (chart.type)
    {
	case "col": cht=new google.visualization.ColumnChart(dv); break;
	case "row": cht=new google.visualization.BarChart(dv); break;	    
	case "area": cht=new google.visualization.AreaChart(dv); break;	    
	default: case "pie": cht=new google.visualization.PieChart(dv); break;
    }
	
    cht.draw(chart.data, {legend:'none', min: 0, width: width, height: height, is3D: true, title: chart.title, backgroundColor: {stroke:'none', fill:'none', strokeSize: 1}});

    return dv;
    /* }}} */
}

function getMapDiv(map)
{
    var mapDiv=null;
    if (ISGOOGLE)
    {
	mapDiv=map.getPane(G_MAP_MAP_PANE);
    }
    else
    {
	mapDiv=map.getPane(CM.Map.OVERLAY_PANE);
    }
    return mapDiv;
}

//hacked from jsDraw2d 
function myImage(map,url,point,width,height,pardiv)
{
    /* {{{ */

    var dv=document.createElement("div");

    var mapDiv;

    if (pardiv)
    {
	mapDiv=pardiv;
    }
    else
    {
	mapDiv=getMapDiv(map);    
    }
    var imgDiv=mapDiv.appendChild(dv);

    imgDiv.style.position = "absolute";
    imgDiv.style.border = "none";

    //apply anchor offset
    imgDiv.style.left = point.x.toString() + "px";
    imgDiv.style.top = point.y.toString() + "px";

    var img=imgDiv.appendChild(document.createElement("img"));
    img.src=url;
    img.div=imgDiv;
    imgDiv.img=img;

    if (width!=null)
    {
	width=width.toString()+"px";
	img.style.width=width;
	imgDiv.style.width=width;
    }
    if (height!=null)
    {
	height=height.toString()+"px";
	img.style.height=height;
	imgDiv.style.height=height;
    }
    return imgDiv;

    /* }}} */
}

//hacked from jsDraw2d
function myLabel(map,text,point,font,color,width,align)
{
    /* {{{ */

    //Check arguments for null values
    if(!text || !point) return false;
    
    if(width!=null)
	width=Math.round(width*scale) + "px";

    var dv=document.createElement("div");
    var mapDiv=getMapDiv(map);
    var textDiv=mapDiv.appendChild(dv);

    textDiv.style.position="absolute";
    textDiv.style.left=point.x + "px";
    textDiv.style.top=point.y + "px";

    if(color)
	textDiv.style.color=color.getHex();

    //set font
    if(font)
    {
	if(font.family)
	    textDiv.style.fontFamily=font.family;

	if(font.weight)
	    textDiv.style.fontWeight=font.weight;
        
	if(font.size)
            	textDiv.style.fontSize=font.size;

	if(font.style)
	    textDiv.style.fontStyle=font.style;
        
	if(font.variant)
	    textDiv.style.fontVariant=font.variant;
    }

    if(width)
	textDiv.style.width=width;

    if(align)
	textDiv.style.textAlign=align;
    
    textDiv.innerHTML=text;

    return textDiv;

    /* }}} */
}

function myGLabel(map,gpt,label,col)
{
    var fcol=(col==1)?map.labbg:map.labfg;
    //var lab=map.jsgr.drawText(label,jsPtFromLL(map,gpt),map.font,fcol);
    var lab=myLabel(map,label,jsPtFromLL(map,gpt),map.font,fcol);
    map.jscharts.push(lab);
    return lab;
}

function drawJSLabels(map,iszoom)
{
    /* {{{ */
    if (!INPANE || iszoom) clearLabels(map);

    if (usejs && map.labs)
    {
	var len=map.labs.length;

	for (ptind=0; ptind<len; ptind++)
	{
	    lab=map.labs[ptind];
	    //jsGLabel(map,lab.pt,lab.label,lab.colour);
	    myGLabel(map,lab.pt,lab.label,lab.colour);
	}	 
    }   
    /* }}} */
}

function drawImage(map,chart)
{
    /* {{{ */

    var width,height;
    if (chart.opt!=null)
    {
	var p1 = map.fromLatLngToDivPixel(chart.pt);
	var p2 = map.fromLatLngToDivPixel(chart.opt);
	width=Math.abs(p1.x-p2.x);
	height=Math.abs(p1.y-p2.y);
    }
    else
    {
	width=chart.w;
	height=chart.h;
    }

    var pt=jsPtFromLL(map,chart.pt);
    pt.x-=width/2;
    pt.y-=height/2;

    var shp=null;

    if (chart.data && chart.data.shape)
    {
	//alert("try shape");
	//draw the area shape??
	var ecolour="#FF0000";
	var eweight=1;
	var eopacity=0.8;
	var fcolour="#00FF00";
	var fopacity=0.8;
	var parr=new Array;
	var plen=chart.data.shape.length;
	var index;
	for(index=0; index<plen; index++)
	{
	    var apt=chart.data.shape[index];
	    parr.push(new GLatLng(apt.lat,apt.lon));
	}
	var p = new GPolygon(parr, ecolour, eweight, eopacity, fcolour, fopacity);
	map.addOverlay(p);
	shp=p;
    }

    //makes its own div
    var lab=myImage(map,chart.image_url,pt,width,height);
    lab.chart=chart; //so gets all related info
    lab.map=map;
    lab.shape=shp;

    if (chart.title)
    {
	//really need offset, size, font, colour etc
	//jsGLabel(map,chart.pt,chart.title,"#000000"); //lab.colour);
	myGLabel(map,chart.pt,chart.title,"#000000"); //lab.colour);

	//GEvent.clearInstanceListeners(lab);//safety 
	GEvent.addDomListener(lab,"click",function(event){labelCallback(this,event);}); //cclick();});
	//GEvent.addDomListener(dom,"mouseover",function(){cover();});
	//GEvent.addDomListener(dom,"mouseout",function(){cout();});
	if (shp)
	{
	    shp.main=lab;
	    GEvent.addListener(shp,"click",function(event){labelCallback(this.main,event);});
	}
    }

    return lab;
    /* }}} */
}

/*
  have a tooltip come up (with a delay?) on mouseover and killed on mouseout, with "click to see more details"
  have a panel come up with town name, status, emissions, video etc and a close button (drop shadow off panel?)
 */

function doBubble(map,item,event)
{
    /* {{{ */
    if (!item || !item.chart || !item.chart.data) return;

    //as per newImage ...
    var ob=new Object();
    ob.otype="image"; //so gendiv can choose right methods
    ob.pt=item.chart.pt;
    ob.opt=null;
    ob.w=250;//w;
    ob.h=150;//h;
    if (item.chart.data.video)
    {
	ob.w+=100;
	ob.h+=250;
    }
    ob.image_url="popup.png";//url;
    ob.title=null; //title;
    //map.charts.push(ob);

    map.setCenter(item.chart.pt);

    bubble=drawImage(map,ob);
    map.bubble=bubble;
    bubble.map=map;
    bubble.ob=ob;

    var cpt=new Object;
    cpt.x=(0.65*ob.w); //0.65 determined by the bubble image
    cpt.y=10;
    closer=myImage(map,"closer.png",cpt,8,8,bubble);
    closer.main=bubble;
    closer.img.main=bubble;
    bubble.closer=cpt;
/*
  ideally want to put an event trigger on the X image but that does not seem to work
  when it overlaps with the main image, hence just put the X in the top left and pick
  that up in the event handler for the main bubble (yuk!)
 */
    //GEvent.addDomListener(bubble,"click",function(event){bubbleup(this,event);});
    //GEvent.addListener(closer,"click",function(event){bubbleCallback(this.main,event);});
    GEvent.addDomListener(bubble,"click",function(event){bubbleCallback(this,event);});

    //make a div, then callback to a routine that fills it in
    //also need bubble image, dims, usable size etc
    var core=bubble.appendChild(document.createElement("div"));
    core.style.position="absolute";
    core.style.left="10px";
    core.style.top="10px";
    core.style.width="160px";
    core.style.height="100px";
    core.innerHTML="";

    if (item.chart.callback)
	item.chart.callback(bubble,core,item.chart,event);
    /* }}} */
}

function labelCallback(item,event)
{
    //alert("clicked on "+item.chart.title);
    doBubble(item.map,item,event);
}

function bubbleup(item,event)
{
    alert("bubble up"+item);
    return event;
}

function bubbleCallback(item,event)
{
    var x=event.layerX-item.closer.x;
    var y=event.layerY-item.closer.y;
    //alert("clicked on "+item+" "+x+" "+y);
    //horrid hardwired coords to model where the X is !!
    if ((x>-10 && x<10) && (y>-10 && y<10))
    {
	//ie in top left where the closer is!
	map=item.map;
	var mapDiv=getMapDiv(map);
	mapDiv.removeChild(bubble);
	delete(bubble);
	map.bubble=null;

	//kill off event propagation
	if (!event) var event = window.event;
	event.cancelBubble = true;
	if (event.stopPropagation) event.stopPropagation();
    }
}

function drawVideo(map,chart)
{
    /* {{{ */

    var dv=newDiv(map,chart);
    var width=dv.jbwidth;
    var height=dv.jbheight;

    dv.innerHTML='<embed src="'+chart.image_url+'" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="'+width.toString()+'" height="'+height.toString()+'"></embed>';

    return dv;

    /* }}} */
}

var firstdone=0;
function drawGenDiv(map,notzoom)
{
    /* {{{ */
    if (INPANE && notzoom && firstdone) return;

    clearGenDiv(map);

    if (usejs && map.charts) //acutally more than charts
    {
	var len=map.charts.length;

	for (ptind=0; ptind<len; ptind++)
	{
	    chart=map.charts[ptind];

	    //var newpt=new GLatLng(chart.pt.lat()-map.dlat,chart.pt.lng()-map.dlon);

	    var bit=null;
	    switch(chart.otype)
	    {
		case "chart": bit=drawChart(map,chart); break;
		case "image": bit=drawImage(map,chart); break;
		case "video": bit=drawVideo(map,chart); break;
		    //other sorts here
	    }
	    map.jscharts.push(bit);
	}	 
    }   
    firstdone=1;
    /* }}} */
}

function drawPaths(map,paths,domarker,rway)
{
    /* {{{ */ 

    clearLabels(map);
    map.allpaths=new Array;
    var drawn=0;
    var ptr = document.getElementById('txtPtr');   
    ptr.value="drawing...";

   var plen=paths.length;
   var index;
   var oldcolour=0; //null;
   for ( index=0; index<plen ; index++ )
   {
      var path=paths[index];

      var ptlen=path.points.length;

      first=path.points[0];
      last=path.points[ptlen-1];

      if (onlythis!=null)
      {
	var lab=path.mode_s+" "+path.callsign;
	if (onlythis!=lab) continue;
      }
      
      if (garrdep!=3)
      {
	  //arrive/depart filter
	  if (((first.altitude<last.altitude) && (garrdep==1)) ||
	      ((first.altitude>last.altitude) && (garrdep==2)))
	      continue;
      }

      var time=(first.altitude<last.altitude)?path.firsttime:path.lasttime;
      var timestr=time.toString();
      var hm=parseInt(timestr.substr(8,4));

      if (gtod!=3)
      {
	  //time of day filter
	  //time is an 64 bit int in form yyyyMMdd hhmmssmil
	  //judge day/night by hour of lowest point vs 23:30 - 6:00
	  //get hours and minutes
	  var daynight=(hm>600 && hm<2330)?1:null;
	  if ((gtod==1 && !daynight) || (gtod==2 && daynight))
	      continue;
      }

      if (hourmin!=hourmax)
      {
	  //alert(hourmin+" "+hourmax);
	  if (hm<hourmin || hm>hourmax)
	      continue;
      }

      var daystr=timestr.substr(6,2);
      var day=parseInt(daystr);

      if (daymin!=0 && daymax!=0 && daymax>=daymin)
      {
	  //alert("day "+day+" "+daymin+" "+daymax);
	  if (day<daymin || day>daymax)
	      continue;
      }


      //sanity check is in refresh window ??
      var gpts=new Array();
      var ptind;

      if (altmax>0 || speedmax>0 || speedmin>0)
      {
	  //could lump other filters in here!
	  //alert("speed "+speedmin+" "+speedmax);

	  for ( ptind=0; ptind<ptlen; ptind++ )
	  {
	     var pt=path.points[ptind];
	     var ok=1;

	     //filter by altitude
	     if (altmax>0 && pt.altitude>altmax)
	     {
		 ok=0;
	     }

	     if ((speedmax>0 || speedmin>0) && ((pt.speed<speedmin) || (pt.speed>speedmax)))
	     {
		 ok=0;
	     }

	     if (ok)
	     {
		 gpts.push(pt);
	     }
	  }
      }
      else
      {
	  //may not need to do this copy!
	  for ( ptind=0; ptind<ptlen; ptind++ )
	  {
	     var pt=path.points[ptind];

	     gpts.push(pt);
	  }
      }

      if (gpts.length>0)
      {
	  if (map.gpts) delete(map.gpts);

	  map.gpts=gpts; //to allow redraw of labels

	  var label=path.mode_s+" "+path.callsign;
	  var len=gpts.length;
	  
	  if (docurves)
	  {
	    //use setOrigin and setScale to fit to the map??
	    var col=new jsColor("red"); //or whatever!
	    var pen=new jsPen(col,1); //colour,width
	    var newlist=new Array();
	    for (ptind=0; ptind<len; ptind++)
	    {
	      var pt=gpts[ptind];
	      newlist.push(jsPtFromLLPt(map,pt));
	    }
	    div=map.jsgr.drawCurve(pen,newlist);
	    //map.allpaths.push(div); 
	  }

	  var colour=path.colour; //by flight
	  var byseg=false;
	  switch (colourscheme) 
	  {
	      case 1: //by time
		  var hour=parseInt(timestr.substr(8,2));
		  if (hour<0 || hour>23) {hour=0;}
		  colour=heatcolours[2*hour];
		  break;
	      case 2: //by carrier??
		  var car=path.callsign.substr(0,3);
		  var carno=carriers[car];
		  if (car) colour=heatcolours[(carno*13)%47];
		  else colour=heatcolours[0];
		  break;
	      case 3: //by height
		  byseg=true;
		  break;
	      case 4: //by speed
		  byseg=true;
		  break;
	      default:
		  //alert("case "+colourscheme+typeof(colourscheme));
		  break; //by flight
	  }


	  var poly;
	  var fpoly=null;
	  var lpoly=null;
	  var firstpt=null;
	  var lastpt=null;

	  if (byseg)
	  {
	      for (ptind=1; ptind<len; ptind++)
	      {
		  var newpoly=new Array();
		  pt=gpts[ptind-1];
		  var ll=new GLatLng(pt.latitude,pt.longitude);
		  if (!firstpt) firstpt=ll;
		  newpoly.push(ll);
		  pt=gpts[ptind];
		  ll=new GLatLng(pt.latitude,pt.longitude);
		  lastpt=ll;
		  newpoly.push(ll);

		  var colour=path.colour; //by flight
		  switch (colourscheme) 
		  {
		      case 3: //by height
			  var bin=Math.floor(pt.altitude/200);
			  if (bin>47) {bin=47;}
			  colour=heatcolours[bin];
			  //alert("alt "+pt.altitude+" bin "+bin+" col "+colour);
			  break;
		      case 4: //by speed
			  var bin=Math.floor(pt.speed/10);
			  if (bin>47) {bin=47;}
			  colour=heatcolours[bin];
			  break;
		      default:
			  alert("case "+colourscheme+typeof(colourscheme));
			  break; //by flight
		  }

    		  poly=makePoly(map,newpoly,label,colour);

		  if (!fpoly) fpoly=poly;
		  lpoly=poly;
    	      }
	  }
	  else
	  {
	      var newpoly=new Array();
	      for (ptind=0; ptind<len; ptind++)
	      {
		  pt=gpts[ptind];
		  newpoly.push(new GLatLng(pt.latitude,pt.longitude));
	      }

	      poly=makePoly(map,newpoly,label,colour);
	      fpoly=poly;
	      lpoly=poly;

	      firstpt=newpoly[0];
	      lastpt=newpoly[len-1];
	  }

	  //put in markers at each end
	  if (domarker==1)
	  {	
	      //process out the date!
	      //20090626062351576
	      //yyyymmddhhmmssmmm
	      //     100000000000        
	      //var time=path.firsttime.toString();
	      var year=timestr.substr(0,4);
	      var month=timestr.substr(4,2);
	      var day=timestr.substr(6,2);
	      var hour=timestr.substr(8,2);
	      var min=timestr.substr(10,2);
	      var sec=timestr.substr(12,2);
	      var extra=hour+":"+min+":"+sec+" "+day+"/"+month+"/"+year;

	      makeMarker(map,firstpt,label,fpoly,"",1,extra); //allows "onlythis"
	      makeMarker(map,lastpt,label,lpoly,"",1,extra);
	  }    
	  else if (domarker==2)
	  {
	      for (ptind=0; ptind<len; ptind++)
	      {
		  var pt=gpts[ptind];
		  var npt=new GLatLng(pt.latitude,pt.longitude);
		  var nlabel=label+" "+pt.latitude+","+pt.longitude+" "+
		    pt.altitude+"ft "+pt.speed+"kt "+pt.time;
		  makeMarker(map,npt,nlabel,fpoly,"");
	      }
	  }
	  else if (domarker==3)
	  {
	      //HERE
	      clearLabels(map,1);
	      for (ptind=0; ptind<len; ptind++)
	      {
		  var pt=gpts[ptind];
		  var label=pt.altitude+"ft "+pt.speed+"kt ";
		  newLabel(map,pt.latitude,pt.longitude,label); //font,colour etc?
	      }	      
	      drawJSLabels(map);
	  }

	  if (path.colour!=oldcolour) //in case path broken up
	  {
	      drawn++;	  
	  }

	  oldcolour=path.colour;
      }
   }

   //report things in the text box
   var ws = drawn + " paths drawn";
   ptr.value = ws;

   makeMarker(map,map.rway.start,map.rway.start_label,0,"");
   makeMarker(map,map.rway.end,map.rway.end_label,0,"");

   /* }}} */
}

//removed all postcode stuff


