
	var geo = null;
	var map = null;
	var geocoder = null;
	var gmarkers = [];
	var active_gmarker = 0;
	var selected = false;
	var htmls = [];
	var otnIds = [];
	var routeOverlay = false;
	var checking = 0;
	var prevrequest = false;
	var autoZoom = false;
	var dragging = false;
	var iframe_height;
    var moreZoom = 0;
	
	// A Cluster is a simple overlay that outlines a lat/lng bounds on the
	function Cluster(bounds, html, size) {
	  this.bounds_ 	= bounds;
	  this.html_ 	= html;
	  this.size_ 	= size;
	}
	Cluster.prototype = new GOverlay();
	
	// Creates the DIV representing this Cluster.
	Cluster.prototype.initialize = function(map) {
	  // Create the DIV representing our Cluster
	  var div = document.createElement("div");
	  div.style.position = "absolute";
	  div.innerHTML = this.html_;
	  div.className = "cluster";
	
	  // Our Cluster is flat against the map, so we add our selves to the
	  // MAP_PANE pane, which is at the same z-index as the map itself (i.e.,
	  // below the marker shadows)
	  map.getPane(3).appendChild(div);
	
	  this.map_ = map;
	  this.div_ = div;
	}
	
	// Remove the main DIV from the map pane
	Cluster.prototype.remove = function() {
	  this.div_.parentNode.removeChild(this.div_);
	}
	
	// Copy our data to a new Cluster
	Cluster.prototype.copy = function() {
	  return new Cluster(this.bounds_, this.html_);
	}
	
	// Redraw the Cluster based on the current projection and zoom level
	Cluster.prototype.redraw = function(force) {
	  // We only need to redraw if the coordinate system has changed
	  if (!force) return;
	
	  // Calculate the DIV coordinates of two opposite corners of our bounds to
	  // get the size and position of our Cluster
	  var c1 = this.map_.fromLatLngToDivPixel(this.bounds_.getSouthWest());
	  var c2 = this.map_.fromLatLngToDivPixel(this.bounds_.getNorthEast());
	  
	  if (c2.x < c1.x) { c2.x += (256 * Math.pow(2, this.map_.getBoundsZoomLevel(this.map_.getBounds()))) }
	  
	  // Now position our DIV based on the DIV coordinates of our bounds
	  this.div_.style.width 	= Math.abs(c2.x - c1.x) + "px";
	  this.div_.style.height 	= Math.abs(c2.y - c1.y) + "px";
	  this.div_.style.left 		= c1.x + "px";
	  this.div_.style.top 		= Math.min(c2.y, c1.y)  + "px";
	}
	
	function drawRoute(response)
	{	
		
		var polyline = new GPolyline.fromEncoded(
		    {
		        color: '#FF0000',
		        weight: 3,
		        opacity: 0.85,
        
		        points: response.data.line,
		        levels: response.data.levels,
        
		        zoomFactor: 2,
		        numLevels: 18
		    }
		);
		
		if (routeOverlay) map.removeOverlay(routeOverlay);
		routeOverlay = polyline;
		map.addOverlay(routeOverlay);	
	}
	
	function routeHover(i)
	{
		if (active_gmarker != i)
		{
			//gmarkers[i].openInfoWindowHtml(htmls[i]);						
			var script = document.createElement('script');
			script.type = 'text/javascript';
			script.src = "http://api.ontracknavigation.com/0.6/json.php?encoding=utf-8&format=json&method=otn.route.getTrack&callback=drawRoute&routeId="+otnIds[i];
			document.getElementsByTagName('head')[0].appendChild(script);
			active_gmarker = i;	
			window.location = buildAnchors();			
		}
	} 
   		
	function loadXMLDoc(url, f) 
	{
		var request = GXmlHttp.create();
		request.open("GET", url, true);
		request.onreadystatechange = function() {
		  if (request.readyState == 4) {
		    f(eval(request.responseText));
		  }
		}
		request.send(null);
		return request;
	}	
	
	function getHashVariable(variable) 
	{ 
		if (! location.hash) { return false; }
		var hash = location.hash.substring(1); 
		var vars = hash.split("&");
		for (var i=0 ; i<vars.length ;i++) { 
			var pair = vars[i].split("=");
			if (pair[0] == variable) 
			{ 
			return pair[1]; 
			} 
		}
	} 
   	
	function onLoad() {
		
        if (GBrowserIsCompatible()) {

			// === create the base icon ===
		    var icon = new GIcon();
		    icon.shadow = "http://www.routeyou.com/images/map_icons/shadow.png";
		    icon.iconSize = new GSize(35, 35);
		    icon.shadowSize = new GSize(52, 35);
		    icon.iconAnchor = new GPoint(17, 35);
		    icon.infoWindowAnchor = new GPoint(17, 35);	
	
			var height = 500;
			
			// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
			if (typeof window.innerWidth != 'undefined')
			{
			     height = window.innerHeight
			}
			
			// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)			
			else if (typeof document.documentElement != 'undefined'
			    && typeof document.documentElement.clientWidth !=
			    'undefined' && document.documentElement.clientWidth != 0)
			{
			      height = document.documentElement.clientHeight
			}
			
			// older versions of IE
			else
			{
			      height = document.getElementsByTagName('body')[0].clientHeight
			}
			
			iframe_height = height;

            setHeights();			

	       	map = new GMap2(document.getElementById("map_search")); 
	       	map.enableContinuousZoom();
	       	map.addControl(new GSmallMapControl());
	        map.addControl(new DragZoomControl());
	        map.addControl(new GMapTypeControl());
	
			// looking for stored keywords
			if (getHashVariable('keywords'))
			{
				document.getElementById('searchkeywords').value =  unescape(getHashVariable('keywords'));
			}
			
			// looking for stored selections
			if (getHashVariable('selected'))
			{
				selected = parseInt(getHashVariable('selected'));
			}
	
			// looking for stored type settings
			if (getHashVariable('type'))
			{
				for (type in types) {
					if(getHashVariable('type').indexOf(type) >= 0) {
						types[type] = true;
					}
					else {
						types[type] = false;
					}
				}
			}
			
			// looking for anchor coordinates
			if (getHashVariable('lat') && getHashVariable('lng') && getHashVariable('z'))
			{
				map.setCenter(	new GLatLng(	Number(getHashVariable('lat')), 
												Number(getHashVariable('lng'))), 
								Number(getHashVariable('z')));
			}
			else
			{
				try
				{
					map.setCenter(new GLatLng(google.loader.ClientLocation.latitude, google.loader.ClientLocation.longitude), 8);
				}
				catch (err)
				{
					map.setCenter(new GLatLng(0,0),2);
				}
			}
            
            GEvent.addListener(map, "drag", function() { dragging = true; });
            GEvent.addListener(map, "dragend", function() { loadClusters(); setTimeout("dragging = false", 500);});
            GEvent.addListener(map, "zoomend", function() {loadClusters(); });

            refresh(false);			
		}
    }

	function timedOutHash()
	{
		if (getHashVariable('lat') && getHashVariable('lng') && getHashVariable('z'))
    	{
    		map.setCenter(	new GLatLng(	Number(getHashVariable('lat')), 
    										Number(getHashVariable('lng'))), 
    						Number(getHashVariable('z')));
    	}
    	setTimeout("timedOutHash()", 500);
	}
    
    function buildAnchors()
    {
    	var zoom 	= map.getZoom();
    	var lat 	= map.getBounds().getCenter().lat();
    	var lng 	= map.getBounds().getCenter().lng();
    	var anchors = "#lat="+lat+"&lng="+lng+"&z="+zoom;
    	var kws 	= getElementValue('searchkeywords');
    	if (kws) {
			anchors = anchors +"&keywords="+kws;
    	}
    	
    	if (active_gmarker > 0) {
			anchors = anchors +"&selected="+active_gmarker;
    	}
    	
    	anchors = anchors+ "&type=";
    	for (type in types) if (types[type]) anchors = anchors + type+'-'; 
    	return anchors;
    }
    
    function openCluster(min_lat, min_lon, max_lat, max_lon)
    {
        if (dragging) {
            dragging = false;
            return;
        }
    	var old_zoom = map.getZoom();
		var min = new GLatLng(min_lat, min_lon);
		var max = new GLatLng(max_lat, max_lon);
		var bounds = new GLatLngBounds(min, max);
		var center = bounds.getCenter();
		var zoom = map.getBoundsZoomLevel(bounds);
		if (zoom == old_zoom) { zoom = zoom + 1; }
		map.setCenter(center, zoom);
		loadClusters();
    }
	
	/*
	 * Internet explorer fix to position auto zoom on lower resolutions
	 * */
//	function positionAutoZoomForIE()
//	{
//		var IE = /*@cc_on!@*/false;
//		
//		if(IE && screen.width<=1280)
//		{
//			autoZoomDiv = document.getElementById("zoominputduo");
//			autoZoomDiv.style.position = "relative";
//			autoZoomDiv.style.left = "-100px";
//			autoZoomDiv.style.top = "30px";
//			autoZoomDiv.style.minWidth = "300px";
//		}
//	}
    
    function implodeTypes()
    {
		var type = '';
		for (t in types) if(types[t]) type = type + '-' + t;
		return type
    }

    function buildUrl(zoom)
    {
		var bounds = map.getBounds();
		if (document.getElementById('autozoom').checked && autoZoom) bounds = new GLatLngBounds(new GLatLng(-90, -180), new GLatLng(90, 180));
		var southWest = bounds.getSouthWest();
		var northEast = bounds.getNorthEast();
		var keywords          = '';
		var characteristic    = '';
		var theme             = '';
		var score             = '';
		var length            = '';
		var group             = '';
		var language          = '';
        if (zoom == undefined) { var zoom = map.getBoundsZoomLevel(bounds); }
            
		if (getElementValue('searchkeywords') ) keywords         = getElementValue('searchkeywords');
		if (getElementValue('characteristic') ) characteristic   = getElementValue('characteristic');
		if (getElementValue('theme')          ) theme            = getElementValue('theme');
		if (getElementValue('score')          ) score            = getElementValue('score');
		if (getElementValue('length')         ) length           = getElementValue('length');
		if (getElementValue('group')          ) group            = getElementValue('group');
		if (getElementValue('searchlang')     ) language         = getElementValue('searchlang');
		var url = "/route/search_clusters.en?"
					 + "min_lon="+ southWest.lng()
					 + "&max_lon="+ northEast.lng()
					 + "&min_lat="+ southWest.lat()
					 + "&max_lat="+ northEast.lat()
					 + "&zoom="+ zoom
					 + "&types="+ implodeTypes()
					 + "&keywords="+ escape(keywords)
					 + "&characteristic="+ escape(characteristic)
					 + "&theme="+ escape(theme)
					 + "&score="+ escape(score)
					 + "&length="+ escape(length)
					 + "&group="+ escape(group)
					 + "&language="+ escape(language);
        return url;
    }  
          
    function getElementValue(id)
    {
    	var e = document.getElementById(id);
    	if (! e ) return false;
    	if (! e.value) return false;
    	return e.value; 
    }
    
    function drawRoutes(clusters)
    {
		var list = document.getElementById('second');
        var routeCounter = 0;
        var clusterCounter = 0;
		list.innerHTML = ''; 
		for ( var i=0 ; i < clusters.length ; ++i )
        {
			route = clusters[i];
			if (route.type == 'cluster') 
            {
                clusterCounter++; 
                continue;
            }
            
            routeCounter++;
            list.innerHTML = list.innerHTML + route.html;
            
            if (! (gmarkers[route.route_id] == undefined)) continue; 

				if (route.routeId == selected) active = selected;
	
	    		// Create our "tiny" marker icon
	    		icon = new GIcon();
	    		var image = "http://www.routeyou.com/images/map_icons/map_"+route.type+"_"+route.score+".png";
	    		icon.image = image.toLowerCase();
	    	    icon.shadow = "http://www.routeyou.com/images/map_icons/shadow.png";
	    	    icon.iconSize = new GSize(35, 35);
	    	    icon.shadowSize = new GSize(52, 35);
	        	icon.iconAnchor = new GPoint(17, 35);
	    	    icon.infoWindowAnchor = new GPoint(17, 35);	
	
	    		// Set up our GMarkerOptions object
	    		var point = new GLatLng(route.lat, route.lon);
	       		var markerOptions = { icon:icon, maxWidth: 250 };
	       		marker = new GMarker(point, markerOptions);
                route.html = '<div style="width:250px; display:block">'+route.html+'</div>';
	       		marker.bindInfoWindowHtml(route.html);
	       		gmarkers[route.route_id] = marker;
	       		htmls[route.route_id] = route.html;
	       		otnIds[route.route_id] = route.otn_id;
	       		
	       		// mouseover for icon
	       		GEvent.bind(marker, "mouseover", route, function() { 
	       			routeHover(this.route_id);
				}); 
	       		
	    		map.addOverlay(marker);			

        }

        if ((routeCounter > 99) || (clusterCounter == 0))
        {
            moreZoom--;
        }
        
		if (routeCounter == 0) list.innerHTML = noResults; 
        else if((routeCounter < 100) && (clusterCounter > 0)) list.innerHTML = list.innerHTML + '<center><br clear="all"><div class="btn_160" onclick="more();">'+moreResults+'</div></center>'; 
        else if(routeCounter > 99) list.innerHTML = list.innerHTML + maxResults;
        prevCount = routeCounter;
		list.style.background = 'none'; 
    }
    	    	
    function drawClusters(clusters)
    {    	    
    	var cluster;
   		var icon;
   		var marker;
   		var active = false;

    	map.clearOverlays();
    	activeGmarker = false;

        // auto zoom ?
        if (document.getElementById('autozoom').checked && autoZoom) {
            var bounds = new GLatLngBounds();
    		for ( var i=0 ; i < clusters.length ; ++i )
                if (!(clusters[i].type == 'cluster')) { 
                    route = clusters[i];
                    bounds.extend(new GLatLng(route.lat, route.lon));
                }
                else {
                    cluster = clusters[i];
                    bounds.extend(new GLatLng(cluster.routes_min_lat, cluster.routes_min_lon));
                    bounds.extend(new GLatLng(cluster.routes_max_lat, cluster.routes_max_lon));
                }

            map.setCenter(bounds.getCenter(), Math.min(12, map.getBoundsZoomLevel(bounds))); 		
            autoZoom = false;
            return loadClusters(buildUrl());
        }
        
        gmarkers = [];
        drawRoutes(clusters);
		for ( var i=0 ; i < clusters.length ; ++i ){

			cluster = clusters[i];
			
			if (cluster.type == 'cluster')
			{
				var clusterBounds = new GLatLngBounds(
				    new GLatLng(cluster.min_lat, cluster.min_lon),
				    new GLatLng(cluster.max_lat, cluster.max_lon));
				map.addOverlay(new Cluster(clusterBounds, cluster.html, cluster.size));    
			} 
		}
								
		if (active > 0) routeHover(active);
    }	    
    function refresh(allow_autoZoom)
    {
		if(allow_autoZoom)
			autoZoom = allow_autoZoom;
		else
			autoZoom=false;
		
        loadClusters();
    }
    	
    function more()
    {
        if ((prevCount >= 100) || (moreZoom > 2))
        {
            alert(maxResults); return; 
        }
    
        document.getElementById("second").innerHTML = '';
        document.getElementById("second").style.background = 'URL("/images/loader.gif") center center no-repeat'; 
        request = loadXMLDoc(buildUrl(map.getZoom()+Math.min(3, ++moreZoom)), drawRoutes);
    }
    	
	function loadClusters(value) 
	{
        if (value === buildUrl()) {
    		document.getElementById("second").innerHTML = '';
    		document.getElementById("second").style.background = 'URL("/images/loader.gif") center center no-repeat'; 
    		window.location = buildAnchors();
    		if (prevrequest) prevrequest.onreadystatechange = function() {}
    		prevrequest = loadXMLDoc(buildUrl(), drawClusters);
        }
        else if (value === undefined) {
            setTimeout('loadClusters("'+buildUrl()+'")', 200);
        }
	} 
	
	function setHeights()
	{
        var advanced   = document.getElementById('advanced');
        var toolbar    = document.getElementById("toolbar");
        var map_search = document.getElementById("map_search");
        var second     = document.getElementById("second");
        var second_div = document.getElementById("second_div");
        // minus 2 for borders
   		map_search.style.height = (iframe_height - 57 - advanced.offsetHeight - toolbar.offsetHeight) + 'px';
   		second.style.height = (iframe_height - toolbar.offsetHeight) + 23 + 'px';
   		second_div.style.height = (iframe_height - toolbar.offsetHeight) + 23 + 'px';
	}
	
	function toggleAdvanced()
	{
        var advanced = document.getElementById('advanced');
		var zoomInputDuo = document.getElementById('zoominputduo');
		
        if (advanced.style.display === 'block')            
            advanced.style.display = 'none';	
        else
            advanced.style.display = 'block';	
			
			
			if(zoomInputDuo.style.display ==='block')
				zoomInputDuo.style.display = 'none';
			else
				zoomInputDuo.style.display = 'block';
			
        setHeights();
	}
    
    /**
     * onchange listener (see html) does not check for ENTER in IE/Opera,
     * so this is a workaround.
     */
    function goToLocation(e, location)
    {
        if(!e)
            e = window.event;
        
        if(e.keyCode == 13) {
            if(geocoder==null) {
                geocoder = new GClientGeocoder();
            }
            
            geocoder.getLatLng(location,
                               function(point) {
                                                    if (point)
                                                    {
                                                        map.setCenter(point,13);
                                                        loadClusters();
                                                    }
                                               });
        }
    }
