with(jzGMap){

importFrom(jz,'newXMLHttpRequest innerText innerHTML update mapf extractf contains indexOf setCookie setCookieForever getCookie _ IE _doBREAK parseUrl scanChecksFor getId')
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
		var atr= (!ops)?'':mapf(ops,function(v,k){ return ' '+(k=='cls'?'class':k)+'="'+v+'"' },[]).join('')
		return ['<',name,atr,'>',content,'</',name,'>'].join('')
		}

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

$.closestTo= function(pts,tpt,minerr){
	//return index of closest point to tpt
	if (!minerr) minerr=0.001 //a meter
	var cDst=99999.0, cPos= -1
	//use mapf so we can break
	mapf(pts,function(pt,pos){
		var dst=mCalcDistance(pt,tpt)
		if (dst>=cDst) return
		//we got a closer pt
		cDst=dst, cPos=pos
		if (dst<minerr) return _doBREAK
		},false) //dont collect results
	return [cPos,cDst]
	}

$.indexBefore= function(pts,tpt,minerr){
	var ret= closestTo(pts,tpt,minerr)
	var pos=ret[0], dst=ret[1]
	if (pos==pts.length-1) return pos //first so start has to be before ....
	if (mCalcDistance(pts[pos+1],tpt)<mCalcDistance(pts[pos+1],pts[pos])) return pos+1
	return pos
	}

$.pts2e= function(pts,res){
	if (res === undefined) res=6.
	res= Math.pow(10.,res)
	
	var olat=0, olng=0, ret=[]
	dof(pts,function(ll){
		var lat=Math.round(res*ll.lat()), lng=Math.round(res*ll.lng())
		var xlat=lat-olat, xlng=lng-olng
		olat+=xlat
		olng+=xlng
		ret.push(xlat)
		ret.push(xlng)
		})
	return ret
	}

$.pts2es= function(pts,res,sep){
	if (!sep) sep= ','
	return pts2e(pts,res).join(sep)
	}

$.e2pts= function(edata,res){
	if (res == undefined) res=6.
	res= Math.pow(10.,res)
	var lat=0,lng=0
	return mapf(edata.length/2,function(i){
		var idx=i*2
		lat+=edata[idx]
		lng+=edata[idx+1]
		return newlatlng(lat/res,lng/res) })
	}

$.es2pst= function(es,res,sep){
	if (!sep) sep=','
	return e2pts(mapf(es.split(sep),parseFloat,[]),res)
	}

$._uiNames= [ 'tq', 'reg', 'local' ]
$.doCostUIUpdate= function(){
	if ( !( mapDiv && mapDiv.vMap && mapDiv.vMap.router && mapDiv.vMap.router.setInfo )) return

	var info={}, update=false

	var speeds={}
	dof(_uiNames,function(name){
	    var elem= getId(name+'-speed')
	    if (elem && parseFloat(elem.value)) speeds[name.charAt(0).toUpperCase()]=parseFloat(elem.value)*1000.,update=true
	    })

	if (update) info.speeds=speeds

	info.usetemps= opttemps= scanChecksFor('it-opt')=='temps', update=true
	var costs= mapf(_uiNames,function(name){ return scanChecksFor(name+'-scale')}).join(',')
	if (costs.length) info.cost=costs,update=true

	var units= scanChecksFor('it-um')
	if (units) {setunit(units); update=true; }

	//alert('cost update info='+mapf(info,function(v,k){return k+':'+v},[]).join(','))
	if (update) mapDiv.vMap.router.setInfo(info)
	}

$.doCostUIRecenter= function(){
	if ( mapDiv && mapDiv.vMap && mapDiv.vMap.router && mapDiv.vMap.router.setInfo ){
	    dof(['tq-scale','reg-scale','local-scale'],function(name){
		var elem=getId(name+'.2')
		if (elem) elem.checked='checked'
		})
	    }
	doCostUIUpdate()
	}

$.doInitCostUI= function(){
	if ( !( mapDiv && mapDiv.vMap && mapDiv.vMap.router && mapDiv.vMap.router.setInfo )) return
	
	var router= mapDiv.vMap.router

	var uiDiv= getId('it-options')
	if (!uiDiv) return //nothing to init

	if (router.speeds) {
	    var spdtxt=mapf(router.speeds,function(v){return (v/1000).toString()})
	    dof(_uiNames,function(nm){
		//if (!nm || nm.length<1) return
		//alert('num ='+(typeof nm)+' : '+nm)
		if (nm.charAt(0).toUpperCase() in spdtxt){
		    var elem= getId(nm+'-speed')
		    var val= spdtxt[nm.charAt(0).toUpperCase()]
		    if (elem && val) {
			dof(elem.options,function(option){ 
			    if (option.value==val){
				option.selected=true
				}
			    })
			} 
		    else alert('no try id='+elem.id+' op val='+val)
		    }
		})
	    }

	if (router.cost) {
	    var costvalues= router.cost.split(',')
	    dof(_uiNames,function(nm,idx){
		var name= nm+'-scale',val=costvalues[idx]
		var elems= getElementsByNames(uiDiv,name,'input')
		dof(elems,function(option){ if (option.value==val) option.checked=true })
		})
	    }

	var um= unitname
	if (um)
	    dof(getElementsByNames(uiDiv,'it-um','input'),function(option){ if (option.value==um) option.checked=true })
	}


$.doRouterReset= function(){
	if ( !( mapDiv && mapDiv.vMap && mapDiv.vMap.router )) return
	mapDiv.vMap.router.reset()
	setunit('km')
	doInitCostUI()
	}


$.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 
	pauseIcon: MidIcon,
	//pauseIcon: PauseIcon,
	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 ...
	ewaypointid: '',
	showen: true,
	units: '', //use sys default
	tracker: false,
	addOnClick: true,
	
	// attribute functions function that are passed as unbound 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,this.units), after:unittxt(after,this.units), total:unittxt(total,this.units) } 
		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)
		},


	makeOvlFor: function(map){
		return this.jz_init(map)
		},

	jz_init: function(map,ops){
		this.map= map
		//var div= map.getContainer()
		update(this,ops)
		this.markers= []
		if (!map) {
			return this
			}
		GEvent.bind(map,'singlerightclick',this,this.dorightclick)
		GEvent.bind(map,'dblclick',this,this.dodblclick)

		var waypoints
		if (this.rwaypoints){
			waypoints=this.rwaypoints
			//alert('using rwaypoints='+waypoints)
			}
		else {
			if (this.waypoints){
				waypoints=ops.waypoints.split(',')
				waypoints=mapf(waypoints.length/2,
					function(x){ return [parseFloat(waypoints[2*x]),parseFloat(waypoints[(2*x)+1])]},
					[])
				}
			else if (this.ewaypoints) {
				waypoints= this.ewaypoints.replace('[','').replace(']','')
				waypoints= mapf(waypoints.split(','),function(v){ return parseInt(v)},[])
				waypoints= this.wpe2wp(waypoints)
				}
			else if ( (waypoints=getId('waypoints')) && waypoints.jz_data) waypoints=waypoints.jz_data
			else if ( (waypoints=getId('ewaypoints')) && waypoints.jz_data) waypoints= this.wpe2wp(waypoints.jz_data)
			else waypoints= false

			if (!waypoints && this.cookie) waypoints= this.initFromCookie()

			if (waypoints){
				waypoints=mapf(waypoints,
					function(wp){ return newLatLng(wp[0],wp[1]) })
				}
			}
		map.router=this
		this.initWaypoints(waypoints)
		//use helpers instead ...
		//GEvent.bind(map,'click',this,this.doclick)
		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 && this.addOnClick && this.showen) 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)
// 		},

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

	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,icon){
		return this.insertPos(this.markers.length,latlng,icon)
		},


	//startend interface
	addMarkerAt: function(pos,latlng,icon){ 
		var markers=this.markers
		if (!icon) icon=this.pauseIcon
		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()
		},

	removedMarkerAt: function(pos,marker){ 
		if (!marker) return
		this.map.removeOverlay(marker)
		marker.router=false
		},

	insertPos: function(pos,latlng,icon){ //pos is before
		this.markers.splice(pos,0,false)
		this.addMarkerAt(pos,latlng,icon)
		this.pathUpdate(pos,'inserted')
		},

	//API 
	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){
		var marker= this.markers.splice(pos,1)[0]
		this.removedMarkerAt(pos,marker)
		this.pathUpdate(pos,'removed') //attention si dernier pos=pos-1 ... TODO:
		},

	reset:	function(){
		//var self= this, fRemoveMarkerAt= MRouterBase.prototype.removedMarkerAt
		//dof(this.markers,function(marker,pos){ fRemoveMarkerAt.call(self,pos,marker) })
		var map=this.map
		dof(this.markers,function(marker){ map.removeOverlay(marker); marker.router=false })
		this.markers=[]
		this.cookieUpdate()
		this.initWaypoints(this.markers)
		},

	// 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){
		this.pathUpdate(0,"initstart")
		if (waypoints){ 
		    var router=this
		    dof(waypoints,function(wp){router.addMarker(wp)})
		    }
		this.pathUpdate(this.markers.length,"initend")
		},

	reloadAll: function(){ //reload the path implemented by sons
		},
		

	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()
		//alert('doing '+action+' '+pos)
		return this.pathUpdateEnd(pos,action)
		},

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

	cookieUpdate: function(){
		if (!(this.cookie || this.ewaypointid||this.tracker)) return
		var info=this.getCookieInfo()
		var txt=mapf(info,function(v,k){ return k+':'+v},[]).join(',') 
		//if (txt) 
		if (this.cookie) {
			setCookieForever(this.cookie,'{'+txt+'}')
			}

		//url box updated exactly in same conditions so done here
		var urlbox= getId('url-box-text')
		if (urlbox) urlbox.value= jz.getfullurl()

		if (this.tracker) this.sendUpdate(this.tracker)
		},

	sendUpdate: function(tracker){
		if (!tracker) return
		var qdata= 'waypoints='+this.getWppTxt()
		if (this.trackerreq){
		    this.trackerreq.abort()
		    this.trackerreq=false
		    }
		var req=this.trackerreq= newXMLHttpRequest()
		var q='http://www.viaexplora.com/app/set/'+this.tracker+'?'+qdata
		//alert('doing q='+q)
		req.open('GET',q)
		var self=this
		req.onreadystatechange= function(){
		    if (req.readyState != 4) return //wait for end ...
		    if (!jz.IE) req.onreadystatechange= undefined //IE does not like this line dno why ...
		    self.trackerreq=false
		    }
		req.send(null)
		},


	getCookieInfo: function(){
		var txt=this.getWpeTxt()
		if (!txt) return {}
		return { WpeTxt: '['+txt+']' }
		},

	readCookieInfo: function(){
		if (!this.cookie) return {}
		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)
		return ret	  // also not ret= added to force parsing of static dict {K:v ...} as object and not code ...
		},

	initFromCookie: function(){
		var rcookie=this.readCookieInfo()
		//var txt=mapf(rcookie,function(v,k){ return k+':'+(typeof v)+'='+v},[]).join(',') 
		//alert('init from cookie '+this.cookie+' = '+txt)
		var ewaypoints= rcookie.WpeTxt
		delete rcookie.WpeTxt
		update(this,rcookie)
		if (!ewaypoints) return false
		return this.wpe2wp(ewaypoints)
		},

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

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

	getWaypoints: function(){ return this.markers },
	getPoints:	function(){ return this.markers },

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

	getWppTxt: function(){
		return jz.mapf(this.getWaypoints(),function(marker){
			var latlng= marker.getLatLng()
			return latlng.lat().toFixed(6)+','+latlng.lng().toFixed(6)
			}).join('|')
		},

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

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

	dumppts: function(){ 
		return mapf(this.getPoints(),function(marker){ return marker.getLatLng() })
		},

	dumpsegments: function(){
		var wpts= this.dumpWaypoints()
		// view each line between 2 way points as a segment
		//var ret=mapf(wpts.length-1,function(idx){ return [wpts[idx],wpts[idx+1]] },[])
		//or
		// view all waypoints as a single segment
		var ret=[ this.dumppts() ]
		return ret
		},

	dumpsegmentstrs: function(){
		var ret= mapf(this.dumpsegments(),function(vect){ return pts2es(vect)})
		return ret
		},

	dumpstrs: function(){
		var wptxt= this.getWpeTxt(',')
		var segs=  this.dumpsegmentstrs()
		//alert('dump str wptxt='+wptxt)end
		return  wptxt+'|'+segs.join('|')
		}
	})


$.StartEndManager =Class(MRouterBase,{
	startIcon: StartIcon,
	endIcon:   EndIcon,

	addMarkerAt: function(pos,latlng,icon){
		if (!icon){ //no icon maybe we have a better default
		    var markers=this.markers, mlen=markers.length
		    if (pos==0) { 
			icon= this.startIcon
			//we are going to add a start icon should we remove one?
			if (mlen>1 && markers[1].getIcon()==this.startIcon)
			    this.changeMarkerTo(1,this.pauseIcon)
			}
		    else if (pos==mlen-1){
			icon= this.endIcon
			//we are going to add a end icon should we remove one?
			if (mlen>1 && markers[mlen-2].getIcon()==this.endIcon)
			    this.changeMarkerTo(mlen-2,(mlen-2<=0)?this.startIcon:this.pauseIcon)
			}
		    }
		StartEndManager.jz_superP.addMarkerAt.call(this,pos,latlng,icon)
		},

	removedMarkerAt: function(pos,marker){
		if (marker){ //no icon maybe we have a better default
		    icon= marker.getIcon()
		    if (pos==0 && icon==this.startIcon) { //or pos==0 removing start
			
			//we are removing starticon sgould we readd it ?
			if (this.markers.length>0 && this.markers[0].getIcon()!=this.endIcon)
			    this.changeMarkerTo(0,this.startIcon)
			}
		    else if (pos==this.markers.length && icon==this.endIcon){ // or pos=this.markers.length
			//we are going to remove a end icon should we add one?
			if (this.markers.length>1 && this.markers[this.markers.length-1].getIcon()!=this.endIcon)
			    this.changeMarkerTo(this.markers.length-1,this.endIcon)
			}
		    }
		StartEndManager.jz_superP.removedMarkerAt.call(this,pos,marker)
		},


	changeMarkerTo: function(pos,icon){
		var markers=this.markers
		var oldmarker= markers[pos]
		if (!oldmarker) {alert('startend error'); return }

		if (oldmarker.getIcon()==icon) return //no need to change it ...
		latlng=oldmarker.getLatLng()
		markers[pos]= false
		this.removedMarkerAt(pos,oldmarker)
		this.addMarkerAt(pos,latlng,icon)
		}

	})


$.HelperManager= Class(StartEndManager,{ //Class(Object,{ //This is a plug-in to augment routers ....

	helperHoverContent: _('directions aide marqeur'),
	startIcon: StartIcon,
	endIcon:   EndIcon,

	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,router.endIcon)
			}
		},


	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) },
	
	//insertion points ...

	pathUpdateEnd: function(pos,mode){
		// Check if end have changed ....
		HelperManager.jz_superP.pathUpdateEnd.call(this,pos,mode)
		
		var markers=this.markers, ml=markers.length
		if (pos<2){//change occured at begging
		    //checkfor remove start
		    if (this.startHelper && (ml && markers[0].getIcon()==this.startIcon)){
			this.clearHelper(this.startHelper)
			this.startHelper=false
			}
		    else if (!this.startHelper && (!ml || markers[0].getIcon()!=this.startIcon)){
			this.addStartHelper()
			}
		    }
		if (pos>ml-3){//change at end check end
		    if (this.endHelper && ( ml && markers[ml-1].getIcon()==this.endIcon)){
			this.clearHelper(this.endHelper)
			this.endHelper=false
			}
		    else if (!this.endHelper && (!ml || markers[ml-1].getIcon()!=this.endIcon)){
			this.addEndHelper()
			}
		    }
		},
/*
	 initWaypoints: function(waypoints){//add initial start stop icons
		HelperManager.jz_superP.initWaypoints.call(this,waypoints)
		var wplen= waypoints?waypoints.length:0
		if (wplen<1) this.addStartHelper()
		if (wplen<2) this.addEndHelper()
		},

	reset: function(){
		HelperManager.jz_superP.reset.call(this)
		if (!this.startHelper)  this.addStartHelper()
		if (!this.endHelper)	this.addEndHelper()
		},
*/
	show: function(){
		HelperManager.jz_superP.show.call(this)
		if (this.startHelper) this.startHelper.show()
		if (this.endHelper) this.endHelper.show()
		},

	hide: function(){
		HelperManager.jz_superP.hide.call(this)
		if (this.startHelper) this.startHelper.hide()
		if (this.endHelper) this.endHelper.hide()
		}
	})


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

	jz_init: function(map,ops){
		this.segments= []
		this.html= []
		SegRouter.jz_superP.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)
		},

	reset: function(){
		var map= this.map
		dof(this.segments,function(seg){map.removeOverlay(seg)})
		this.segments=[]
		this.html=[]
		if (this.dirDiv && this.dirHelp) this.dirDiv.innerHTML= this.dirHelp
		SegRouter.jz_superP.reset.call(this)
		},
		
	reloadAll: function() {
		return this.reloadAllSegments()
		},

	reloadAllSegments: function(){
		var self=this
		dof(this.segments,function(v,pos){
		    //alert('update seg'+pos)
		    self.updateSeg(pos)
		    })
		},

	pathUpdateEnd: function(pos,action){
		// this is called in all circumstances insert,move and remove
		// action is moved inserted or removed
		SegRouter.jz_superP.pathUpdateEnd.call(this,pos,action)
		if (action=='inserted' && this.markers.length>1) this.insertSeg(pos)
		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)
		// Check for help instead of directions
		if (!this.segments.length && this.dirDiv && this.dirHelp) this.dirDiv.innerHTML= this.dirHelp
		},

	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,this.units)+' 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
		},

	dumpsegments: function(){
		var ret= mapf(this.segments,function(seg){
			if (!seg) return []
			return mapf(seg.getVertexCount(),function(idx){ return seg.getVertex(idx)},[])
			})
		//alert(' dump seg segments='+ret)
		return ret
		},

	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 ...
		},

	makeRouteSummary: function(vars){
		return span({cls:"dir-troncon-txt"}, _("Étape $i: $dist (environ $durt)",vars))
		},

	makeStepSummary: function(vars){
		var step= vars.step
		var units= vars.units
		return li({cls:"dir-etape"},span({cls:"dir-etape-txt"},
			    _("$postxt $stephtml, pour $disthtml ( $timehtml )",{
				disthtml:unittxt(step.dist.meters,units),
				timehtml:timetxt(step.time.seconds),
				stephtml:step.html,
				postxt:unittxt(vars.cpos,units)
				})
			    ))
		},

	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 self= this
		
		var routes=mapf(html,function(routeinfo,i){
			var startPos=pos, startTime= time

			var dist='', durt=''
			if (routeinfo.dist){
				dist=unittxt(routeinfo.dist.meters,self.units)
				durt=timetxt(routeinfo.time.seconds)}

			var routeSummary= self.makeRouteSummary({i:i+1, dist:dist, durt:durt})
				
			var steps= mapf(routeinfo.steps,function(step,j){
				var stephtml= self.makeStepSummary({step:step, idx:j, units:self.units, cpos:pos, ctime:time})
				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( li({cls:"dir-etape"},span({cls:"dir-etape-txt"},unittxt(pos,this.units)+'  '+end))  )
			if (html.length>1)
				 return li({cls:"dir-troncon"},routeSummary+ul({cls:'dir-troncon'},steps.join('')))
			else return steps.join('')
			})

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

		if (html.length>1)
		    var allhtml= summary+ul({cls:'dir-list-troncons'},routes.join(''))+this.htmlfooter
		else
		    var allhtml= summary+ul({cls:'dir-troncon'},routes.join(''))+this.htmlfooter
		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
	reqdefops:  {
		getPolyline:true,
		getSteps:true,
		preserveViewport:true,
		locale: _('locale'),
		avoidHighways: false
		},


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

	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))
			}
		else { //do abort 
		    }
		var query= req.jz_query= [ ''+start.lat()+','+start.lng(), ''+end.lat()+','+end.lng() ]
		var ops= req.jz_ops= this.reqdefops
		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)},500+(Math.random()*2000))
			}
		else alert('Google error stat='+statusinfo.code+' '+statusinfo.request)
		}
	})


$.GSegRouterVelo= Class(GSegRouter,{
	cookie: 'googleroutevelo',
	reqdefops:  {
		getPolyline:true,
		getSteps:true,
		preserveViewport:true,
		locale: _('locale'),
		avoidHighways: true
		}
	})


$.RSegRouter= Class(SegRouter,{
	requests: false, //
	cookie: 'motoneigeroute',
	network: 'def-network',
	routeStyle: {color: "#ffff00", weight:7, opacity:0.6},
	cost: '',
	
	jz_init: function(map,ops){
		if (!ops.cost){
		  var cost=parseUrl()['cst']
		  if (cost) ops['cost']=cost
		  }
		//alert('creating RSegRouter ops.cost='+ops.cost)
		this.requests= []
		//jz.superClsP(GSegRouter).jz_init.call(this,map,ops)
		RSegRouter.jz_superP.jz_init.call(this,map,ops) //super method
		doInitCostUI(this)
		return this
		},

	reset: function(){
		var self=this
		dof(this.requests,function(req){ self.clearReq(req)}) //works cause clear req does no reffer to this ..
		this.requests= []
		delete this.cost
		RSegRouter.jz_superP.reset.call(this) //super method
		},
	
	setInfo: function(info){
		update(this,info)
		this.cookieUpdate()
		this.reloadAll()
		},

	getCookieInfo: function(){
		var info=RSegRouter.jz_superP.getCookieInfo.call(this) //super method
		if (this.cost) info.cost= '"'+this.cost+'"'
		return info
		},

	clearReq: function(req){
		if (!req) return
		req.abort()
		req._jz_router= req.onreadystatchange= undefined //help gc
		},

	clearSeg: function(pos){
		var req= this.requests[pos]
		if (req) this.clearReq(req)
		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&cost=$cost',
			{network:this.network, start:start, end:end, cost:this.cost})

		//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)
		},

	getStepInfoFromResp: function(stepnum,resp){
		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},
			nomrue: innerText(stepid+'.nomrue',resp)
			}
		},
	    

	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 self=this
		var steps= mapf(numsteps,function(stepnum){ return self.getStepInfoFromResp(stepnum,resp)})
		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()
		},

	makeStepSummary: function(vars){
		var step= vars.step
		var units= vars.units
		return li({cls:"dir-etape"},span({cls:"dir-etape-txt"},
			    _("A $postxt prendre <b>$nomrue</b> pour $distxt ($timetxt)",{
				distxt:unittxt(step.dist.meters,units),
				timetxt:timetxt(step.time.seconds),
				nomrue:step.nomrue,
				postxt:unittxt(vars.cpos,units)
				})
			    ))
		}

	})

$._defSpeed= 50000.
$._speedKeys= ['T','R','L']
$.PMNSegRouter= Class(RSegRouter,{

	cost: '1.0,1.01,1.05',
	
	speeds: { T:_defSpeed, R:_defSpeed, L:_defSpeed },

	jz_init: function(map,ops){
		var speeds=ops.speeds
		if (!speeds) speeds=parseUrl()['spd']
		if (typeof speeds == 'string' && speeds) ops.speeds=this._parseSpeeds(speeds)
		var ret=PMNSegRouter.jz_superP.jz_init.call(this,map,ops) //super method
		},

	reset: function(){
		delete this.speeds

		if (this.dirDiv && getId('tq-pct'))
		    dof(['tq','reg','local'],function(name){
			var elemp=getId(name+'-pct')
			if (elemp) elemp.innerHTML= ''

			var elemd=getId(name+'-km')
			if (elemd) elemd.innerHTML= ''
			})
		
		PMNSegRouter.jz_superP.reset.call(this) //super method
		},

	getCookieInfo: function(){
		var info=PMNSegRouter.jz_superP.getCookieInfo.call(this) //super method
		if (this.speeds && this.speeds != PMNSegRouter.jz_superP.speeds)
		    var speeds=this.speeds
		    info.speeds= '"'+mapf(_speedKeys,function(v){ return speeds[v]}).join(',')+'"'
		return info
		},

	readCookieInfo: function(){
		var cookieinfo= PMNSegRouter.jz_superP.readCookieInfo.call(this)
		if (cookieinfo.speeds) cookieinfo.speeds= this._parseSpeeds(cookieinfo.speeds)
		return cookieinfo  // also not ret= added to force parsing of static dict {K:v ...} as object and not code ...
		},

	_parseSpeeds: function(spdstr){
		var spd={}
		dof(spdstr.split(','),function(v,k){ if (parseFloat(v)) spd[_speedKeys[k]]=parseFloat(v) })
		return spd
		},

	getStepInfoFromResp: function(stepnum,resp){
		var stepid= 'step_'+stepnum
		var dm= parseFloat(innerText(stepid+'.dist',resp))
		var nomrue=innerText(stepid+'.nomrue',resp)
		if (nomrue && nomrue.charAt(0) in this.speeds){
		    var ds= dm/(this.speeds[nomrue.charAt(0)]/3600.)// metre/(mh/60min*60sec
		    //alert('speed did ds='+ds+' was='+dm/(this.speeds[nomrue[0]]/3600.)+' nomrue='+nomrue)
		    }
		else {
		    var ds= dm/(_defSpeed/3600.)// metre/(mh/60min*60sec)
		    //alert('no speed nomrue='+nomrue) // Vlocal = traversiers
		    }
		return {
			html: innerHTML(stepid+'.deschtml',resp),
			dist: { meters:dm},
			time: { seconds:ds},
			nomrue:nomrue
			}
		},



	setHtml: function(){
		PMNSegRouter.jz_superP.setHtml.call(this) // super method

		if (!this.dirDiv || !getId('tq-pct')) return

		var tq= 0
		var reg= 0
		var local= 0
		var total= 0

		dof(this.html,function(routeinfo,i){
			dof(routeinfo.steps,function(step,j){
				var d=step.dist.meters
				total+= d
				if (step.nomrue){
				    switch (step.nomrue.charAt(0)){
					case 'T': tq+= d; break
					case 'R': reg+= d; break
					case 'L': local+= d; break
					}
				    }
				})
			})
		//alert('ops unpdate got total='+total+' tq='+tq+' reg='+reg+' local='+local)
		dof([['tq',tq],['reg',reg],['local',local]],function(info){
		    var name=info[0],dst=info[1]

		    var elemp=getId(name+'-pct')
		    if (elemp) elemp.innerHTML= Math.round(100*dst/total)+'%'

		    var elemd=getId(name+'-km')
		    if (elemd) elemd.innerHTML= unittxt(dst,this.units)
		    })
		}

    })



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

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

	doPolyClick: function(seg,latlng){
		var pos= indexBefore(this.dumpWaypoints(),latlng,0.01)
		this.insertPos(pos,latlng)
		},

	initWaypoints: function(waypoints){
		if (!this.delayable) return jz.superClsP(PolyRouter).initWaypoints.call(this,waypoints)
		if (!waypoints) return

		this.delayed=true
		this.delayedaction=false
		this.delayedpos=false
		var router=this
		dof(waypoints,function(wp){router.addMarker(wp)})
		this.delayed=false
		if (this.delayedaction){
		    this.pathUpdate(this.delayedaction,this.delayedpos)
		    this.delayedaction= false
		    this.delayedpos= false
		    }
		},

	pathUpdate: function(pos,action){
		if (this.delayed) {
		    this.delayedaction= action
		    this.delayedpos= pos
		    return}

		this.cookieUpdate()
		return this.pathUpdateEnd(pos,action)
		},

	pathUpdateEnd: function(pos,action){
		// this is called in all circumstances insert,move and remove
		// action is moved inserted or removed

		//PolyRouter.jz_superP.pathUpdateEnd.call(this,pos,mode)

		this.clearPoly()
		if (this.markers.length<2) return //need atleast 2 points to draw a line ... bye
		this.setPoly(mapf(this.getPoints(),function(pt){return pt.getLatLng()})) //was: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 ...
		},

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

	})
	
	
$.Simple= Class(PolyRouter,{
	//this is a ptah like Poly router but only reports begining and end as waypoints 
	//all other way points are condidered to be part of the segment
	getWaypoints: function(){ 
		//alert('simple get waypoints')
		var len= this.markers.length
		if (len<3) return this.markers //2 or less
		return [this.markers[0],this.markers[len-1]]
		}
	})


$.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

		//? GPolyRouter.jz_superP.pathUpdateEnd.call(this,pos,mode)

		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= function(d){ return unittxt(d,this.units)}
		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), //init force a trarget
	cookie: '',

	jz_init: function(map,ops){
		if (!ops) ops={}
		if (!ops.target){
			//if (!ops.cookie) ops.cookie=this.cookie //why?
			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){
		//alert('target router inwp='+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]
			}
		this.constructor.jz_superP.initWaypoints.call(this,waypoints)
		},

	//manage helpers Never show an end 

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

	
	addMarkerAt: function(pos,latlng,icon){
		if (icon==this.startIcon && this.markers.length==1 && this.afterinit) icon=this.endIcon
		this.constructor.jz_superP.addMarkerAt.call(this,pos,latlng,icon)
		//alert('target watch pos='+pos+'  len='+this.markers.length)
		if (pos==this.markers.length-1 && this.afterinit) this.markers[pos].hide() //dont show last icon
		},
	
	pathUpdateEnd: function(pos,mode){
		// Check if end have changed ....
		if (mode=='initstart') this.ininit= true,  this.afterinit= false
		if (mode=='initend')   this.ininit= false, this.afterinit= true

		this.constructor.jz_superP.pathUpdateEnd.call(this,pos,mode)
		//alert('pathUpdateend '+mode+' '+pos+' l='+this.markers.length)
		if (mode=='initend' && pos){
		    this.markers[pos-1].hide()
		    if (pos==1) this.addStartHelper()
		    }
		},
		
	show: function(){
		this.constructor.jz_superP.show.call(this)
		if (this.markers.length) this.markers[this.markers.length-1].hide()
		},

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


$.GDirRouter= Class(GSegRouter,TargetRouter)
GDirRouter.prototype.cookie= 'googletarget'

$.GDirRouterVelo= Class(GSegRouterVelo,TargetRouter)
GDirRouterVelo.prototype.cookie= 'gvelotarget'

$.RDirRouter= Class(RSegRouter,TargetRouter)

$.PMNDirRouter= Class(PMNSegRouter,TargetRouter)
PMNDirRouter.prototype.cookie= 'pmntarget'

$.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 (network=='gvelo') return GDirRouterVelo(map,ops)
		if (prefixIs(network,'pmn') || prefixIs(network,'motoneige')){
		    ops['htmlfooter']= _('<br />&nbsp;<b>T</b>:Trans-Québec, <b>R</b>:Régional, <b>L</b>:Local')
		    return PMNDirRouter(map,ops)
		    }
		if (prefixIs(network,'velo')) return RDirRouter(map,ops)
		if (prefixIs(network,'moto')) return RDirRouter(map,ops)
		if (prefixIs(network,'pqd')) return RDirRouter(map,ops)
		if (network=='aucun') return SegRouter(map,ops)
		return GSegRouter(map,ops)
		}
	})
//$.Router= GMRouter
$.Router=DynaRouter
//$.Router= GPolyRouter
$._info = function(a){
	alert('welcome to _info')
	if (a.rwaypoints){
		a.rwaypoints=mapf(getId(a.rwaypoints).childNodes,
				function(node){
					if (node.nodeType==1 && node.id) return parseDataFor(node.id)
					else return jz._doIGNORE }
				)
		}
	else a.rwaypoints= false
	var eid=a.ewaypoints?a._elem.id+'_ewaypoints':''
	//alert('doing ied='+eid)
	var cost=parseUrl()['cost']||''
	var router= DynaRouter(false,{network:a.network,rwaypoints:a.rwaypoints, ewaypoints:a.ewaypoints, ewaypointid:eid, cookie:''})
	router.cookie=''
	//alert('router.cookie='+router.cookie)
	if (eid && getId(eid))
	    getId(eid).jz_getter=function(){ return router.dumpstrs() }
	return router
	}
	
jz.DomClasses['Router']=jz.DelaiedFactory(jz.DomClasses.Data,_info )
	
jz.doClickAddPoint= function(ovl,latlng){
	//Remember latlng not set if ovl is ....
	if (!ovl){
		alert('jz.doClickAddPoint')
		return this.router.addMarker(latlng)
		}
	}

$.doRemoveLast= function(mapid){
	var router= getId(mapid).vMap.router
	if (!router){
		alert('No router getId='+jz.getId('form.overlays._map'))
		return
		}
	router.removeLastMarker()
	}

}
//end of file
