//# expects js2py
//#####################  Added for PathMap
jzGMap=jz.Module() // create a jz Module
with(jzGMap){      // Use name spave dont indent whole file

importFrom(jz,'_ dof mapf addListener removeObjListeners update at Class IE Log getId urlMerge')

if (window.GUnload) addListener(window,'unload',GUnload)

$.newPolyline = function(seg,style) {
	style=style||{}
	return new GPolyline(seg,style['color'],style['weight'],style['opacity'])
	}
$.boundsOf= function(a,b){
		//return bounds formed by latlng a and b
		//not the same as GBounds(a,b) because a is not min and b is not max
		//could be:
		//var alalt=a.lat(), blat=b.lat(), alng=a.lng(), blng=b.lng()
		//GBounds( GlatLng( min(alat,blat),min(alng,blng) ), GLatLng( max(alat,blat),max(alng,blng) ) )
		var bnds= new GBounds(a)
		bnds.extend(b)
		return bnds
		}

$.distanceTo= function(p1,p2,c){
		// distance from latlng c to segemnt formed by latlng's p1 and p2
		// from: maps.forum.nu/gm_mouse_dist_to_line.html
		// I know, I know I'm working with degress not pixels ... but it works magnitudes are preserved (in higher zooms)
		var abs= Math.abs, pow=Math.pow
		var p1x=p1.lng(), p1y=p1.lat(), p2x=p2.lng(), p2y=p2.lat(), cx=c.lng(), cy=c.lat()
		if (p2x != p1x) {
				var a= (p2y-p1y)/(p2x-p1x), b= p2y - a*p2x
				var distc= abs(a*cx + b - cy / Math.sqrt(a*a+1))
				}
		else var distc= abs(cx-p2x)
		var seglen2=  pow(p2x-p1x,2) + pow(p2y-p1y,2)
		var distcp22= pow(cx-p2x,2) + pow(cy-p2y,2)
		var distcp12= pow(cx-p1x,2) + pow(cy-p1y,2)
		var distc2=   pow(distc,2)
	}

$.unittxt= function(dst){ return (dst/unitscale).toFixed(unitfixed)+unitname },
$.unittxtk= function(dst) { return unittxt(dst*1000.) }
$._units= {
	km:[' km',1000.,1],
	m:[' m',1.,0],
	mi:[' mi',1609.344,1],
	nmi:[' nmi',1852.,1]}
$.setunit= function(unit){
	var newu= _units[unit.toLowerCase()]
	if (newu){
		$.unitname=  newu[0] //suffix
		$.unitscale= newu[1] //scale frommeters
		$.unitfixed= newu[2] //decimals
		}
	}
setunit('km')

$.timetxt= function(time){
	var hrs= Math.floor(Math.round(time/60.)/60.)
	var mn= Math.round(time/60.)%60
	var hrt= hrs?_((hrs>1)?'$h heures':'$h heure',{h:hrs}):''
	var mnt= mn ?_((mn>1)?'$m minutes':'$m minute',{m:mn}):''
	return hrt+(hrt?' ':'')+mnt
	},

$.polyPoximity= function(poly,bnds,findclosest){
		if (!bnds.intersects(poly.getbounds())) return false //if bounds dont intersect thers no chance ...

		var l=poly.getVertexCount(),  bof= boundsOf, ct= bnds.getCenter()
		var a=poly.getVertex(0), hit=false
		for (var i=1; i<l; i++){
			b=poly.getVertex(i)
			if (bnds.intersects(bof(a,b))) {
				//could be close enough calc distance to segment
				segbnds=new GBounds(pt)
				segbnds.extend(poly.getVertex(i-1))
				if (bnds.intersects(segbnds)){
					if (!findclosest) return true
					//get distnace to segment 
					if (dst<cdst){
						//update cdst
						}
					}
				}
			a= b
			}
		if (!hit) return false
		return hit
	} 


$.newEPolyline = function(epts,eseg,style,zIndex) {

//         var encodedPoints = "iuowFf{kbMzH}N`IbJb@zBpYzO{dAvfF{LwDyN`_@`NzKqB|Ec@|L}BKmBbCoPjrBeEdy@uJ`Mn@zoAer@bjA~Xz{JczBa]pIps@de@tW}rCdxSwhPl`XgikCl{soA{dLdAaaF~cCyxCk_Aao@jp@kEvnCgoJ`]y[pVguKhCkUflAwrEzKk@yzCv^k@?mI";
//         var encodedLevels = "B????????????????????????????????????B";
//  
//         var encodedPolyline = new GPolyline.fromEncoded({
// 		color: "#3333cc",
// 		weight: 10,
// 		points: encodedPoints,
// 		levels: encodedLevels,
// 		zoomFactor: 32,
// 		numLevels: 4
// 	});
// 	return encodedPolyline



	var style=style||{}
	var style2={
		color	: style['color'],
		weight	: style['weight'],
		opacity	: style['opacity'],
		points	: epts,
		levels	: eseg,
		zoomFactor: 2,
		numLevels:18
		}
	//Log('createin encoded poly with: ')
	//LogObj(style2)
	var ret=GPolyline.fromEncoded(style2)
	//Log('...got ')
	//LogObj(ret)
	//if (zIndex) ret.setZindex(zIndex)
	return ret
	}

$.newPolygon = function (seg,lineStyle,fillStyle) {
	if (seg[0]!=last(seg)) seg.push(seg[0])
	return newPolyline(seg,lineStyle)
	}

$.newMarker = function (coord,ops) {
	//Prepare parametrers
	ops=ops||{}
	if (typeof ops['icon'] == 'string') ops['icon']=MAPIcons[icon]
	var mOps={icon:ops['icon'], 
		clickable:(ops['href'] || ops['click'] || ops['dblclick'] || ops['hoverContent'] || ( ops.icon && ops.icon.hoverImage) ) ? true:false,
		draggable:( ops['dragstart'] || ops['drag'] || ops['dragend'] ||  ops['draggable']) ? true:false
		}
	// always us myhovers if (typeof ops['hoverContent']==='string') mOps['title']=ops['hoverContent']

	//Allocate(create) object
	var marker=new GMarker(coord,mOps)
	if (ops.title) marker.title=ops.title
	//Apply initializations
	if (mOps['draggable']) marker._jzEnableDrag=true //flag to force enable drag after addOverlay
	if ((typeof ops['hoverContent']==='function')||(typeof ops['hoverContent']==='string')|| ( ops.icon && ops.icon.hoverImage)) {
		if ((typeof ops['hoverContent']==='function')||(typeof ops['hoverContent']==='string')) marker.hoverContent=ops['hoverContent']
		if (ops.icon && ops.icon.hoverImage) {
			marker.hoverImage=ops.icon.hoverImage
			marker.nonHoverImage=ops.icon.image
			}
		GEvent.addListener(marker,'mouseover',function(){showHover(marker)})
		GEvent.addListener(marker,'mouseout',function(){hideHover(marker)})
		}
	if (ops['href']) {
		GEvent.addListener(marker,'click',doNavigate)
		marker.href=ops['href']
		}
	marker.getHoverAnchor=marker.getPoint
	if (ops['debug']) {
		marker.debugName=ops['debug']
		var s=''
		for (var key in mOps) if (typeof mOps[key] != 'function') s+=(key+':'+mOps[key]+', ')
		Log('got debug mode for '+marker.debugName+' mops='+s); //rare case where its required
		var s=''
		//jzCleanup(ops)
		for (var key in ops) s+=(key+':'+(typeof ops[key]=='function'?'function':ops[key])+', ');
		Log('and ops='+s); //rare case where its required
		dof(['resize','click','dblclick','contextmenu','mouseover','mouseout','mousedown','mouseup','dragstart','dragend','drag','remove'],function(event){ 
			 GEvent.addListener(marker,event, new Function('Log("'+event+' on "+this.debugName)'))
			})
		}

	if (ops.jz_doRemoved) marker.jz_doRemoved = ops.jz_doRemoved 
	dof(['click','dblclick','dragstart','drag','dragend','mouseover','mouseout','remove'], function(event){
		if (ops[event]) {
			if (ops['debug']) Log('adding '+event+' listener on '+ops['debug'])
			GEvent.addListener(marker,event,ops[event])
			}
		})
		
	return marker
	}

$.getOffsetPos = function(elem){
	//Log('get Offset Pos')
	var x = 0, y = 0, dx,dy
	while (elem) {
		x += (dx=elem.offsetLeft)
		y += (dy=elem.offsetTop)
		//Log('.. dx='+dx+' dy='+dy+' x='+x+' y='+y+' for '+elem+' pos='+elem.position)
		elem = elem.offsetParent
		//Log('..next elem='+elem)
		}
	var ret={x:x, y:y}
	//Log('..returning: '+ret.x,','+ret.y)
	return ret
	}

$.getPos = function(elem){
	//Log('get Pos')
	var x = 0, y = 0, dx,dy
	while (elem) {
		if (dx=elem.style.top)  x+=parseInt(dx)
		if (dy=elem.style.left) y+=dy
		//Log(' .. dx='+dx+' dy='+dy+' x='+x+' y='+y+' pos= '+elem.style.position+' for elem '+elem)
		elem = elem.parentNode
		}
	var ret={x:x, y:y}
	//Log('..returning: '+ret.x+','+ret.y)
	return ret
	}

$.getClientBounds = function(marker){

	if (!mapDiv) return
	var vMap=mapDiv.vMap

	if (marker.bounds_) { // gota rectangle like object
		var c1 = vMap.fromLatLngToContainerPixel(marker.bounds_.getSouthWest());
		var c2 = vMap.fromLatLngToContainerPixel(marker.bounds_.getNorthEast());
		var b = new GBounds([c1,c2])
		//alert('return bounds='+b)
		return b
		}

	if (marker.getPoint) { //Ok got a marker
	
		var markerPos = vMap.fromLatLngToContainerPixel(marker.getPoint())
		var iconSize = marker.getIcon().iconSize
		var iconAnchor = marker.getIcon().iconAnchor
	
		var left  = markerPos.x - iconAnchor.x
		var right = left+iconSize.width
		var top   = markerPos.y - iconAnchor.y
		var bottom= top + iconSize.height
		return new GBounds([new GPoint(left,top),new GPoint(right,bottom)])
		}
	return //Got something undefined
	}


$.showHover = function (marker,pt){
	if (!mapDiv|| !mapDiv.hoverDiv ||  !(marker.hoverContent || marker.hoverImage)) return
	if (marker.hoverImage) {
		marker.setImage(marker.hoverImage)
		//alert('did setIamge='+marker.hoverImage)
		}
	if (!marker.hoverContent) return
	var hover=mapDiv.hoverDiv, vMap=mapDiv.vMap
	var content
	cancelHideHover(hover)
	if (typeof marker.hoverContent == 'function') content=marker.hoverContent()
	else content=marker.hoverContent
	//alert('show hov for '+content)
	if (!content) return

	//Set content get Height
	hover.style.width=hover.hoverWidth+'px'
	hover.style.height='auto'
	hover.style.display="block";
	hover.innerHTML=content
	hover.hoverHeight= hover.offsetHeight //could be wrong at this point ...

	
	//Reset hover offset
	hover.mouseOffsetY= hover.mousePadding
	hover.mouseSideY= 'top'
	hover.mouseOffsetX= -(hover.hoverWidth/2)
	hover.mouseSideX= 'left'


	if (mapDiv.home != 'vx' && vMap.mousePos) {
		//Got a mousePos recalc best possible offset
		var mouseXY= vMap.fromLatLngToContainerPixel(vMap.mousePos)
		var mx=mouseXY.x, my=mouseXY.y, hw= hover.hoverWidth, hh= hover.hoverHeight,
			dw= mapDiv.offsetWidth, dh=mapDiv.offsetHeight, padding= hover.mousePadding, yCenter= false

		//check for bottom fit
		if ( (dh-my-padding) >= hh ) hover.mouseOffsetY= padding //got a fit
		// does not fit below check over
		else if ( (my-padding) >= hh ) hover.mouseOffsetY= -( padding + hh ) //got a fit over
		//ok cant got on top or bottom will center vericatly
		else {
			yCenter= true
			//center but dont go over the top .... 
			var a= Math.min(-hh/2, hh-(dh-my))
			//alert(' a= '+a+' hh='+hh+' dh='+dh+' my='+my)
			hover.mouseOffsetY= Math.max(-my,a)
			}
		//ok now do x
		//start by trying right side
		if ( (mx+padding+hw) <= dw) hover.mouseOffsetX= padding
		//try left
		else if ( (mx-padding) >= hw) hover.mouseOffsetX= -( padding + hw)
		//try center
		else if ( !yCenter && (mx >= hw/2) && (dw-mx)>=hw/2 ) hover.mouseOffsetX= -(hw/2) //got a fit
		//even if does not fit use rigth side ..
		else hover.mouseOffsetX= padding

		hover.openPos = vMap.mousePos
		setHoverPos(hover.openPos)
		}
	else hover.openPos = true
	//alert('show hover for '+clientRect)
	//alert(' open hover x='+hover.mouseOffsetX+' y=hover.mouseOffsetY)
	//alert('width = '+hoverWidth+' left='+leftSpace+' r='+rightSpace+' i.x='+iconSize.width+'  ia.x='+iconAnchor.x)


	hover.style.visibility="visible";
	}


$.showHoverOld = function (marker,pt){
	if (!mapDiv|| !mapDiv.hoverDiv ||  !(marker.hoverContent || marker.hoverImage)) return
	if (marker.hoverImage) {
		marker.setImage(marker.hoverImage)
		//alert('did setIamge='+marker.hoverImage)
		}
	if (!marker.hoverContent) return
	var hover=mapDiv.hoverDiv, vMap=mapDiv.vMap
	var content
	cancelHideHover(hover)
	if (typeof marker.hoverContent == 'function') content=marker.hoverContent()
	else content=marker.hoverContent
	//alert('show hov for '+content)
	if (!content) return

	

	if (vMap.mousePos) {
		hover.openPos = vMap.mousePos
		setHoverPos(hover.openPos)
		}
	else hover.openPos = true
	//alert('show hover for '+clientRect)
	
	//alert('width = '+hoverWidth+' left='+leftSpace+' r='+rightSpace+' i.x='+iconSize.width+'  ia.x='+iconAnchor.x)
	hover.style.width=hover.hoverWidth+'px'
	hover.style.height='auto'
	hover.innerHTML=content


	hover.style.display="block";
	hover.style.visibility="visible";
	}

$.setHoverPos = function(mouseCoord){
	if (!mapDiv) return
	var vMap = mapDiv.vMap, hover=mapDiv.hoverDiv
	//if (!vMap || !hover) return
	mousePos = vMap.fromLatLngToContainerPixel(mouseCoord)

	var container=vMap.getContainer()
	var cPos=getOffsetPos(container)
	hover.style[hover.mouseSideX] = (cPos.x+mousePos.x+hover.mouseOffsetX) + 'px'
	hover.style[hover.mouseSideY]  = (cPos.y+mousePos.y+hover.mouseOffsetY) + 'px'
	}
	

$.showHoverOld2 = function (marker,pt){
	if (!mapDiv|| !mapDiv.hoverDiv ||  !(marker.hoverContent || marker.hoverImage)) return
	if (marker.hoverImage) {
		marker.setImage(marker.hoverImage)
		//alert('did setIamge='+marker.hoverImage)
		}
	if (!marker.hoverContent) return
	var hover=mapDiv.hoverDiv, vMap=mapDiv.vMap
	var content
	cancelHideHover(hover)
	if (typeof marker.hoverContent == 'function') content=marker.hoverContent()
	else content=marker.hoverContent
	//alert('show hov for '+content)
	if (!content) return

	
	var clientRect
	var border=10
	if (pt) clientRect =  new GBounds([new GPoint(pt.x-border,pt.y-border),new GPoint(pt.x+border,pt.y+border)])
	else    clientRect = getClientBounds(marker)
	//alert('show hover for '+clientRect)
	if (!clientRect) return
	var container=vMap.getContainer()

	var leftSpace  = clientRect.min().x
	var rightSpace = container.offsetWidth-clientRect.max().x
	var topSpace   = clientRect.min().y
	var bottomSpace= container.offsetHeight-clientRect.max().y

	hoverWidth=Math.min(250,Math.max(leftSpace,rightSpace,50))
	//alert('width = '+hoverWidth+' left='+leftSpace+' r='+rightSpace+' i.x='+iconSize.width+'  ia.x='+iconAnchor.x)
	hover.style.width=hoverWidth+'px'
	hover.style.height='auto'
	hover.innerHTML=content
	var hoverWidth=hover.offsetWidth
	var hoverHeight=hover.offsetHeight

	var cPos=getOffsetPos(container)

	if (leftSpace>=hoverWidth) hover.style.left=(cPos.x+clientRect.min().x-hoverWidth)+'px'
	else hover.style.left=(cPos.x+clientRect.max().x)+'px'

	if (topSpace>=hoverHeight || bottomSpace<hoverHeight) hover.style.top= (cPos.y+Math.max(0,clientRect.min().y-hoverHeight))+'px'
	else hover.style.top= (cPos.y+clientRect.max().y)+'px'

	hover.style.display="block";
	hover.style.visibility="visible";
	}

$.showRectHover = function(overlay,e){
	//var x=e.layerX, y=e.layerY, xy=new GPoint(x,y)
	//alert('x='+x+' y='+y+' xy='+xy)
	//var pt=mapDiv.vMap.fromContainerPixelToLatLng(xy)
	//alert('pt='+pt)

	var pane= mapDiv.vMap.getPane(G_MAP_MARKER_PANE).parentNode.style
	var offx=parseInt(pane.left)
	var offy=parseInt(pane.top)
	var div=overlay.div_.style
	var divx=parseInt(div.left)
	var divy=parseInt(div.top)
	var pt =  new GPoint(e.layerX+offx+divx, e.layerY+offy+divy)
	//alert('offx='+offx+' offy='+offy+' divx='+divx+' divy='+divy+' pt='+pt)

	return showHover(overlay,pt)
	}

$.cancelHideHover = function (){
	if (!mapDiv|| !mapDiv.hoverDiv) return
	var hover=mapDiv.hoverDiv
	if (hover.waitingToClose) {
		clearTimeout(hover.waitingToClose)
		hover.waitingToClose=false
		}
	}

$.hideHover = function(marker) {
	if (!mapDiv) return
	if (marker && marker.nonHoverImage) marker.setImage(marker.nonHoverImage)
	if (!mapDiv.hoverDiv) return
	var hover=mapDiv.hoverDiv
	cancelHideHover(hover) //Do this to make sure the counter is reset
	hover.waitingToClose=setTimeout(hideHoverBis,300)
	}

$.hideHoverBis =function() {
	if (!mapDiv|| !mapDiv.hoverDiv) return
	var hover=mapDiv.hoverDiv
	//cancelHideHover(hover) not sure exactly what to do ...
	hover.waitingToClose=false //Not sure exactlu what to do... does canceling a 'running' timeout cause an error?
	hover.openPos=false
	//Hide the hover
	hover.style.visibility='hidden'
	}

$.initHover = function(div){
	
	var hover=getId('hoverDiv')
	if (hover){
		div.hoverDiv=hover
		return hover
		}
	hover = document.createElement("div")
	div.hoverDiv=hover
	hover.hoverWidth= 250
	hover.mousePadding= 30
	hover.mouseOffsetY= hover.mousePadding
	hover.mouseOffsetX= -(hover.hoverWidth/2)
	hover.className="hoverDiv"
	hover.style.backgroundColor='#ffffff'
	hover.style.fontWeight='normal'
	hover.style.fontFamily='Arial'
	hover.style.fontSize='8pt'
	hover.style.border='2px #888888 solid'
	//hover.style.whiteSpace='pre'
 	hover.style.height='auto'
	hover.style.width= hover.hoverWidth+'px'
	hover.innerHTML="Hover Div"
        //div.vMap.getPane(G_MAP_FLOAT_PANE).appendChild(hover);
        hover.style.visibility="hidden";
	hover.style.padding='2px'
	hover.style.position='absolute'
	hover.style.zIndex=9999
	hover.id='hoverDiv'
	hover.waitingToClose=false
	hover.onmouseover=cancelHideHover
	hover.onmouseout=hideHover
	document.body.appendChild(hover);
	return hover
	}

$.MAPIcons={} // Icon registry

$.newIcon = function (name,ops,copyIcon) {
	ops = ops||{}
	if (typeof copyIcon == 'string') copyIcon=MAPIcons[copyIcon]

	var icon = new GIcon(copyIcon)
	var item
	if (item=ops['image']) icon.image=item
	if (item=ops['hoverImage']) icon.hoverImage=item
	if (item=ops['printImage']) icon.printImage=item
	if (item=ops['shadow']) icon.shadow=item
	if (item=ops['iconSize']) icon.iconSize=new GSize(item[0],item[1])
	if (item=ops['shadowSize']) icon.shadowSize=new GSize(item[0],item[1])
	if (item=ops['iconAnchor']) icon.iconAnchor=new GPoint(item[0],item[1])
	if (item=ops['infoWindowAnchor']) icon.infoWindowAnchor=new GPoint(item[0],item[1])
	if (item=ops['imageMap']) icon.imageMap=item
	if (item=ops['transparent']) icon.transparent=item
	if (icon.image) {
		icon.cache=new Image()
		icon.cache
		icon.cache.onload=function(){initIcon(icon)}
		icon.cache.src=icon.image
		}

	if (name && icon) MAPIcons[name]=icon
	return icon
	}

$.initIcon = function(icon) {
	if (!icon.iconSize) icon.iconSize= new GSize(icon.cache.width,icon.cache.height)
	if (!icon.iconAnchor) icon.iconAnchor= new GSize(icon.iconSize.width/2,icon.iconSize.height)
	if (!icon.infoWindowAnchor) icon.infoWindowAnchor= new GSize(icon.iconSize.width/2,0)
	if (!icon.imageMap) {
		var x=icon.iconSize.width, y=icon.iconSize.height
		icon.imageMap = [0,0, x,0, x,y, 0,y, 0,0]
		}
	//alert('imageMap='+icon.imageMap)
	//if (!icon.transparent) icon.transparent=icon.image
	
	icon.cache = null
	}
	
$.newMap = function(elem,ops) { 
	var map=new GMap2(elem,ops)
	// patch addOverlay
	map._jzAddOverlay=map.addOverlay
	map.addOverlay=function(ovl) {
		if (ovl && ovl._jzEnableDrag) {
			//alert('doing enable drag patch2')
			var ret=this._jzAddOverlay(ovl)
			delete ovl._jzEnableDrag
			var ret2=ovl.enableDragging()
			}
		else var ret=this._jzAddOverlay(ovl)
		return ret
		}
		
	if (!map.fromLatLngToContainerPixel) {
		map.fromLatLngToContainerPixel  = function(latlng){
			var pos = this.fromLatLngToDivPixel(latlng)
			var pane= this.getPane(G_MAP_MARKER_PANE).parentNode.style
			var offx=parseInt(pane.left)
			var offy=parseInt(pane.top)
			return new GPoint(pos.x+offx, pos.y+offy)
			}
		}

	
	GEvent.addListener(map,'mouseover',function(pos){ map.mousePos = pos })
	GEvent.addListener(map,'mouseout', function(pos){ map.mousePos = false })
	GEvent.addListener(map,'mousemove',function(pos){
		map.mousePos = pos
		if (elem.hoverDiv && elem.hoverDiv.openPos) setHoverPos(pos)
		})
	return map
	}

$.addNavtec = function(map){
	G_NORMAL_MAP.getName = function() { return 'TeleAtlas'}
	map.addMapType(G_NORMAL_MAP)
	map.addMapType(getNavTeq())
	
	copyrights = new GCopyrightCollection('Map data');
	copyrights.addCopyright(new GCopyright('gmaps-navteq',
		newBounds(newLatLng(-90,-180), newLatLng(90,180)),
		0,'©2006 NAVTEQ'))

	var tileset = new GTileLayer(copyrights, 0, 14)
	tileset.getTileUrl = function(tile, zoom){
    		tileServer++;
  		if (tileServer > 3) tileServer = 0
    		return 'http://mt' + tileServer + '.google.com/mt?n=404&v=w2.21&x=' + tile.x + '&y=' + tile.y + '&zoom=' + (17 - zoom) + ''
		}		;
	tileset.isPng = function() { return false }
	tileset.getOpacity = function() { return 1.0 }

	var maptype = new GMapType(
    				[tileset],
    				new GMercatorProjection(14),
    				'NAVTEQ',
				{shortName:'NT',tileSize:256,maxResolution:14,minResolution:0}
				)
	}

$.intersects = function(bounds){ return bounds.contains(this) }

$.newLatLng = function (lat,lng) {
	var ret= new GLatLng(lat,lng)
	ret.intersects = intersects //Of course could also modify the prototype ....
	return ret
	}

$.newBounds = function (includeList) {
	if (!includeList.length) includeList=[includeList]
	var bounds=new GLatLngBounds()
	dof(includeList, function(p){
		// Is P a bounded object
		if (p.getBounds) p=p.getBounds() // Yes then get bounds of object
		//Is P a GLatLng Bounds object
		if (p.getSouthWest) { // Yes then extend with SW and NE corners
			bounds.extend(p.getSouthWest())
			bounds.extend(p.getNorthEast())
			}
		// else assume this is a GLatLng
		else if (p.lat) bounds.extend(p)
		})
	return bounds
 }

$.doNavigate = function(overlay,point) {
	//return doNavigateReq(overlay,point)
	if (overlay && overlay.href){
		//var pos=overlay.href.indexOf('viaexplora.com')
		//alert('pos='+pos+' for '+overlay.href)
		if (mapDiv && (mapDiv.home=='vx') ) return doNewNavigate(overlay,point)
		if (mapDiv && (!mapDiv.iframe) ) return doNavigateReq(overlay,point)
		
		gotohref(overlay,overlay.href)
		}
	//else alert('got donavigate nohref on '+overlay)
	}

$.doNavigateReq = function(overlay,point) {
	if (!mapDiv) return
	
	//from plone stuf
	var name=mapDiv.id.slice(0,mapDiv.id.lastIndexOf('.')) //remove ._map
	var reqstr = scanChecksFor(name+'._reqAttrait')
	if (overlay && overlay.href) gotohref(overlay,overlay.href+getHrefArgs())
	//else alert('got donavigate nohref on '+overlay)
	}

$.doNewNavigate = function(overlay,point) {
	var newhref= urlMerge(overlay.href)
	//alert('new navidate url='+newhref)
	gotohref(overlay,newhref)
	}


$.doNavigateIndirect = function(rect){//This alows us to change doNavReq after the evnt listener was been set ...
	doNavigate(rect)
	//panAndZoomTo(rect.bounds_)
	}

$.gotohref= function(overlay,href){
	//alert(' gogo ovl='+overlay+' ovl.href='+overlay.href+' href='+href+' ovlt='+overlay.hreftarget+' oid='+overlay.id+' ctype='+overlay.ctype)
	if (overlay && overlay.hreftarget){
	    window.open('http://www.viaexplora.com/redirect.html#'+href,overlay.hreftarget[0],overlay.hreftarget[1])
	    
	    //var w=top.frames[overlay.hreftarget[0]].document.open().top.frames[overlay.hreftarget[0]].document.window.location=href
	    //w.close()
	    //alert('did window.open("'+href+'","'+overlay.hreftarget[0]+'","'+overlay.hreftarget[1]+'")')
	    }
	else
	   // alert('no target navigating for '+overlay+' oh='+overlay.href+' OT='+overlay.hreftarget)
	    top.location=href
	}

// A Rectangle is a simple overlay that outlines a lat/lng bounds on the
// map. It has a border of the given weight and color and can optionally
// have a semi-transparent background color.

$.newRectangle = function (bounds,ops,cls){//Rectangle factory
	ops=ops||{}
	cls=cls||Rectangle
	var rect= cls(bounds,ops['weight'],ops['color'])
	if (ops['hoverContent']) rect.hoverContent = ops.hoverContent
	rect._jzSetZ=Rectangle.currentZIndex++ //new rects always on top
	// apply ops
	return rect
	}

$.Rectangle = Class(GOverlay,{

	jz_init	: function(bounds,opt_weight,opt_color,opt_background,opt_opacity) {
		this.bounds_ = bounds;
		if (typeof opt_weight == 'undefined') opt_weight=2
		this.weight_ = opt_weight 
		this.color_ = opt_color || ""
		if (IE){
			this.background_ = opt_background || "transparent"
			//this.opacity_ = opt_opacity || 0.1
			}
		else {
			this.background_ = opt_background || ""
			this.opacity_ = opt_opacity || 0.2
			}
		},

	currentZIndex : 100000,

	// Creates the DIV representing this rectangle.
	initialize : function(map) {
		// Create the DIV representing our rectangle
		this.map_ = map
		var div = document.createElement("div")
		this.div_ = div
		div.jz_Listeners = []
		if (this.divClass) div.className=this.divClass

		div.style.border = this.weight_ + "px solid " + this.color_;
		if (this.background_) div.style.backgroundColor = this.background_
		if (this.opacity_) {
			div.style.MozOpacity = div.style.khtmlOpacity = div.style.opacity = this.opacity_
			div.style.filter="alpha(opacity="+(100*this.opacity_)+")"
			}
		div.style.position = "absolute"
		div.style.overflow = "hidden"
		
		// Our rectangle is flat against the map, so we add our selves to the
		// MAP_PANE pane, which is at the same z-index as the map itself (i.e.,
		// below the marker shadows)
		if (this._jzSetZ) {
			div.style.zIndex=this._jzSetZ
			}
		else div.style.zIndex=GOverlay.getZIndex(this.bounds_.getNorthEast().lat())
		map.getPane(G_MAP_MARKER_SHADOW_PANE).appendChild(div);

		//div.onclick="alert('goa click')"
		this.inithref(map)
		if (this.hoverContent) this.initHover(map)
		},

	inithref : function(map){
		if (this.href){
			var self=this, div=this.div_
			addListener(div,'click',function(e){doNavigateReqIndirect(self)})
			addListener(div,'mouseover',function(e){div.style.borderColor='red';div.style.borderWidth='3px';})
			addListener(div,'mouseout',function(e){div.style.borderColor=self.color_;div.style.borderWidth=self.weight_+'px';})
			}
		},

	initHover : function(map){
		if (!mapDiv) return
		var self=this,div=this.div_
		addListener(div,'mouseover',function(e){showRectHover(self,e)})
		addListener(div,'mouseout',function(){
			hideHover(self)
			//if (mapDiv && mapDiv.hoverDiv) mapDiv.hoverDiv.style.visibility='hidden'
			})
		},

	// Remove the main DIV from the map pane
	remove : function() {
		if (!this.div_) return
		var cnt=removeObjListeners(this.div_)
		this.div_.parentNode.removeChild(this.div_)
		this.div_ = false
		},

	// Copy our data to a new Rectangle
	copy : function() {
		return new Rectangle(this.bounds_, this.weight_, this.color_,this.backgroundColor_, this.opacity_);
		},

	// Redraw the rectangle based on the current projection and zoom level
	redraw : function(force) {
		// We only need to redraw if the coordinate system has changed
		if (!force) return;
		if (!this.div_) return
		
		// Calculate the DIV coordinates of two opposite corners of our bounds to
		// get the size and position of our rectangle
		var c1 = this.map_.fromLatLngToDivPixel(this.bounds_.getSouthWest());
		var c2 = this.map_.fromLatLngToDivPixel(this.bounds_.getNorthEast());
		
		// Now position our DIV based on the DIV coordinates of our bounds
		this.div_.style.width = Math.abs(c2.x - c1.x) + "px";
		this.div_.style.height = Math.abs(c2.y - c1.y) + "px";
		this.div_.style.left = (Math.min(c2.x, c1.x) - this.weight_) + "px";
		this.div_.style.top = (Math.min(c2.y, c1.y) - this.weight_) + "px";
		},

	getHoverAnchor : function(){return newLatLng( this.bounds_.getSouthWest().lng(), this.bounds_.getNorthEast().lat())}, //remember newlatlng inverts lat and lng

	//Get bounds of rectangle (read only)
	getBounds : function (){return this.bounds_} ,// { return newBounds(this.bounds_) }

	removeable : function (){return true}
	
	})//end Rectangle class def

$.FocusRectStyle =  { opacity:.3,    color:'#ff00ff', weight:8 }
$.FocusRectangle = Class(Rectangle,{

	divClass : 'jz-focusrect',

	_mouseDownTime : new Date,
	inithref : function(map){
		var self=this, div=this.div_
		if (this.href){
			addListener(div, 'mousedown', function(e){self._mouseDownTime = new Date})
			addListener(div, 'click',     function(e){if (((new Date)-self._mouseDownTime)<500) doNavigateIndirect(self)})//Ignore drags or slow clicks ...
			}
		addListener(div, 'mouseover', function(e){self.doShowFocus()})
		addListener(div, 'mouseout',  function(e){self.doHideFocus()})
		},
	doShowFocus : function(){
		if (!mapDiv) return
		if (mapDiv.home=='vx' && IE && IE>=7.) return //patch ie hover bug ...
		if (this.overlays) { dof(this.overlays,function(ovl){mapDiv.vMap.addOverlay(ovl)}); return }
		if (!this.path ) return
		//Create overlay
		this.overlays=mapf(this.path.eoverlays, function(ovl){ return newEPolyline(ovl[0],ovl[1],FocusRectStyle)})
		dof(this.overlays,function(ovl){mapDiv.vMap.addOverlay(ovl)})
		},
	doShowFocusNew : function(){
		if (!mapDiv) return
		if (!this.path ) return
		//Create overlay
		dof(this.path.overlayCache,function(ovl){
			var oldstyle
			if (!ovl.jz_oldStyle) oldstyle=ovl.jz_oldStyle={}  
			dof(FocusRectStyle,function(val,key){
				if (oldstyle) oldstyle[key]=ovl[key]
				ovl[key]=val
				})
			ovl.redraw(true)
			})
		},

	doHideFocus : function(){
		if (!mapDiv) return
		if (this.overlays) { dof(this.overlays,function(ovl){mapDiv.vMap.removeOverlay(ovl)}); return }
		this.overlays=false
		},

	doHideFocusNew : function(){
		if (!mapDiv) return
		if (!this.path ) return
		//Create overlay
		dof(this.path.overlayCache,function(ovl){
			if (!ovl.jz_oldStyle) return //continue
			update(ovl,ovl.jz_oldStyle)
			delete ovl.jz_oldStyle
			ovl.redraw(true)
			})
		}
	})//End Focus Rectangle class

$.newFocusRectangle = function(bounds,ops){ return newRectangle(bounds,ops,FocusRectangle) }


$.jzControl = Class(new GControl(true,false),{ //Rectangle Class
	jz_init : function(innerHtml,style,pos){
		if (innerHtml)	this.html=innerHtml
		if (style)	this.style=style
		if (pos)	this.pos=pos
		},

	// Creates the DIV representing this rectangle.
	initialize : function(map) {
		// Create the DIV representing our rectangle
		this.map_ = map
		var div = document.createElement("div")
		div.className='jz'
		div.map= map
		update(div.style,this.style)
		div.innerHTML=this.html
		this.div_ = div;
		map.getContainer().appendChild(div)
		return div
		},

	pos : new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(10,10)),
	// Remove the main DIV from the map pane
	//Control.prototype.printable = function() { Log('in printable'); return true }
	//Control.prototype.selectable = function() { Log('in selectable'); return true }

	// Copy our data to a new Rectangle
	getDefaultPosition : function(){ return  this.pos }
	})

$._CopyrightText = 'Sentiers de motoneige &copy; Gouvernement du Québec'
$._CopyrightText_en = 'Snowmobile trails &copy; Gouvernement du Québec'
$.CopyrightControl = Class(jzControl(
	'<span style="font:8pt sans-serif; letter-spacing:-1px;">'+_CopyrightText+'</span>',
	{},new GControlPosition(G_ANCHOR_BOTTOM_RIGHT,new GSize(5,15))
	))
$.CopyrightControl_en = Class(CopyrightControl('<span style="font:8pt sans-serif; letter-spacing:-1px;">'+_CopyrightText_en+'</span>'))

$.Copyright2Control = Class(jzControl(
	'<span style="font:8pt sans-serif; letter-spacing:-1px;">'+_CopyrightText+'</span>',
	{},new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(125,15) )
	))
$.Copyright2Control_en = Class(Copyright2Control('<span style="font:8pt sans-serif; letter-spacing:-1px;">'+_CopyrightText_en+'</span>'))

$.LogoControl = Class(jzControl(
	'<a href="http://www.ViaExplora.com" onclick="top.location=this.href" ><img src="/static/image/logosml.gif" style="height:49px ; width:150px; border:0px" /></a>',
	{},new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(80,10))
	))

$.SmllogoControl = Class(jzControl(
	'<a href="http://www.ViaExplora.com" onclick="top.location=this.href" ><img src="/static/image/logovsml.gif" style="height:25px ; width75px; border:0px" /></a>',
	{},new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(5,5))
	))


$.MessageControl = Class(jzControl(
	'<div id="MessageControlElem" style="visibility:hidden; font:9pt sans-serif; color:black;  background:white; border:1px solid black; padding: 1px"></div>',
	{},new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(235,25))
	))

$.dirctrlhtml=_('\
	 <div id="DirectionsControl" style=" font:9pt sans-serif; color:black;  background:url(/static/image/50white.png); padding: 1px; border: 1px solid grey">\n\
		 <input type="checkbox" id="DirectionsControl.check" checked="true" \n\
			 onclick="jzGMap.dodirectionscontrolchange(this.parentNode.parentNode,this.checked)">$dirctrltext</input>\n\
		 </div>',{dirctrltext:_('dirctrltext')})

//alert('dirctrlhtml='+dirctrlhtml)
$.DirectionsControl = Class(jzControl(dirctrlhtml,
	{},new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(80,60))
	),{ 
	initialize : function(map) {
		var ret= jzControl.prototype.initialize.call(this,map) //eh super cls ...
		dodirectionscontrolchange(this.div_,getId('DirectionsControl.check').checked,' init control')
		return ret
		}
	})

$.dodirectionscontrolchange= function(ctrldiv,checked,caller){
	//var ctrldiv= ctrl.parentNode.parentNode
	caller=caller?caller:'no caller'
	//alert(' in dir ctl change fom '+caller+' div='+ctrldiv+' map='+ctrldiv.map+' router='+(ctrldiv.map?ctrldiv.map.router:'nomap')+' checked='+checked)
	var map= ctrldiv.map
	if (!map) return //setup is not finished
	var router=map.router
	var elem= getId('mappane_container')
	var dirdiv= getId('directions')
	//alert('dirdiv='+dirdiv)
	if (checked) {
		if (elem && jz.vsplitRestoreRight) jz.vsplitRestoreRight('mappane')
		else if (dirdiv) dirdiv.style.display='block'
		if (router) router.show()
		}
	else {
		if (elem && jz.vsplitMaxRight) jz.vsplitMaxRight('mappane')
		else if (dirdiv) dirdiv.style.display='none'
		if (router) router.hide()
		}
	map.checkResize()		
	}

$.Legend1Control = Class(jzControl(_('\
	 <div id="Legend1ControlElem" style="font:7pt sans-serif; color:black;  background:url(/static/image/50white.png); border:1px solid black; padding: 1px; width:11em;height:3em; margin-bottom:0.5em">\n\
		<div class="LegendBlock">\n\
			<div class="LegendElem" style="border-color:#00ff00; clear:both" ></div>$PisteCyclable</div>\n\
		<div class="LegendBlock">\n\
			<div class="LegendElem" style="border-color:#4040ff;" ></div>$CircuitRoutier</div>\n\
	    </div>',{PisteCyclable:_('PisteCyclable'), CircuitRoutier:_('CircuitRoutier')} ),
	{},new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(5,35))
	))

//		<div class="LegendBlock">\n\
//			<div class="LegendElem" style="border-color:#20A0B0;" ></div>$Hybride</div>\n\
//  ,Hybride:_('Hybride')

$.Legend2Control = Class(jzControl(
	'<div id="Legend1ControlElem" style="font-family:Arial, Helvetica, sans-serif; font-size:7pt; color:black;  background:url(/static/image/75white.png);  border:1px solid black; padding: 1px; width:13em;height:14em; margin-bottom:0.5em">'+
		'<div><b>'+_('Piste-cyclable')+'</b></div>'+
			'<div class="LegendBlock"><div class="LegendElem" style="border-color:#008000;" ></div>'+_('Asphaltée')+'</div>'+
			'<div class="LegendBlock"><div class="LegendElem" style="border-color:#00ff00;" ></div>'+_('Poussière de pierre')+'</div>'+
		//'<div class="lgndE" >'+
		//	'<div class="lgndB" style="background:#000000;" ></div>'+
		//	'Projet</div>'+

		'<div><b>'+_('Balisée sur route')+'</b></div>'+
			'<div class="LegendBlock"><div class="LegendElem" style="border-color:#8080ff;margin-bottom:1.2em" ></div>'+_('Chaussée désignée asphaltée')+'</div>'+
			'<div class="LegendBlock"><div class="LegendElem" style="border-color:#00ff80;" ></div>'+_('Bande cyclable')+'</div>'+
			'<div class="LegendBlock"><div class="LegendElem" style="border-color:#ffa020;" ></div>'+_('Accotement asphalté')+'</div>'+
		//'<div class class="LegendBlock"="lgndE">'+
		//	'<div class="lgndB" style="background:#000000;" ></div>'+
		//	'Projet</div>'+

		'<div><b>'+_('Non balisée sur route')+'</b></div>'+
			'<div class="LegendBlock"><div class="LegendElem" style="border-color:#808080;" ></div>'+_('Chaussée pavée')+'</div>'+
			'<div class="LegendBlock"><div class="LegendElem" style="border-color:#b07040;"></div>'+_('Chaussée non pavée')+'</div>'+
		//'<div><b>'+_('Autres')+'</b></div>'+
		//'<div class="lgndE" >'+
		//	'<div class="lgndB" style="background:#ff8000;" ></div>'+
		//	'Navette terrestre</div>'+
		//'<div class="lgndE">'+
		//	'<div class="lgndB" style="background:#ffff00;" ></div>'+
		//	'Navette fluviale</div>'+
		//	'<div class="LegendBlock"><div class="LegendElem" style="border-color:#ff80ff;" ></div>'+_('Train')+'</div>'+
	'</div>',
	{},new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(5,35))
	))

$.mCalcDistance = function(p1,p2) { // Calculate ditance between point p1 and p2(both GPoints)  
	var pi=Math.PI,earthRadious=6378.137,p1RLat,p2RLat,p1RLng,p2RLng //6378137 was 6366.707
	p1RLat=  pi*(90-p1.lat())/180
	p2RLat=  pi*(90-p2.lat())/180
	p1RLng= pi*((360+p1.lng()) % 360)/180
	p2RLng= pi*((360+p2.lng()) % 360)/180

	var x1,y1,z1,x2,y2,z2
	x1 = Math.cos(p1RLng)*Math.sin(p1RLat)
	y1 = Math.sin(p1RLng)*Math.sin(p1RLat)
	z1 = Math.cos(p1RLat)
	
	x2 = Math.cos(p2RLng)*Math.sin(p2RLat)
	y2 = Math.sin(p2RLng)*Math.sin(p2RLat)
	z2 = Math.cos(p2RLat) // could cor
	
	var gc = earthRadious*Math.acos((2-((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)))/2)
	
	return gc
   	}

$.distance = function(pts,toIdx){
	if (toIdx === undefined) toIdx=pts.length-1
	if (!pts._distances) {
		var distances=mapf(pts.length,function(v,i,l){
			if (!i) return 0
			return l+mCalcDistance(at(pts,i-1),at(pts,i))
			})
		distances.end   = distances[distances.length-1]
		distances.start = distances[0] //should be zero
		pts._distances  = distances
		}
	return pts._distances[toIdx]
	}
} //end jzGMap name space


