with(jzGMap){

importFrom(jz,'newXMLHttpRequest innerText innerHTML update mapf extractf contains indexOf setCookie getCookie setCookieForever _ IE')
importFrom(Math,'max min')

$.movetoscrn= function(marker,map){
			if (!(map && marker && marker.screenpos)) return
			latlng= map.fromContainerPixelToLatLng(marker.screenpos)
			marker.setLatLng(latlng)
			}

$.tag= function(name,ops,content){
		if (content === undefined ) content=ops, ops=false
		return '<'+name+(ops?' style="'+ops+'" >':'>')+content+'</'+name+'>'
		}

$.li= function(ops,content){ return tag('li',ops,content) }
$.ul= function(ops,content){ return tag('ul',ops,content) }

$.MRouterBase= Class(Object,{
	//Multi Point Router
	// This class represents a path between multiple waypoints
	// How the routing occurs between the diffrent waypoints is determined by the subclassing
	// such as Google roads, VX snowmobilw paths etc
	// a simple implementation is provided that assumes lines between way points
	// 2 sub classes are implemented as bases, one assumes routinge occurs between 2 way points
	// the other redoes the whole routing when ever a change occurs ..
	// The main class (this one) is responsible for managing the ordered way points ... 
	//set a init
	markers:false, //list of marker that amke up the path

	map:	false,
	//def vals can overide as args to init 
	startIcon: StartIcon,
	pauseIcon: MidIcon,
	//pauseIcon: PauseIcon,
	endIcon:   EndIcon,
	offset: [10,-30],
	routeStyle: {color: "#0bf559", weight:7, opacity:0.6},  // ffff33 c6ff00 4cf61e 0bf559 35e56f
	cookie: '', //name of cookie used to track waypoinst '' means dont use ...
	showen: true,
	helperHoverContent: _('directions aide marqeur'),
		
	// attribute functions function that are passed as unbounde arguments
	initHoverContent: function(){
		//WARNING this methos is an attribute 'the function' is passed as an
		//attribute to MArker when created so this will be refering TO THE MARKER
		//NOT the router ...
		var marker= this
		var router= marker.router
		var pos= indexOf(router.markers,marker)
		if (pos<0) return '' //marker not in route cant do anything
		var beforeAfter= router.getBeforeAfter(pos)
		var before=beforeAfter[0], after=beforeAfter[1], total=before+after
		var ret= [], mess='', ret2=[]
		var info={ pos:pos, before:unittxt(before), after:unittxt(after), total:unittxt(total) } 
		if (pos==0) mess= _('DirDebut',info)
		else if (pos == router.markers.length-1) mess= _('DirFin',info)
		else mess=_('Etape $pos',info)
		ret.push(mess)
		if (before > 0. ) ret.push(_('$before de fait',info))
		if (after > 0. )  ret.push(_('$after à faire',info))
		if (total >0. && after > 0. && before > 0.)  ret.push (_('$total au total',info))
		ret.push(_('DirFooter',info))
		dof(ret,function(i){ if (i) ret2.push(i)})
		ret= ret2.join('<br/>')
		return ret
		},

	markerdragend: function(){ //function holder this is the marker ....
		//this is the marker
		var marker= this
		marker.router.moveMarker(marker)
		},

	clearhelper: function(marker){
		if (marker.moveendlistener) { //stop tracking
			GEvent.removeListener(marker.moveendlistener)
			marker.screenpos= marker.moveendlistener= false
			}
		if (marker.movelistener) { //stop tracking
			GEvent.removeListener(marker.movelistener)
			marker.screenpos= marker.movelistener= false
			}
		this.map.removeOverlay(marker)
		marker.router= false
		},

	helperdragend: function(){//function holder this is the marker ....
		//this is the marker
		var marker= this, router=marker.router, map=router.map
		var latlng= marker.getLatLng()
		router.clearhelper(marker)
		if (marker === router.startHelper){
			router.startHelper= false
			router.insertPos(0,latlng)
			}
		else if (marker === router.endHelper){
			router.endHelper= false
			router.addMarker(latlng)
			}
		},

	initHelpers: function(waypoints){//add initial start stop icons
		var wplen= waypoints?waypoints.length:0
		if (wplen<1) this.addStartHelper()
		if (wplen<2) this.addEndHelper()
		},

	makeHelper: function(icon,pos){//add initial start stop icons
		var offset= this.offset
		var iwidth= this.startIcon && this.startIcon.size && this.startIcon.size.width || 20
		var map= this.map
		var div= map.getContainer()
		//var dcw= div.clientWidth, dch= div.clientHeight
		var dow= div.offsetWidth
		var doh= div.offsetHeight //you asked for it ...
		var dcw=dow, dch=doh		//alert('In make helper')
		
		if (offset[0]<0)	offset[0]= max(0,offset[0]+dcw-iwidth)
		else if (offset[0]<1)	offset[0]= max(0,offset[0]*dcw-iwidth)
		else			offset[0]= min(dcw,offset[0])

		if (offset[1]<0)	offset[1]= max(0,offset[1]+dch)
		else if (offset[1]<1)	offset[1]= max(0,offset[1]*dch)
		else			offset[1]= min(dch,offset[1])
		
		//alert('offset='+offset+' iwidth='+iwidth+' dcw='+dcw+' dch='+dch)
		
		var helperoffset= new GPoint(offset[0]+(iwidth*pos),offset[1])
		var helperpos= map.fromContainerPixelToLatLng(helperoffset)

		var helper= newMarker(helperpos,{
				icon:icon,
				hoverContent: this.helperHoverContent,
				dragend   :   this.helperdragend
				})
		update(helper,{
			isstart: icon==this.startIcon,
			screenpos: helperoffset,
			router: this,
			moveendlistener: GEvent.addListener(map,'moveend',function(){ movetoscrn(helper,map) }),
			movelistener: GEvent.addListener(map,'move',function(){ movetoscrn(helper,map) })
			})
		map.addOverlay(helper)
		if (!this.showen && helper.hide) helper.hide()
		return helper
		},

	addStartHelper: function(){	return this.startHelper= this.makeHelper(this.startIcon,0) },

	addEndHelper:  function(){ return this.endHelper=   this.makeHelper(this.endIcon,1) },
	

	jz_init: function(map,ops){
		this.map= map
		//var div= map.getContainer()
		update(this,ops)
		this.markers= []
		GEvent.bind(map,'singlerightclick',this,this.dorightclick)
		GEvent.bind(map,'dblclick',this,this.dodblclick)
		var waypoints=getId('waypoints')
		if (waypoints && waypoints.jz_data) waypoints=waypoints.jz_data
		else {
			var ewaypoints= getId('ewaypoints')
			if (ewaypoints && ewaypoints.jz_data)
				 waypoints= this.wpe2wp(ewaypoints.jz_data)
			else waypoints= false
			}

		if (!waypoints && this.cookie){

		    var txt=getCookie(this.cookie)
		    if (txt && txt.charAt(0)=='[') //old cookie
			txt='{ WpeTxt:'+txt+'}'
		    //alert(' cookie text = "'+txt+'"')
		    var ret={}
		    if (txt) eval('ret= '+txt) // TODO: parse the coockie small security risk (nothing valuable to protect)

			var ewaypoints= ret.WpeTxt
			if (ewaypoints) waypoints= this.wpe2wp(ewaypoints)
			}

		if (waypoints)
			waypoints=mapf(waypoints,
				function(wp){ return newLatLng(wp[0],wp[1]) })
		this.initWaypoints(waypoints)
		this.initHelpers(waypoints)
		//use helpers instead ...
		//GEvent.bind(map,'click',this,this.doclick)
		map.router=this
		if (map.jzControls['Directions'])
			dodirectionscontrolchange(map.jzControls['Directions'].div_,getId('DirectionsControl.check').checked,'router init')
		return this
		},

	doclick: function(ovl,latlng){
		//Remember latlng not set if ovl is ....
		if (!ovl) return this.addMarker(latlng)
		},

	dorightclick: function(pt,src,ovl){
		var pos= indexOf(this.markers,ovl)
		if (pos>-1) this.removeMarker(ovl)
		return
		},

	dodblclick: function(ovl,latlng){
		//alert('go right click latlng='+latlng+' ovl='+ovl)
		return
		},

// 	dopathupdate: function(marker){
// 		pos= indexOf(this.markers,marker)
// 		if (pos<0) return //should be exception
// 		this.pathUpdate(pos)
// 		},

	getWpTxt: function(){
		return jz.mapf(this.markers,function(marker){
			var latlng= marker.getLatLng()
			return '['+latlng.lat().toFixed(6)+','+latlng.lng().toFixed(6)+']'
			}).join(',')
		},

	getWpeTxt: function(){
		var olat=0, olng=0
		return jz.mapf(this.markers,function(marker){
			var ll= marker.getLatLng()
			var lat=Math.round(100000*ll.lat()), lng=Math.round(100000*ll.lng())
			var xlat=lat-olat, xlng=lng-olng
			olat+=xlat
			olng+=xlng
			return xlat+','+xlng
			}).join(',')
		},

	wpe2wp: function(wpe){
		var lat=0., lng=0., idx=0
		if (wpe[0].constructor === Array)
			return mapf(wpe,function(ell){
				lat+=ell[0]
				lng+=ell[1]
				return [lat/100000.,lng/100000.] })
		else
			return mapf(wpe.length/2,function(i){
				idx=i*2
				lat+=wpe[idx]
				lng+=wpe[idx+1]
				return [lat/100000.,lng/100000.] })
		},

	moveMarker: function(marker){
		var pos= indexOf(this.markers,marker)
		if (pos < 0) return //not found nothing to remove TODO: through error
		return this.movePos(pos)
		},

	movePos: function(pos){ return this.pathUpdate(pos,'moved') },

	addMarker: function(latlng){
		return this.insertPos(this.markers.length,latlng)
		},

	insertPos: function(pos,latlng){ //pos is before
		var icon= this.pauseIcon
		if (pos>= this.markers.length && pos>0){//end for sure
			icon= this.endIcon
			if (pos>1) this.changeMarkerTo(this.markers.length-1,this.pauseIcon)
			}
		if ( pos == 0 ){//start for sure
			//we could only have the end 
			if (this.markers.length == 0 && this.startHelper)
				 icon= this.endIcon
			else icon= this.startIcon
			}
		this.markers.splice(pos,0,false)
		this.changeMarkerTo(pos,icon,latlng)

		this.pathUpdate(pos,'inserted')
		},

	removeLastMarker: function(){
		if (!this.markers.length) return
		this.removePos(this.markers.length-1)
		},

	removeMarker: function(marker){
		var pos= indexOf(this.markers,marker)
		if (pos < 0){
			alert('blaaaa')
			return //not found nothing to remove TODO: through error
			}
		return this.removePos(pos)
		},

	removePos: function(pos){
		//if (pos==0) alert('got remove = '+pos+' ml='+this.markers.length)
		var ma= this.markers
		var temp
		temp= ma.splice(pos,1)[0]
		var icon= temp?temp.getIcon():false
		if (temp) this.map.removeOverlay(temp)
		if (icon === this.startIcon) {//removed start change an Icon or add helper
			if (ma.length>1) this.changeMarkerTo(pos,this.startIcon)
			else this.addStartHelper()//only one marker left add the start helper
			}
		if (icon === this.endIcon) {//end start change an Icon or add helper
			if (ma.length>1) this.changeMarkerTo(pos-1,this.endIcon)
			else this.addEndHelper()//only one marker left add the start helper
			}
		this.pathUpdate(pos,'removed') //attention si dernier pos=pos-1 ... TODO:
		},

	changeMarkerTo: function(pos,icon,latlng){
		var markers=this.markers
		var oldmarker= markers[pos]
		if (oldmarker){
			latlng=oldmarker.getLatLng()
			this.map.removeOverlay(oldmarker)
			oldmarker.router= false //remove circular ref ..
			}
		var newmarker= markers[pos]= newMarker(latlng,{
			icon:icon,
			hoverContent: this.initHoverContent,
			dragend   :   this.markerdragend
			})
		newmarker.router= this
		this.map.addOverlay(newmarker)
		if (!this.showen && newmarker.hide) newmarker.hide()
		},

	dumpWaypoints: function(){
		return mapf(this.markers,function(marker){ return marker.getLatLng() })
		},

	dumppts: function(){ return this.dumpWaypoints() },

	// API

	getBeforeAfter:  function(pos){
		var before=0, after=0, self=this
		dof(pos,function(i){ before+= self.getDistance(i) })
		dof(this.markers.length-pos-1,function(i){ after+= self.getDistance(pos+i) })
		return [before,after]
		},
	
	getDistance: function(pos){ //get distance to next Marker OR length of segment pos
		return mCalcDistance(this.markers[pos].getLatLng(),this.markers[pos+1].getLatLng())*1000.
		},

	initWaypoints: function(waypoints){
		if (!waypoints) return
		var router=this
		dof(waypoints,function(wp){router.addMarker(wp)})
		},

	pathUpdate: function(pos,action){
		// this is called in all circumstances insert,move and remove
		// action is moved inserted or removed
		//base class does except manage the cookie
		this.cookieUpdate()
		//this.initHelpers(this.markers)
		//alert('doing '+action+' '+pos)
		return this.pathUpdateEnd(pos,action)
		},

	pathUpdateEnd: function(pos,action){ },//defined by son's 

	cookieUpdate: function(){
		var txt=this.getWpeTxt()
		if (txt) txt='['+txt+']'
		//alert('cookie update coockie='+this.cookie+' '+txt)
		if (this.cookie) {
			setCookieForever(this.cookie,txt)
			}
		 },

	show: function(){
		dof(this.markers,function(m){ m.show() })
		if (this.startHelper) this.startHelper.show()
		if (this.endHelper) this.endHelper.show()
		this.showen= true
		},

	hide: function(){
		dof(this.markers,function(m){ m.hide() })
		if (this.startHelper) this.startHelper.hide()
		if (this.endHelper) this.endHelper.hide()
		this.showen= false
		}

	})

$.SegRouter= Class(MRouterBase,{
	//Segment based Router
	segments: false,
	html: false, // array of html fragments
	dirDivName: 'directions', //name of div that will contain html directions
	dirDiv: false,

	jz_init: function(map,ops){
		this.segments= []
		this.html= []
		jz.superClsP(SegRouter).jz_init.call(this,map,ops)
		if (this.dirDivName){
			this.dirDiv= getId(this.dirDivName)
			if (this.dirDiv) this.dirHelp= this.dirDiv.innerHTML //rember help text
			}
		return this
		},

	doSegmentClick: function(seg,latlng){
		var pos= indexOf(this.segments,seg)
		//alert('segclick got pos='+pos+' at latlng '+latlng)
		if (pos<0) return //unkown seg to cuase exception
		this.insertPos(pos+1,latlng)
		},

	pathUpdateEnd: function(pos,action){
		// this is called in all circumstances insert,move and remove
		// action is moved inserted or removed
		if (action=='inserted' && this.markers.length>1) this.insertSeg(pos-1)
		else if (action=='removed' && this.segments.length){
			if (pos<this.segments.length)
				 this.delSeg(pos)
			else this.delSeg(pos-1) 
			}
		if (this.markers.length && this.segments.length >= this.markers.length) alert(' lens eq ='+this.segments.length)
		if (pos >=1 && pos<=this.segments.length) this.updateSeg(pos-1)
		if (pos<this.segments.length) this.updateSeg(pos)
		},

	updateSeg: function(pos){
		var start= this.markers[pos].getLatLng()
		if (pos>=this.markers.length) alert('oups pos='+pos+' ml='+this.markers.length)
		var end= this.markers[pos+1].getLatLng()
		this.clearSeg(pos)
		var dst= jzGMap.mCalcDistance(start,end)*1000.
		var html=unittxt(dst)+' from '+start.lat().toFixed(6)+','+start.lng().toFixed(6)+' to '+end.lat().toFixed(6)+','+end.lng().toFixed(6)
		this.setSeg(pos,[start,end],false,html)
		this.setHtml()
		},

	setSeg: function(pos,points,segPoly,html){
		this.html[pos]= html || ''
		if (!segPoly) segPoly= newPolyline(points,this.routeStyle)
		else update(segPoly,this.routeStyle)
		segPoly.clickable= true
		//segPoly.enableEditing()
		var thisrouter= this
		this.segments[pos]= segPoly
		this.map.addOverlay(segPoly)
		GEvent.addListener(segPoly,'click',function(latlng){ thisrouter.doSegmentClick(this,latlng) })
		if (!this.showen && segPoly.hide) segPoly.hide()
		},

	clearSeg: function(pos){
		this.html[pos]= ''
		var segPoly= this.segments[pos]
		if (segPoly) this.map.removeOverlay(segPoly)
		this.segments[pos]= false
		},

	insertSeg: function(pos){
		this.html.splice(pos,0,'')
		this.segments.splice(pos,0,false)
		},

	delSeg: function(pos){
		this.clearSeg(pos)
		this.segments.splice(pos,1)
		this.html.splice(pos,1)
		},

	getDistance: function(pos){ //get distance to next Marker OR length of segment pos
		var seg= this.segments[pos]
		if (seg) return seg.getLength()
		//OK no seg probably waiting for the ajax transaction ...
		//Anser 0 or NaN ... 0 for now ...
		return 0
		},

	dumppts: function(){
		var lastpt=false, pts=[]
		dof(this.segments,function(seg){
			dof(seg.getVertexCount(),function(i){
				var pt= seg.getVertex(i)
				if (!lastpt || !( lastpt.lat()==pt.lat() && lastpt.lng()==pt.lng() )) pts.push(pt)
				lastpt= pt
				})
			})
		return pts
		},

	show: function(){
		dof(this.segments,function(seg){ if (seg.show) seg.show() })
		return SegRouter.jz_superP.show.call(this) // goto super cls ...
		},

	hide: function(){
		dof(this.segments,function(seg){ if (seg.hide) seg.hide() })
		return SegRouter.jz_superP.hide.call(this) // goto super cls ...
		},

	setHtml: function(){
		if (!this.dirDiv) return //ok no directions we are done ..
		
		var html= this.html
		var pos= 0.0
		var time= 0.0
		var router= this
		
		function lipos(content){return li(unittxt(pos)+'  '+content)}

		var routes=mapf(html,function(routeinfo,i){
			var startPos=pos, startTime= time
			var dist='', durt=''
			if (routeinfo.dist){
				dist=unittxt(routeinfo.dist.meters)
				durt=timetxt(routeinfo.time.seconds)}
			var routeSummary= _('<span style="font-weight:bold">Étape $i: $dist (environ $durt)</span>',
				{i:i+1, dist:dist, durt:durt})
			var steps= mapf(routeinfo.steps,function(step,j){
				var stephtml= _('<li> $postxt $stephtml, pour $disthtml ( $timehtml )</li>',
					{disthtml:unittxt(step.dist.meters), timehtml:timetxt(step.time.seconds), stephtml:step.html, postxt:unittxt(pos)})
				pos+= step.dist.meters
				time+= step.time.seconds
				return stephtml
				})
			if (!steps) steps= []
			var end
			if (i == html.length-1)
				 end= _('Arrivée à la fin du trajet')
			else end= _("Arrivée à l'étape $i",{i:i+1})
			steps.push(lipos(end))
			if (html.length>1)
				 return li(routeSummary+ul(steps.join('')))
			else return steps.join('')
			})

		var summary
		if (this.htmlsummary) summary=this.htmlsummary
		else { 
			var distxt= unittxt(pos)
			var tempstxt= timetxt(time)
			var mn= Math.round(time/60.)%60
			summary= _('<b>Distance $dist duré environ $temps </b>', {dist:distxt, temps:tempstxt})
			}

		var allhtml= summary+'<ul>'+routes.join('')+'</ul>'
		this.dirDiv.innerHTML= allhtml
		},

	makeHelper: function(icon,pos){
		var ret= SegRouter.jz_superP.makeHelper.call(this,icon,pos)
		if (this.dirDiv && this.dirHelp) this.dirDiv.innerHTML= this.dirHelp
		return ret
		}

	})


$.GSegRouter= Class(SegRouter,{
	requests: false, //
	cookie: 'googleroute',
	dirDivName: 'directions', //name of div that will contain html directions

	jz_init: function(map,ops){
		this.requests= []
		GSegRouter.jz_superP.jz_init.call(this,map,ops) //super method
		return this
		},
	
	clearSeg: function(pos){
		var req= this.requests[pos]
		if (req) req.clear()
		GSegRouter.jz_superP.clearSeg.call(this,pos) //super method
		},

	insertSeg: function(pos){
		this.requests.splice(pos,0,false)
		GSegRouter.jz_superP.insertSeg.call(this,pos) //super method
		},

	delSeg: function(pos){
		GSegRouter.jz_superP.delSeg.call(this,pos) //super method
		this.requests.splice(pos,1)
		},

	updateSeg: function(pos){
		this.clearSeg(pos)
		var req= this.requests[pos]
		var start= this.markers[pos].getLatLng()
		if (pos>=this.markers.length) alert('oups pos='+pos+' ml='+this.markers.length)
		if (!this.markers[pos+1]) alert('oups2 pos='+pos+' ml='+this.markers.length+' mpos+1='+this.markers[pos+1])
		var end= this.markers[pos+1].getLatLng()

		if (!req) {
			req= this.requests[pos]= new GDirections()
			GEvent.addListener(req,'load',GEvent.callbackArgs(this,this.doGDirLoad,req))
			GEvent.addListener(req,'error',GEvent.callbackArgs(this,this.doGDirError,req))
			}

		var query= req.jz_query= [ ''+start.lat()+','+start.lng(), ''+end.lat()+','+end.lng() ]
		var ops= req.jz_ops = {
			getPolyline:true,
			getSteps:true,
			preserveViewport:true,
			locale: _('locale')
			}
		req.loadFromWaypoints( query,ops) //dirflg:'h', avoidHighways:true, avoidHighway:true, avhwy:true, ddopt_avhwy:true})
		},

	doGDirLoad: function(gdir){
		var pos= indexOf(this.requests,gdir)
		if (pos<0) return //could through error ...

		//Be carfull cant clear becuase that wil reste the gdir
		var segPoly= gdir.getPolyline()
		var segSummary= gdir.getSummaryHtml() //if one route same as step summary
		if (gdir.getNumRoutes() != 1) {
			alert('gdir numroutes='+gdir.getNumRoutes()+' expected 1')
			return
			}
		var route= gdir.getRoute(0)
		var routeinfo= {
			summary: route.getSummaryHtml(),
			dist: route.getDistance(),
			time: route.getDuration(),
			steps: mapf(route.getNumSteps(), function(j){
				var step=route.getStep(j)
				return  { html: step.getDescriptionHtml(),
					dist: step.getDistance(),
					time: step.getDuration()}
				})
			}

		//this.clearSeg(pos) done in updateSeg
		this.setSeg(pos,false,segPoly,routeinfo)
		this.setHtml()
		},

	doGDirError: function(gdir){ //this will be the GDirectios object
		//alert('in google err')
		var statusinfo= gdir.getStatus()
		if (statusinfo.code == 620){
			//ok lets waut a while and try again
			setTimeout(function(){gdir.loadFromWaypoints( gdir.jz_query, gdir.jz_ops)},100+(Math.random()*200))
			}
		else alert('Google error stat='+statusinfo.code+' '+statusinfo.request)
		}


	})


$.RSegRouter= Class(SegRouter,{
	requests: false, //
	cookie: 'motoneigeroute',
	network: 'def-network',
	routeStyle: {color: "#ffff00", weight:7, opacity:0.6},
	
	jz_init: function(map,ops){
		this.requests= []
		//jz.superClsP(GSegRouter).jz_init.call(this,map,ops)
		RSegRouter.jz_superP.jz_init.call(this,map,ops) //super method
		return this
		},
	
	clearSeg: function(pos){
		var req= this.requests[pos]
		if (req) {
			req.abort()
			req._jz_router= req.onreadystatchange= undefined //help gc
			}
		this.requests[pos]= false
		RSegRouter.jz_superP.clearSeg.call(this,pos) //super method
		},

	insertSeg: function(pos){
		this.requests.splice(pos,0,false)
		RSegRouter.jz_superP.insertSeg.call(this,pos) //super method
		},

	delSeg: function(pos){
		RSegRouter.jz_superP.delSeg.call(this,pos) //super method
		this.requests.splice(pos,1)
		},

	updateSeg: function(pos){
		this.clearSeg(pos)
		var start= this.markers[pos].getLatLng()
		var end= this.markers[pos+1].getLatLng()

		var query= _('/app/findroute2?network=$network&start=$start&end=$end',
			{network:this.network, start:start, end:end})

		//alert('rseg router doing query=\n'+query)
		var req= this.requests[pos]= newXMLHttpRequest()
		req.open('GET',query)
		req._jz_router= this
		//req._jz_pos= pos
		req.onreadystatechange= function(){
			if (req.readyState != 4) return //wait for end ...
			if (!req._jz_router) return //cause not much to do ...
			if (req.status == 200) req._jz_router.doUpdateSegReq(req)
			if (!jz.IE) req.onreadystatechange= undefined //IE does not like this line dno why ...
			req._jz_router.requests[pos]= undefined
			req._jz_router=  undefined
			}
		req.send(null)
		},

	doUpdateSegReq: function(req){
		var pos= indexOf(this.requests,req)
		if (pos<0) return //could through error ...
		var resp= req.responseXML
		
		var pts=  innerText('epoints',resp)
		var lvls= innerText('lvls',resp)
		var numsteps= parseInt(innerText('numsteps',resp))
		var distance= parseFloat(innerText('distance',resp))
		if (!pts || !lvls) return false

		var steps= mapf(numsteps, function(stepnum){
				var stepid= 'step_'+stepnum
				var dm= parseFloat(innerText(stepid+'.dist',resp))
				var ds= dm/(50000./3600.) // metre/(kmh/60min*60sec) 
				return {
					html: innerHTML(stepid+'.deschtml',resp),
					dist: { meters:dm},
					time: { seconds:ds}
					}
				})
		var html= innerHTML('tpath',resp)
		var debug= innerHTML('debug',resp)
		if (debug) html+=debug
		
		var routeinfo= {
			summary: '',
			dist:  { meters: distance},
			time:  { seconds: distance/(50000./3600.)},
			steps:steps,
			otherhtml:html
			}

		this.setSeg(pos, false, newEPolyline(pts,lvls,this.routeStyle),routeinfo)
		this.setHtml()
		}

	})


$.PolyRouter= Class(MRouterBase,{
	//Polyline based router
	//Line is a poly that spreads througn multiple waypoints
	poly: false,

	jz_init: function(map,ops){
		this.segments= false
		jz.superClsP(PolyRouter).jz_init.call(this,map,ops)
		return this
		},

	dumppts: function(){
		var poly=this.poly
		if (!poly) return []
		return mapf(poly.getVertexCount(),function(i){ return poly.getVertex(i)})
		},

	doPolyClick: function(seg,latlng){
		alert('click on poly at '+latlng)
		},

	pathUpdateEnd: function(pos,action){
		// this is called in all circumstances insert,move and remove
		// action is moved inserted or removed
		this.clearpoly()
		if (this.markers.length<2) return //need atleast 2 points to draw a line ... bye
		this.setPoly(this.dumpWaypoints())
		},

	setPoly: function(points,poly){
		if (!poly) poly= newPolyline(points,this.routeStyle)
		else update(poly,this.routeStyle)
		poly.clickable= true
		var thisrouter= this
		GEvent.addListener(poly,'click',function(latlng){ thisrouter.doPolyClick(this,latlng) })
		this.poly= poly
		this.map.addOverlay(poly)
		if (!this.showen && poly.hide) poly.hide()
		},

	clearPoly: function(){
		if (this.poly) this.map.removeOverlay(this.poly)
		this.poly= false
		},

	show: function(){
		var poly= this.poly
		if (poly && poly.show) poly.show()
		return PolyRouter.jz_superP.show.call(this) // goto super cls ...
		},

	hide: function(){
		var poly=this.poly
		if (poly && poly.hide) poly.hide()
		return PolyRouter.jz_superP.hide.call(this) // goto super cls ...
		}

	})


$.GPolyRouter= Class(PolyRouter,{

	//Polyline based router
	//Line is a poly that spreads througn multiple waypoints
	gdir: false, //gDirectionsObject for this router ...

	jz_init: function(map,ops){
		var gdir= this.gdir= new GDirections()
		GEvent.bind(gdir,'load',this,this.doGDirLoad)
		GEvent.bind(gdir,'error',this,this.doGDirError)
		this.dirDiv= getId('directions')
		//jz.superClsCall(GPolyRouter,'jz_init',this,map,ops)
		//PolyRouter.prototype.jz_init.call(this,map,ops)
		jz.superClsP(GPolyRouter).jz_init.call(this,map,ops)
		return this
		},

	pathUpdateEnd: function(pos,action){
		// this is called in all circumstances insert,move and remove
		// action is moved inserted or removed
		if (this.markers.length<2){
			//need atleast 2 points to draw a line ... bye
			this.clearPoly()
			return
			}
		this.gdir.clear()
		var query= mapf(mapf(this.markers,'getLatLng()'),'lat()+","+lng()')
		//alert('doing q='+query)
		this.gdir.loadFromWaypoints(query,{
			getPolyline:true,
			getSteps:true,
			preserveViewport:true,
			locale: 'fr_CA'
			}) //dirflg:'h', avoidHighways:true, avoidHighway:true, avhwy:true, ddopt_avhwy:true})
		},

	//TODO: add to language ....
	doGDirLoad: function(){
		var ut= unittxt
		var gdir= this.gdir
		this.clearPoly()
		this.setPoly(false,gdir.getPolyline())

		if (!this.dirDiv) return //ok no directions we are done ..

		var li= function(c){ return tag('li',c) }
		var tripSummary= '<span style="font-weight:bold; font-size:133%">Trajet:'+gdir.getSummaryHtml()+'</span>'
		var numRoutes= gdir.getNumRoutes()
		var pos= 0.0
		var routes= mapf(numRoutes,function(i){
			var route= gdir.getRoute(i)
			var routeSummary=  '<span style="font-weight:bold;">Étape '+(i+1)+': '+route.getSummaryHtml()+'</span>'
			var steps= mapf(route.getNumSteps(), function(j){
				var step=route.getStep(j), dist=step.getDistance(), time=step.getDuration(), at=pos
				pos+= dist.meters
				return li(ut(a)+' '+step.getDescriptionHtml()+', pour '+ut(dist.meters)+' ('+time.html+')')
				})
			if (i == numRoutes-1) steps.push(li('Arrivée à la fin du trajet'))
			else steps.push(li("Arrivée à l'étape "+(i+2)))
			return li(tag('ul',routeSummary+steps.join('')))
			})
		this.dirDiv.innerHTML= tag('ul',tripSummary+routes.join(''))
		},

	doGDirError: function(){ //this will be the GDirectios object
		//alert('in google err')
		var gdir= this.gdir
		var statusinfo= gdir.getStatus()
		alert('Google error stat='+statusinfo.code+' '+statusinfo.request)
		}
	})

//Directions router expects a target this is a plug in ....
$.TargetRouter= { //this is a plug in
	target: new GLatLng(47.1,-71.1),
	
	jz_init: function(map,ops){
		if (!ops) ops={}
		if (!ops.target){
			if (!ops.cookie) ops.cookie=this.cookie
			return this.constructor.jz_superCls(map,ops) //a TargetRouter expects a target ...
			}
		var ret= this.constructor.jz_superP.jz_init.call(this,map,ops)
		return ret
		},

	initWaypoints: function(waypoints){
		if (!waypoints) waypoints=[]
		if ( (waypoints.length<1) || ((waypoints.length == 1 ) && mCalcDistance(waypoints[0],this.target)<1.0)) waypoints=[this.target]
		else if ( (waypoints.length == 1 ) || (mCalcDistance(waypoints[waypoints.length-1],this.target)>0.1)){
			//sorry cant keep waypoints no end or end is to far from target
			waypoints=[waypoints[0], this.target]
			}
		var router=this
		dof(waypoints,function(wp){router.addMarker(wp)})
		},

	initHelpers: function(waypoints){
		//Gdir always has a target so if only one waypoint start is missing
		var wplen= waypoints && waypoints.length || 0
		if (wplen<2) this.addStartHelper()
		},

	addEndHelper:  function(){ return this.endHelper= false },


	//Hide end marker patchs ....

	changeMarkerTo: function(pos,icon,latlng){
		var ret= this.constructor.jz_superP.changeMarkerTo.call(this,pos,icon,latlng)
		// hiding management
		if (icon === this.endIcon){
			//alert('end hit at '+pos)
			this.markers[pos].hide() //dont show end icon
			}
		},

	show: function(){
		var ret= this.constructor.jz_superP.show.call(this) // goto super cls ...
		//Patch
		var m=this.markers
		if (m.length) m[m.length-1].hide()
		}

	}

$.GDirRouterOld= Class(GSegRouter,{
	cookie: 'GDirRouter',
	target: new GLatLng(47.1,-71.1),
	
	jz_init: function(map,ops){
		if (!ops) ops={}
		if (!ops.target){
			if (!ops.cookie) ops.cookie='GDirRouter'
			return GSegRouter(map,ops) //Gdir expects a target ...
			}
		var ret= GDirRouter.jz_superP.jz_init.call(this,map,ops)
		return ret
		},

	initWaypoints: function(waypoints){
		if (!waypoints) waypoints=[]
		if (waypoints.length<1) waypoints=[this.target]
		else if ( (waypoints.length == 1 ) || (mCalcDistance(waypoints[waypoints.length-1],this.target)>0.1)){
			//sorry cant keep waypoints no end or end is to far from target
			waypoints=[waypoints[0], this.target]
			}
		var router=this
		dof(waypoints,function(wp){router.addMarker(wp)})
		},

	initHelpers: function(waypoints){
		//Gdir always has a target so if only one waypoint start is missing
		var wplen= waypoints && waypoints.length || 0
		if (wplen<2) this.addStartHelper()
		},

	addEndHelper:  function(){ return this.endHelper= false },


	//Hide end marker patchs ....

	changeMarkerTo: function(pos,icon,latlng){
		var ret= GDirRouter.jz_superP.changeMarkerTo.call(this,pos,icon,latlng)
		// hiding management
		if (icon === this.endIcon){
			//alert('end hit at '+pos)
			this.markers[pos].hide() //dont show end icon
			}
		},

	show: function(){
		var ret= GDirRouter.jz_superP.show.call(this) // goto super cls ...
		//Patch
		var m=this.markers
		if (m.length) m[m.length-1].hide()
		}

	})

$.GDirRouter= Class(GSegRouter,TargetRouter)

$.RDirRouter= Class(RSegRouter,TargetRouter)

$.prefixIs= function(str,prefix){ return str.substring(0,prefix.length)==prefix}

$.DynaRouter= Class(Object,{
	
	jz_init: function(map,ops){
		var network= (ops['network'] || 'google').toLowerCase()
		ops['network']= network
		if (contains(['google','route','routes'],network)) return GDirRouter(map,ops)
		if (prefixIs(network,'pmn') || prefixIs(network,'motoneige')) return RDirRouter(map,ops)
		if (prefixIs(network,'velo')) return RDirRouter(map,ops)
		if (prefixIs(network,'pqd') || prefixIs(network,'motoneige')) return RDirRouter(map,ops)
		if (network=='aucun') return SegRouter(map,ops)
		return GSegRouter(map,ops)
		}
	})
//$.Router= GMRouter
$.Router=DynaRouter
//$.Router= GPolyRouter

}
//end of file

