function LclMapItem(poi,latlng) {  //constructor func for map item object
	this.poi=poi;
	this.latlng=latlng;
}

function LclResult() {		//constructor func for result object
	this.venuename="";
	this.venuepostalcode="";
	this.venuestate="";
	this.venuephonenumber="";
	this.venueaddress=null;
	this.venuecity=null;
	this.venuedescription="";
	this.flon=null;
	this.flat=null;
	this.venuehasphoto=null;
	this.venuephotourl=null;
	this.hasreviews=null;
	this.reviewrating=null;
	this.numberofreviews=null;
	this.lastreviewdate="";
	this.websiteurl="";
	this.cityguideurl="";
	this.mapItem=null;	//will hold LclMapItem object
	this.bs_distance=null;
	this.category="";
	this.eventname="";
	this.directionsUrl="";
	this.adhasphoto="";
	this.citybest=false;
}

var local={
	debug:true,		//debug messages displayed in firebug console.
	smallMap:false,		// whether to use the static map or the fully featured one
	defaultRadius:5,      //default radius to use in searches.
	mapItems:[],	//holds child array of result sets.
	cssDir:"",	//set later in JSP
	myMap:null,			//ref to MQ map object
	myVControl:null,	//ref to Map control, need to persist as controls are reinitiated on map resize
	myLZControl:null,	//ref to Map control, need to persist as controls are reinitiated on map resize
	wnDiv:null,		//ref to wide Div column element
	nDiv:null,		//ref to narrow Div column element
	wDiv:null,		//ref to narrow Div column element
	paginDiv:null,	//ref to pagination div
	mapWindow:null,		//ref to mapWindow element
	local_hits:null,	//ref to local_hits UL element, hold results
	cmn:null,	//holder for cmn functions API
	panTimeout:null,	//var used to hold ref to timeout if timeout needs to be cleared.
	currStickyRes:null,    //reference to thich results popup is currently open.
	currResSet:null,	//holds current index of Results set which is displayed
	roWin:null,			//reference to RollOver Window
	roWinTimeout:null,	//hold timeout ref for rollover/rollout display
	poiWinTimeout:null,	//hold timeout ref for rollover/rollout display
	b_star:null,
	resultsPages:new Array(),	//hold refs to mapItems searches... all searches might not produce unique results, hence we don't want them all referenced as different results pages.
	currPoi:null,		//reference to which POI is "rolled-over" when accessing popup window functions.
	ddSessionID:null,	//hold ref to driving directions session object.
	ddEntryText:"",
	/* MQ proxy variables */
	myPxyServer:"",
	myPxyPort:"",
	myPxyPath:"/JSAPIProxy/JSReqHandler",
	/* MQ server variables */
	mqPort:"80",
	mqPath:"mq",
	/* MQ objects */
	mqConsts:null, // stores MQ Constant Values
	mqIcon:null, // stores a MQ Icon Object
	myGExec:null, //new MQExec("geocode.access.mapquest.com",mqPath,mqPort,myPxyServer,myPxyPath,myPxyPort),
	myRExec:null, //new MQExec("route.access.mapquest.com",mqPath,mqPort,myPxyServer,myPxyPath,myPxyPort),
	myTAddress:null, //new MQAddress(),
	myFAddress:null, //new MQAddress(),
	myGcColl:null, //new MQLocationCollection("MQGeoAddress"),
	myRtColl:null, //new MQLocationCollection("MQGeoAddress"),
	myBB:null, //used for driving direction bounding box.
	detMapCntr:null, //center of map remembered for details page if user scrolls away from center.

    initVals:function() {
        this.mapWindow=$("mapWindow");
        this.mqIcon = new MQMapIcon();		//setup standard icon to clone, to stop multiple HTTP requests for icon graphics
		this.mqIcon.setImage(cg.imagesDir+"sml_balloon1.png",16,18,true,true);
		this.mqIcon.setShadow(cg.imagesDir+"shadow.png",6,18,16,6,true);
		
    },
	startMap:function(){		//gathers plot point data from HTML and initalises map, plotting points
		var pois = new Array(),x = 1,prnt,hasLatLong=true,myPoint,myIcon;

		var resColl;		//result collection variable
		this.mapItems.push(resColl=new Array());	//add result collection to mapItems array
        var poiColl=new MQPoiCollection();

		prnt = $$("ul.search-results #slr_listing"+x)[0];	//get first local results HTML element
		while(prnt != null) {	//use while loop to go through results (1 - X)
			var resObj;		//new Result Object variable
			resColl.push(resObj=new LclResult());		//push result object into mapItems array via resColl variable pointer
			
			var resultJson=eval("("+prnt.getElementsBySelector("div.result_json")[0].firstChild.nodeValue+")");	//evaluate JSON string from result HTML
			prnt.resultJson=resultJson;
			var lat=resObj.flat=parseFloat(resultJson.lat);
			var lon=resObj.flon=parseFloat(resultJson.long);
			resObj.adhasphoto=resultJson.photo;
            resObj.citybest=resultJson.cb;
			if(!(isNaN(lat) || isNaN(lon))) {
				var latlong = new MQLatLng(resObj.flat,resObj.flon);		//new lat/long object for result item
				var container = prnt.parentNode;	//get parent container element of HTML for result 
				var vlink=prnt.getElementsBySelector("a.fn")[0]; 
				var name=resObj.venuename=vlink.innerHTML.unescapeHTML();		//get venue name
				resObj.cityguideurl=vlink.href;
				var t;
				resObj.venueaddress=((t=prnt.getElementsBySelector(".street-address")).length > 0) ? t[0].innerHTML.unescapeHTML():"";	//get address
				resObj.venuecity=((t=prnt.getElementsBySelector(".locality")).length > 0) ? t[0].innerHTML.unescapeHTML():"";	//get city
				resObj.venuestate=((t=prnt.getElementsBySelector(".region")).length > 0) ? t[0].innerHTML.unescapeHTML():"";	//get state
				resObj.websiteurl=((t=prnt.getElementsBySelector(".official-site")).length > 0) ? t[0].href:"";	//get website
				resObj.directionsUrl=((t=prnt.getElementsBySelector(".dirs-url")).length > 0) ? t[0].href:"";	//get directions url
				var tel;
				if ((tel=prnt.getElementsBySelector(".tel")).length > 0) resObj.venuephonenumber=local.cmn.trim(tel[0].innerHTML).replace(/-/g,"");		//get phonenumber
				resObj.mapItem=new LclMapItem(null,latlong);
				var resImg=prnt.getElementsBySelector("img.result-num")[0];
				var balloonSrc = (resObj.citybest)?"sml_cbballoon" + x + ".png":"sml_balloon" + x + ".png"
				if (cg.browser.ie6) {
                    resImg.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + cg.imagesDir+balloonSrc + "', sizingMethod='image')";
                    resImg.src = "http://img.mqcdn.com/a/a";
                } else {
                    resImg.src=cg.imagesDir+balloonSrc;
                }
                resImg.alt="Map Reference "+x;
                prnt.resultJson.resNum=x;
				resImg.show();
                resObj.li=prnt;
                resObj.li.resImg=resImg;
                Event.observe(resObj.li,"mouseover",this.rolloverResult.bindAsEventListener(this));
                Event.observe(resObj.li,"mouseout",this.rolloutResult.bindAsEventListener(this));
                Event.observe(prnt.getElementsBySelector("a.map-link")[0],"click",this.mapLink.bindAsEventListener(this));
			} else {
                resColl.pop();
                this.nonMapLis.push(prnt);
				var sp = prnt.getElementsBySelector("span.map-span")[0];
				if(sp)sp.hide();
            }
			x++;	//increment current result reference number
			prnt = $$("ul.search-results #slr_listing"+x)[0];	//get next result element reference
		}
		
		this.currResSet=0;
		this.resultsPages.push(0);	//add to result pages collection
		poiColl=this.redrawPois(resColl,poiColl);		//draw POI's from mapItems array
		
		var mInit=new MQMapInit();
		mInit.setBestFitRect(poiColl.getBoundingRect());
		mInit.setBestFitMargin(20);
		
		this.myMap = new MQTileMap(this.mapWindow,9,this.b_star,"map",mInit);	//create new map instance
		this.myMap.enableDragging(false);

		this.myMap.setRolloversEnabled(false);		//disable MapQuest RollOvers
		this.myMap.replacePois(poiColl);
	},
	startDetailsMap:function(){		//gathers plot point data from HTML and initalises map, plotting points
	   	this.smallMap=true;
		var pois = new Array(),x = 1,prnt,hasLatLong=true,myPoint,myIcon;
		var resColl,resObj;		//result collection variable
		this.mapItems.push(resColl=new Array());	//add result collection to mapItems array
		var poiColl=new MQPoiCollection();
		resColl.push(resObj=new LclResult());		//push result object into mapItems array via resColl variable pointer
		var resultJson=eval("("+$$("div#venue_json")[0].firstChild.nodeValue+")");	//evaluate JSON string from result HTML
		var lat=resObj.flat=parseFloat(resultJson.lat);
		var lon=resObj.flon=parseFloat(resultJson.long);
		var latlong = new MQLatLng(resObj.flat,resObj.flon);		//new lat/long object for result item
		resObj.mapItem=new LclMapItem(null,latlong);
		this.currResSet=0;
		this.resultsPages.push(0);	//add to result pages collection
		this.myMap = new MQTileMap(this.mapWindow,12,this.b_star,"map");	//create new map instance
		this.redrawPois(resColl);		//draw POI's from mapItems array
		this.myMap.setCenter(latlong);
		this.myMap.enableDragging(false);
		this.myMap.setRolloversEnabled(false);		//disable MapQuest RollOvers
	},
	ordinaryLiHl:function(e) {
        var targetEle;
        if (e) targetEle=e.relatedTarget;
        else targetEle=event.toElement;
        e=e||event;
        var el=Event.findElement(e,"li"),poi;
        while (el.id.indexOf("listing") == -1) el=el.up("li");
        if (e.type.indexOf("mouseout")>-1 && targetEle!==null) {
            while (targetEle.id.indexOf("listing") == -1 && $(targetEle).up("li")!==undefined) targetEle=$(targetEle).up("li");
            if (el===targetEle) return;
        }
        if (e.type.indexOf("mouseover")>-1) el.addClassName("over");
        else el.removeClassName("over");
    },
	rolloverResult:function(e) {
	   if (this.currStickyRes!=null) return;
        if (e.constructor==MQPoi) {      //if being fired by the MQ event handler
            this.highlightPoi(e,true);
        } else {
            e=e||event;
            var el=Event.findElement(e,"li"),poi;
            while (el.id.indexOf("listing") == -1) el=el.up("li");
            poi=local.mapItems[0][el.resultJson.resNum-1].mapItem.poi;
            this.highlightPoi(poi,true);
        }
    },
    rolloutResult:function(e) {
        if (this.currStickyRes!=null) return;
        if (e.constructor==MQPoi) {     //if being fired by the MQ event handler
            this.highlightPoi(e,false);
        } else {
            var targetEle;
            if (e) targetEle=e.relatedTarget;
            else targetEle=event.toElement;
            e=e||event;
            var el=Event.findElement(e,"li"),poi;
            while (el.id.indexOf("listing") == -1) el=el.up("li");
            if (targetEle!==null) {
                while (targetEle.id.indexOf("listing") == -1 && $(targetEle).up("li")!==undefined) targetEle=$(targetEle).up("li");
                if (el===targetEle) return;
            }
            poi=local.mapItems[0][el.resultJson.resNum-1].mapItem.poi;
            this.highlightPoi(poi,false);
        }
    },
    highlightPoi:function(poi,hl) {
        var newUrl;
        var oldUrl=poi.getIcon().getImage().src;
        if (cg.browser.ie6) {
            oldUrl=poi.getIcon().getImage().style.filter.match(/src='[a-zA-Z-_0-9.:\/]+'/)[0];
            oldUrl=oldUrl.substring(5,oldUrl.length-1);
        }
		if (hl) newUrl=oldUrl.replace(/\/sml_/,"/o_sml_");
		else newUrl=oldUrl.replace(/\/o_sml_/,"/sml_");
        poi.getIcon().getImage().src=newUrl;
		poi.getIcon().getImage().width=24;
		poi.getIcon().getImage().height=(newUrl.indexOf("cbballoon")>-1)?34:27;
		poi.getIcon()._fixPng(poi.getIcon().getImage());
		$(poi.mqMapIcon.element).up().setStyle({"zIndex":(hl?"91":"90")});
		var poiKey,poiNum;
        poiKey=poi.getKey();		//get key
        poiNum=parseInt(poiKey.substr(3));	//get result number from key
        var res=local.mapItems[0][poiNum];
        if (hl) res.li.addClassName("over");
        else res.li.removeClassName("over");
        if (cg.browser.ie6) {
            res.li.resImg.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + newUrl+"', sizingMethod='image')";
        } else res.li.resImg.src=newUrl;
    },
	createLclPOI:function(latlng,img,imgW,imgH,key) {		//create & return POI object, given POI parameters
		var myIcon = new MQMapIcon(this.mqIcon);		//create map Icon object
		myIcon.setImage(img,imgW,imgH,true,true);		//set image for icon
		var myPoint=new MQPoi(latlng,myIcon);		//create new POI object, using icon object
		if (key) myPoint.setKey(key);			//set key if given
		return myPoint;
	},
	poiRollover:function(poi,cMulti) {		//gather info required for display of popup when user rolls over a POI
	   if (!this.mapExpanded) return;
	   if (this.currStickyRes!==null) this.closePoiRollover();
		var poiKey,poiNum,ll,xyLoc;
		poiKey=poi.getKey();		//get key
		poiNum=parseInt(poiKey.substr(3));	//get result number from key
		ll=poi.getLatLng();		//get lat/lng object
		xyLoc=this.myMap.llToPix(ll);		//get XY position of POI from lat/lng object
		window.clearTimeout(local.poiWinTimeout);		//clear timeouts used for rollover refinement
		window.clearTimeout(local.roWinTimeout);
		this.currPoi=poiNum;	//set current POI identifier variable
		this.dispPoiRollover(this.mapItems[this.currResSet][poiNum],xyLoc);		//call display popup function 
		this.highlightPoi(poi,true);
		this.currStickyRes=poiNum;
	},
	closePoiRollover:function() {
        this.highlightPoi(this.mapItems[0][this.currStickyRes].mapItem.poi,false);
        $(this.mapItems[0][this.currStickyRes].mapItem.poi.mqMapIcon.element).up().setStyle({"zIndex":"90"})
        this.roWin.hide();
        this.currStickyRes=null;
    },
	poiRollout:function(poi) {		//timer function, popup close function will be called after pre-defined timeout in this function.
		this.poiWinTimeout=window.setTimeout("local.hidePoiRollover(\"res\")",500);
	},
	dispPoiRollover:function(resObj,xyLoc) {		//construction of HTML for popup and display trigger
		window.clearTimeout(this.poiWinTimeout);	//clear timeout if user momentarily rolled off popup.
		var ce=local.cmn.ce,apTxt=local.cmn.apTxt,roCnt=$("RO_content"),el,el2;		//init vars, create short refs to helper functions
		local.cmn.removeChildren(roCnt);	//remove HTML from content area of rollover
		var ximg=ce("span",null,"popup_x");
		Event.observe(ximg,"click", local.closePoiRollover.bindAsEventListener(this));
		roCnt.appendChild(ximg);
		if (resObj.venuephotourl) {	//if venue data includes photo, create HTML for this
			el=roCnt.appendChild(ce("a"));
			el.href=resObj.cityguideurl;
			el=el.appendChild(ce("img"));
			el.alt="Photo of "+resObj.venuename;
			el.src=resObj.venuephotourl;
			el.onerror=el.onload=function() { local.positionPopup(local.myMap.llToPix(local.mapItems[local.currResSet][local.currPoi].mapItem.poi.getLatLng())); };		//when images load or not, re-calculate position of popup 
			roCnt.appendChild(ce("br"));
		}
		el=roCnt.appendChild(ce("div",null,"puUrl"));
		if (resObj.cityguideurl) {		//if cityguide URL exists add the link
			el=el.appendChild(ce("a"));
			el.setAttribute("target","_parent");
			el.href=resObj.cityguideurl;
		}
		this.searchTermNodes(el,resObj.venuename,cg.query);		//add the venuename, bolding any search terms contained within
		roCnt.appendChild(ce("br"));
		el.style.paddingBottom="4px";

		if (resObj.venueaddress) apTxt(roCnt,resObj.venueaddress+", ");		//add venue address if it exists
		if (resObj.venuecity) apTxt(roCnt,resObj.venuecity+", ");		//add city if is exists
		apTxt(roCnt,resObj.venuestate);		//add state
		roCnt.appendChild(ce("br"));
		var ph;
		ph=(resObj.venuephonenumber.indexOf("-") == -1)?this.formatPhoneNum(resObj.venuephonenumber):resObj.venuephonenumber;	//format phone number
		if (resObj.venuephonenumber) {
            el=ce("b");
            apTxt(el,ph);		//add phone number
            roCnt.appendChild(el);
        }
		roCnt.appendChild(ce("br"));
		if (resObj.category) {			//add categories if they exist
			el=roCnt.appendChild(ce("div",null,"grey"));
			apTxt(el,"Category: "+resObj.category);
			el.style.paddingBottom="7px";
		}
		el=roCnt.appendChild(ce("br"));  //spacer
		el=el.parentNode;
		if (resObj.websiteurl != "") {		//add website URL
			//el=roCnt.appendChild(ce("div",null,"pu-website"));
			apTxt(roCnt,"- ");
			el=roCnt.appendChild(ce("a"));
			el.target="_blank";
			el.href=resObj.websiteurl;
			apTxt(el,"Website");
			roCnt.appendChild(ce("br"));
		}
		apTxt(roCnt,"- ");
		el=roCnt.appendChild(ce("a"));
		apTxt(el,"Get Directions");
		el.href=resObj.directionsUrl;
		
		if (resObj.adhasphoto!=="") {	//if venue data includes photo, create HTML for this
            roCnt.appendChild(ce("br"));
			el=roCnt.appendChild(ce("a"));
			el.href=resObj.cityguideurl;
			el=el.appendChild(ce("img"));
			el.className="ad-photo";
			el.alt="Photo of "+resObj.venuename;
			el.src=resObj.adhasphoto;
			el.onerror=el.onload=function() { local.positionPopup(local.myMap.llToPix(local.mapItems[local.currResSet][local.currPoi].mapItem.poi.getLatLng())); };		//when images load or not, re-calculate position of popup 
		}
		this.roWin.style.display="";
		this.positionPopup(xyLoc);		//postion dialog
	},
	hidePoiRollover:function(typ) {		//hide POI popup
		this.roWin.style.display="none";
	},
	positionPopup:function(xyLoc) {			//determine position of popup on screen
		var flip=this.decideFlip(xyLoc);
		var offset = Position.cumulativeOffset(this.mapWindow);
		var flippedTop=xyLoc.y+offset[1]-this.roWin.offsetHeight+15;
		if (flip && flippedTop > 0) {
			this.roWin.style.top=(xyLoc.y+offset[1]-this.roWin.offsetHeight+19) + "px";
			this.roWin.style.left=(xyLoc.x+offset[0]-this.roWin.offsetWidth-26) + "px";
		} else {
			this.roWin.style.top=(xyLoc.y+offset[1]-22) + "px";
			this.roWin.style.left=(xyLoc.x+offset[0]+25) + "px";
			flip=false;
		}
		$("popup_middle").className=(flip)?"puMiddle_r":"puMiddle";
		$("offArrowR").style.display=(flip) ? "":"none";
		$("offArrow").style.display=(!flip) ? "":"none";
	},
	decideFlip:function(xyLoc) {		//determine if popup should be flipped between below/right of mouse cursor or above/left.
		var wW=(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth);
		var wH=(window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) + (document.documentElement.scrollTop||document.body.scrollTop);
		var x=xyLoc.x+Position.cumulativeOffset(this.mapWindow)[0];
		var y=xyLoc.y+Position.cumulativeOffset(this.mapWindow)[1];
		if (x+this.roWin.offsetWidth+50 < wW && ((y+this.roWin.offsetHeight-30) > wH && y-(document.documentElement.scrollTop||document.body.scrollTop)-this.roWin.offsetHeight < 0)) return false;
		else if (x+this.roWin.offsetWidth+50 > wW || y+(this.roWin.offsetHeight-30) > wH) return true;
		else return false;
	},
	onload:function() {		//called when the page loads to initialise map module
        this.roWin=$("RO_window");
        if (this.roWin) {
            this.roWin.onmouseout=function(e) { local.roWinTimeout=window.setTimeout("local.hidePoiRollover(\"both\")",500); };
			this.roWin.onmouseover=function(e) { window.clearTimeout(local.poiWinTimeout);window.clearTimeout(local.roWinTimeout); };
			$$("body")[0].appendChild(this.roWin);
        } 
        this.initVals();
        
        if (this.noresults) {
            $("map_results").hide();
            return;
        }
        
        if (this.mapWindow) {
            this.myLZControl = new MQLargeZoomControl(this.myMap);
            this.myVControl = new MQViewControl(this.myMap);
            
            this.isResultsPage=(cg.template == "search"||cg.template == "whatsnearby");
            this.isDetailsPage=(cg.template=="venue_details"||cg.template=="event_details");

            if (this.isResultsPage) {
                this.startMap();
                this.scrollMapWithViewport();
            } 
            else if (this.isDetailsPage) this.startDetailsMap();
            
            if ((this.isResultsPage || this.isDetailsPage) && this.mapWindow && $("mqtiledmap")) $("mqtiledmap").addClassName("no-cursor");
            
            if (cg.template==="directions") {
                if ($("from_input").value.length > 0) this.getDirections();
                Event.observe($("from_input").form,"submit",function(e) {
                    e=e||event;
                    Event.stop(e);
                    this.getDirections();
                }.bindAsEventListener(this));
            }
        }
	},
	removeAllPois:function() {			//remove all POI's from map instance
		var limit=0;
		while (this.myMap.getPois().getSize() > limit) {
			var poi=this.myMap.getPois().getAt(limit);
			if (poi.key=="bs") { limit++; }		//if blue star... skip
			else this.myMap.removePoi(poi);
		}
	},
	searchTermNodes:function(/*DOMNode*/prnt,/*string*/ itm, /*string*/ st) {		//take a string and return a collection of nodes with search terms encapsulated in bold tags
		var idx=0,el,apTxt=local.cmn.apTxt,str;
		
		if ((idx=itm.toLowerCase().indexOf(st.toLowerCase())) == -1 || st=="") {
			apTxt(prnt,itm);
		} else {
			str=idx;
			apTxt(prnt,itm.substring(0,str));
			do {
				apTxt(prnt,itm.substring(str,idx));
				el=local.cmn.ce("b");
				apTxt(el,itm.substr(idx,st.length));
				prnt.appendChild(el);
				str=idx=idx+st.length;
			} while ((idx=itm.toLowerCase().indexOf(st.toLowerCase(),idx)) != -1);
			apTxt(prnt,itm.substr(str));
		}
	},
	formatPhoneNum:function(num) {		//format phone number into a string
		if (!num) return "";
		num=num.toString();	//convert to string
		return num.substr(0,3) + "-" + num.substr(3,3) + "-" + num.substr(6);
	},
	dbgmsg:function(txt) {
		if (!local.debug) return;
		if (window.console) {
			window.console.log(txt);
		}
	},
	redrawPois:function(resObj /*Object*/, poiColl /*Object*/) {		//re-plot POI's on the map
		if (!resObj) return;
		if (typeof(poiColl)=="undefined") poiColl=false;
		var img;
		for (var i=0;i<resObj.length;i++) {
			if (resObj[i].mapItem.poi != null) {		//if POI already exists in mapItems array then add it.
				if (poiColl) poiColl.add(resObj[i].mapItem.poi); 
				else this.myMap.addPoi(resObj[i].mapItem.poi);
				continue;
			}
			if (this.smallMap && resObj.length==1) img=cg.imagesDir+"sml_balloon.png";
			else {
				if (resObj[i].citybest) img=cg.imagesDir+"sml_cbballoon" + (i+1) + ".png";
				else img=cg.imagesDir+"sml_balloon"+(i+1)+".png";
			}
			pnt=this.createLclPOI(resObj[i].mapItem.latlng,img,24,(resObj[i].citybest?34:27),"res"+i);
			
			if (!this.smallMap){
                MQEventManager.addListener(pnt,"mouseover",function() { local.rolloverResult(this); });
                MQEventManager.addListener(pnt,"click",function() { local.poiRollover(this); });
                MQEventManager.addListener(pnt,"mouseout",function() { local.rolloutResult(this); });
			}
			if (poiColl) poiColl.add(pnt);
			else this.myMap.addPoi(pnt);
			if (resObj[i].mapItem.poi == null) resObj[i].mapItem.poi = pnt;
		}
		if (poiColl) return poiColl; 
	},
	updatePois:function() {		//general update function, removes all POI's and re-plots them
		this.removeAllPois();
		this.redrawPois(this.mapItems[this.currResSet]);
	},
	getDirections:function() {
	   if (this.ddEntryText == $("from_input").value) return;
	   this.ddEntryText=$("from_input").value;
	   if ($("mapWindow").visible()) $("mapWindow").update();
        this.initDDVars();
	    this.popInfo();
	},
	initDDVars:function() {
	   this.mqConsts = new MQConstants();
        this.myFAddress=new MQSingleLineAddress();
        this.myTAddress=new MQAddress();
	   
        this.myGExec = new MQExec("geocode.aol.mapquest.com",this.mqPath,this.mqPort,this.myPxyServer,this.myPxyPath,this.myPxyPort);
        this.myRExec = new MQExec("route.aol.mapquest.com",this.mqPath,this.mqPort,this.myPxyServer,this.myPxyPath,this.myPxyPort);
        this.myGcColl = new MQLocationCollection("MQGeoAddress");
        this.myRtColl = new MQLocationCollection("MQGeoAddress");
        this.myOptions = new MQRouteOptions();
		this.myRtResults = new MQRouteResults();
		this.myManStr = "";
		this.myTrkStr = "";
    },
    popInfo:function() {
        var prnt,destJson,tLoc=null;
        if (!(prnt=$("bus_vcard"))) return;
        
        try {
            destJson=eval("("+$("dest_json").firstChild.nodeValue+")");
        } catch (e) {}
        if (typeof destJson!=="undefined") {
            if (destJson.lat!=""&&destJson.long!="") {
                tLoc=new MQGeoAddress();
                tLoc.setMQLatLng(new MQLatLng(destJson.lat,destJson.long)); 
            }
        } else {
    		if (prnt.getElementsBySelector("span.street-address").length>0)this.myTAddress.setStreet(prnt.getElementsBySelector("span.street-address")[0].firstChild.nodeValue);
    		if (prnt.getElementsBySelector("span.locality").length>0)this.myTAddress.setCity(prnt.getElementsBySelector("span.locality")[0].firstChild.nodeValue);
    		if (prnt.getElementsBySelector("span.region").length>0)this.myTAddress.setState(prnt.getElementsBySelector("span.region")[0].firstChild.nodeValue);
    		if (prnt.getElementsBySelector("span.postal-code").length>0)this.myTAddress.setPostalCode(prnt.getElementsBySelector("span.postal-code")[0].firstChild.nodeValue);
    		this.myTAddress.setCountry("US");
		}
		this.myFAddress.setAddress($("from_input").value);
		this.geocodeThem(tLoc);
    },
    geocodeThem:function(tLoc) {
    	this.myGExec.geocode(this.myFAddress, this.myGcColl);
    	if (this.myGcColl.get(0).getCity()==="" && this.myGcColl.get(0).getState()==="" && this.myGcColl.get(0).getPostalCode()==="") {
    	   alert("Not a valid address, please re-check your entry.")
            return;
        }
    	this.myRtColl.add(this.myGcColl.get(0));
    	if (tLoc===null) {
    	   this.myGExec.geocode(this.myTAddress, this.myGcColl);
    	   this.myRtColl.add(this.myGcColl.get(0));
    	} else {
            this.myRtColl.add(tLoc);
        }
    	this.getRoute();
    },
    getRoute:function() {
        this.ddSessionID = this.myRExec.createSessionEx(new MQSession());
        this.myBB = new MQRectLL(new MQLatLng(),new MQLatLng());
    	this.myRExec.doRoute(this.myRtColl,this.myOptions,this.myRtResults,this.ddSessionID,this.myBB);
    	this.displayIt();
    },
    displayIt:function() {
    	var myMinutes = this.myRtResults.getTime()/60;
    	if (myMinutes > 60) {
    		if (myMinutes/60 == 1) {
    			var myTotTime = "1 hr ";
    		}
    		else {
    			var myTotTime = Math.round((myMinutes/60)*100)/100 + " hrs";
    		}
    	}
    	else {
    		var myTotTime = myMinutes + " min";
    	}
    	var myDist = Math.round(this.myRtResults.getDistance()*100)/100;
    
    	var myTrkRtColl = this.myRtResults.getTrekRoutes();
    	var myManeuverColl = myTrkRtColl.get(0).getManeuvers();
    	var myTrkStr="",myManStr,myManDist;
    
        myTrkStr = '<table class="directions_results" cellspacing="0" cellpadding="0" border="0">';	 
        myTrkStr += '<tr><th colspan="3">DRIVING DIRECTIONS</th></tr>';
        myTrkStr += '<tr><th>Maneuver</th><th></th><th>Distance</th></tr>'; 
    	for (var intX = 0; intX < myManeuverColl.getSize(); intX ++){
            signSrc = (intX == 0)?this.getMQRoadSign(null,"start"):this.getMQRoadSign(this.myRtResults.getTrekRoutes().get(0).getManeuvers().get(intX));;
            myTrkStr +='<tr><td><img src="'+signSrc+'" alt="Maneuver sign" /></td>';
    		myManDist = Math.round(myManeuverColl.get(intX).getDistance()*100)/100;
    		myTrkStr += "<td>" +(intX +1) +  ". " + myManeuverColl.get(intX).getNarrative() + "</td><td class=map_distance>" + myManDist + " miles</td>";
    		myTrkStr += "</tr>";
    	}
    	signSrc = this.getMQRoadSign(null,"end");
    	myTrkStr +='<tr><td><img src="'+signSrc+'" alt="Maneuver sign" /></td>';
    	
    	 var endName,tmp;
	     var endAddress;
	     var endLocality;
	     var endRegion;
	     var endZip;
	     
	     endName = ((tmp=$$("#bus_vcard .fn")).length>0)?tmp[0].innerHTML+": ":"";
	     endAddress = ((tmp=$$("#bus_vcard .street-address")).length>0)?tmp[0].innerHTML+", ":"";
	     endLocality = ((tmp=$$("#bus_vcard .locality")).length>0)?tmp[0].innerHTML+", ":"";
	     endRegion = ((tmp=$$("#bus_vcard .region")).length>0)?tmp[0].innerHTML+", ":"";
	     endZip = ((tmp=$$("#bus_vcard .postal-code")).length>0)?tmp[0].innerHTML+".":"";
	     
	     myTrkStr += '<td colspan="2">End at <strong>' + endName + '</strong> ' + endAddress + ' ' + endLocality + ' ' + endRegion + ' ' + endZip + '</td></tr>';
	    	
    	
    	
    	$("DDIRResults").innerHTML = myTrkStr;
    	
    	$("durTop").innerHTML=$("durBot").innerHTML="<strong>Total Time: </strong>" + myTotTime + "<strong> Total Distance: </strong>" + myDist + " miles";
    	$("DDIRResults").show();
    	$("durBot").show();
    	$("durTop").show();
    
    	this.myMap = new MQTileMap($('mapWindow'));
      	this.myMap.addRouteHighlight(this.myBB,"http://map.aol.mapquest.com",this.ddSessionID,true);
      	var strtEndImgs=["icon-start.png","icon-finish.png"];
		for (var k=0;k<this.myRtResults.getLocations().getSize();k++) {
			var myPoint = new MQPoi(this.myRtResults.getLocations().get(k).getMQLatLng());
			var myIcon = new MQMapIcon(this.mqIcon);
			myIcon.setAnchorOffset(new MQPoint(-28,-26));
			myIcon.setImage(cg.imagesDir+strtEndImgs[k],35,26,false,true);
			myPoint.setIcon(myIcon);
			this.myMap.addPoi(myPoint);
		}
      	this.myMap.addControl(new MQLargeZoomControl());
    	this.myMap.addControl(new MQViewControl());
    	$("mapWindow").show();
    },
    getMQRoadSign:function(this_maneuver,startorend){

		var img_src = "";
		var cdn_a = "http://mqsigns.aolcdn.com";
		var cdn_b = "http://img.mqcdn.com";
		var img_start ="http://img.mqcdn.com/mqsite/icon-dirs-start";
		var img_end = "http://img.mqcdn.com/mqsite/icon-dirs-end";
		var shields = new Array(1,2,3,5,20,21,22,23);
		var BWorCO = "CO";
		
		if(startorend == "start") return img_start;
		else if(startorend == "end") return img_end;

		var this_turn_type = this_maneuver.getTurnType();
		
		if (this_maneuver.getSigns().getSize() > 0) {
			img_src = cdn_a + "/?";
			for (var k = 0; k < this_maneuver.getSigns().getSize(); k++) {
				var this_sign = this_maneuver.getSigns().get(k);
				
				if (this_sign != null) {
					var this_sign_type = this_sign.getType();
					var this_direction = this_sign.getDirection();
					var this_text = this_sign.getText();
					
					if (this_sign_type == 1001) {
						var t;
						if (this_maneuver.getTurnType() == 14 || this_maneuver.getTurnType() == 12) 
							t = "RSEXITRIGHTNUM";
						else 
							t = "RSEXITLEFTNUM";
						return img_src + "s=rs&t=" + t + "&n=" + this_text + "&d=&v=";
					}
					else 
						if (this_sign_type == 1 || this_sign_type == 20 ||
						this_sign_type == 21 ||
						this_sign_type == 22 ||
						this_sign_type == 23) {
							return img_src + "s=rs&t=RS0000" + this_sign_type + "CO" + "&n=" + this_text + "&d=" + this_maneuver.getDirectionName();
						}
						else 
							if (this_sign_type == 3 || this_sign_type == 2) {
								return img_src + "s=rs&t=RS0000" + this_sign_type + "BW" + "&n=" + this_text + "&d=" + this_maneuver.getDirectionName();
							} else /* its just a regular road sign */{
								return cdn_b + this.getRegularSign(this_turn_type);
							}
				}
			}
			return img_src;
		} else /* its just a regular road sign */ {
			return (cdn_b + this.getRegularSign(this_turn_type));
		} 
		
	},
	getRegularSign:function(turnType){

		if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_STRAIGHT ||
			turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_STRAIGHT_FORK ){
			return "/mqsite/rs_straight";
		}
		else if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_SLIGHT_RIGHT ) {
			return "/mqsite/rs_slight_right";
		}
		else if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_RIGHT ) {
			return "/mqsite/rs_right";
		} 
		else if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_SHARP_RIGHT ){
			return "/mqsite/rs_sharp_right";
		}
		else if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_RIGHT_MERGE ){
			return "/mqsite/rs_merge_right";
		}
		else if(turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_SHARP_LEFT ) {
			return "/mqsite/rs_sharp_left";
		}
		else if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_LEFT ) {
			return "/mqsite/rs_left";
		}
		else if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_SLIGHT_LEFT ) {
			return "/mqsite/rs_slight_left";
		}
		else if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_LEFT_MERGE ){
			 return "/mqsite/rs_merge_left";
		}
		else if( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_LEFT_UTURN ||
				 turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_REVERSE){
			return "/mqsite/rs_uturn_left";
		}
		else if(turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_RIGHT_UTURN){
			return "/mqsite/rs_uturn_right";
		}
		else if(turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_LEFT_OFF_RAMP){
			return "/mqsite/rs_gr_exitleft";
		}
		else if(turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_RIGHT_OFF_RAMP){
			return "/mqsite/rs_gr_exitright";
		}
		else if ( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_RIGHT_ON_RAMP ||
				  turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_LEFT_ON_RAMP){
			return "/mqsite/rs_ramp";
		}
		else if ( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_RIGHT_FORK ){
			return "/mqsite/rs_fork_right2";
		}
		else if ( turnType == this.mqConsts.MQMANEUVER_TURN_TYPE_LEFT_FORK ){
			return "/mqsite/rs_fork_left2";
		}
		return "";
	},
	formatAddress:function(thisAddress){
		var str = "";
		str = thisAddress.getStreet();

		if (thisAddress.getCity().length > 0){
			if(str == "") str += thisAddress.getCity();
			else str += ", " + thisAddress.getCity();
		}
		if(thisAddress.getState().length > 0 ){
			if(str == "") str += thisAddress.getState();
			else str += ", " + thisAddress.getState();
		}
		if(thisAddress.getPostalCode().length > 0 ){
			if(str == "") str += thisAddress.getPostalCode();
			else str += ", " + thisAddress.getPostalCode();
		}
		return str;
	},
	toggleMap:function(){
        if(!this.mapExpanded){
            this.detMapCntr=local.myMap.getCenter();
            $("container").addClassName("map-expanded");
            $("mapWindow").setStyle({width:"479px",height:"530px"});
            local.myMap.setSize();
            if (this.isResultsPage) local.myMap.bestFit();
            this.myMap.enableDragging(true);
			this.myMap.addControl(this.myLZControl, new MQMapCornerPlacement(MQMapCorner.TOP_RIGHT, new MQSize(0,20)));
			this.myMap.addControl(this.myVControl, new MQMapCornerPlacement(MQMapCorner.TOP_LEFT, new MQSize(110,0)));
            $("map_expand_link").innerHTML="Reduce Map";
            $("mqtiledmap").removeClassName("no-cursor");
            this.mapExpanded=true;
        }else{
            if (this.currStickyRes!==null) this.closePoiRollover();
            this.myMap.enableDragging(false);
            this.myMap.removeControl(this.myLZControl);
            this.myMap.removeControl(this.myVControl);
            local.myMap.setSize(new MQSize(304,250));
            $("mapWindow").setStyle({width:"304px",height:"250px"});
            if (this.isResultsPage) local.myMap.bestFit();
            else if (this.isDetailsPage) local.myMap.setCenter(this.detMapCntr,12);
            $("map_expand_link").innerHTML="Enlarge Map";
            $("container").removeClassName("map-expanded");
            $("mqtiledmap").addClassName("no-cursor");
            this.mapExpanded=false;
        }
        if (cg.template=="search"||cg.template=="whatsnearby") {
            this.mapBotLimit=$("content").offsetHeight - $("content_right").offsetHeight;
            this.positionMap();
        }
    },
    mapLink:function(e) {
        e=e||event;
        Event.stop(e);
        var el=Event.findElement(e,"li");
        while (el.id.indexOf("listing") == -1 || el===undefined) el=el.up("li");
        var poiNum=el.resultJson.resNum-1;
        if (!this.mapExpanded) this.toggleMap();
        if (this.currStickyRes!=null) this.closePoiRollover();
        this.poiRollover(this.mapItems[0][poiNum].mapItem.poi);
        $(this.mapItems[0][poiNum].mapItem.poi.mqMapIcon.element).up().setStyle({"zIndex":"91"});
     },
     scrollMapWithViewport:function(e) {
        $("content_right").relativize();
        this.contentRoffset=$("content_right").offsetTop;
        this.mapBotLimit=$("content").offsetHeight - $("content_right").offsetHeight;
        Event.observe(window,"scroll",this.positionMap.bindAsEventListener(this));
     },
     positionMap:function(e) {
        if ($("content").offsetHeight < local.mapWindow.offsetHeight) return;
        var newPos=document.viewport.getScrollOffsets().top-local.mapWindow.offsetTop-this.contentRoffset+5;
        if (newPos<0) newPos=0;
        else if (newPos>this.mapBotLimit) newPos=this.mapBotLimit;
        $("content_right").style.top=newPos+"px";
        if (this.currStickyRes!=null) this.positionPopup(this.myMap.llToPix(this.mapItems[this.currResSet][this.currStickyRes].mapItem.poi.getLatLng()));		//when images load or not, re-calculate position of popup
     }
};

local.cmn={		//common functions
	removeChildren:function(node) {		//remove all children of a node
		if(node == null)
			return;
		while (node.childNodes.length > 0) node.removeChild(node.firstChild);
	},
	ce:function(en,eid,ecl) {		//create element, setting id,class if present
		var e=document.createElement(en);
		if (eid != null) e.id=eid;
		if (ecl != null) e.className=ecl;
	return e;
	},
	apTxt:function(ele,txt) {		//append text helper function
		return ele.appendChild(document.createTextNode(txt));
	},
	trim:function(str){		//trim whitespace from beginning and/or end of a string
		return str.replace(/^\s*|\s*$/g,"");
	},
	stripHTML:function(str){		//string HTML tags from a string.
		return str.replace(/<(.|\n)+?>/g,"");
	},
	getErrorDetails:function(targ) {
		try {
			targ();
		} catch (e) {
			var msg="Error:\n" + e.message;
			msg+="\nName:" + e.name;
			if (document.evaluate) {
				msg += "\nLine #: " + e.lineNumber;
				msg += "\nFile: " + e.fileName;
			} else if (document.all) {
				msg += "\nIE number: " + e.number;
			}
			alert(msg);
			return;
		}
		local.dbgmsg("getErrorDetails executed with no errors");
	},
	checkForEnter:function(e) {		//check if event was fired by the ENTER key
		if (!e) e=event;
		if (e.keyCode == 13) return true;
		else return false;
	},
	submitenter:function(myfield,e){	//check if event was fired by the ENTER key, and submit local search form.
		var keycode;
		if (window.event) keycode = window.event.keyCode;
		else if (e) keycode = e.which;
		else return true;

		if (keycode == 13){
   		   return local.submitLocal(myfield.form);
	   }
		else
			return true;
	},
	/* custom arcDistance function, so we dont need to include >150kb of MQ JS */
	arcDistance:function(from_ll,to_ll,lUnits){
		var MQLATLNG_RADIANS=0.01745329251994;
		var MQDISTANCEUNITS_MILES=0;
		var MQDISTANCEUNITS_KILOMETERS=1;
		var PI=3.14159265358979323846
		if(from_ll && to_ll){
			if(from_ll.getClassName()!=="MQLatLng" && to_ll.getClassName()!=="MQLatLng"){
				alert("failure in arcDistance");
				throw"failure in arcDistance";
			}
		}
		else{
			alert("failure in arcDistance");
			throw"failure in arcDistance";
		}
		if(!lUnits){
			lUnits= MQDISTANCEUNITS_MILES;
		}
		if(from_ll.getLatitude()==to_ll.getLatitude()&&from_ll.getLongitude()==to_ll.getLongitude()){
			return 0.0;
		}
		var dLon=to_ll.getLongitude()-from_ll.getLongitude();
		var a=MQLATLNG_RADIANS*(90.0-from_ll.getLatitude());
		var c=MQLATLNG_RADIANS*(90.0-to_ll.getLatitude());
		var cosB=(Math.cos(a)*Math.cos(c))+(Math.sin(a)*Math.sin(c)*Math.cos(MQLATLNG_RADIANS*(dLon)));
		var radius=(lUnits===MQDISTANCEUNITS_MILES)?3963.205:6378.160187;
		if(cosB<-1.0)
			return PI*radius;
		else if(cosB>=1.0)
			return 0;
		else
			return Math.acos(cosB)*radius;
	}
};

Event.observe(window,'load',function() { local.onload(); });	//add onload for initialisation.