
    var map = null;
    var geocoder = null;
    var currentZoomLevel = 13;
    var xmlHttp;
    var secondSearchPerformed = false;
     
    // Initierar karta
    function initializeMap() {
      if (GBrowserIsCompatible()) {
        map = new GMap2(document.getElementById("map_canvas"));
        map.setCenter(new GLatLng(59.85723009946356, 17.653656005859375), currentZoomLevel); // Uppsala 
	map.addControl(new GSmallZoomControl);
	GEvent.addListener(map, "zoomend", function(oldzoomlevel, newzoomlevel) {
	  //currentZoomLevel = newzoomlevel; // Zoomnivån ska uppdateras för alla kommande sökningar när användaren ändrar zoom manuellt
	  map.clearOverlays(); // Ta bort gamla ikoner från kartan
	  findShopsNearby(false); // Gör automatiskt om sökningen när användaren ändrat zoomnivå
	});
	GEvent.addListener(map, "dragend", function(){ 
	  map.clearOverlays(); // Ta bort gamla ikoner från kartan
	  findShopsNearby(false); // Uppdatera kartan när användaren panorerat i kartbilden
	});

        geocoder = new GClientGeocoder();

      } else {
	alert("Din webbläsare stödjer tyvärr inte sökning via karta. Uppdatera din webbläsare, eller sök endast via lista.");
      }
    }

    /*
    // Ser till att kartan frigörs då besökaren lämnar sidan
    function addUnloadMap() {
	if (window.attachEvent) {
		window.attachEvent("onunload", function() {
		        GUnload();      // Internet Explorer
		});
	} else {

		window.addEventListener("unload", function() {
		        GUnload(); // Firefox och andra standardwebbläsare
		}, false);

	}
    } /**/


   function toggleArrow(imageIdToToggle) {
	var oIndicatorToToggle = document.getElementById(imageIdToToggle);
	if(oIndicatorToToggle.src.indexOf('Up') != -1) {
		oIndicatorToToggle.src = 'images/arrowDown.gif';
	} else {
		oIndicatorToToggle.src = 'images/arrowUp.gif';
	}
	
   }

   // Ser till att ingen sökning genomförs när användaren trycker enter
   // Bör inte behövas från och med version 2.3
   function submitenter(myfield,e) {
	var keycode;
	if (window.event) keycode = window.event.keyCode;
	else if (e) keycode = e.which;
	else return true;

	if (keycode == 13)
	   {
	   return false;
	   }
	else
	   return true;
    }


    // Initierar rätt typ av sökning beroende på vad besökaren valt
    function performSearch(){

	var strAddressOrCity = document.getElementById("inputAddress").value;
	var bolResultsOnMap = document.getElementById("searchTypeMap").checked;
	var strSelectedSearchRadius = document.getElementById("searchRadius").value;

	currentZoomLevel = radiusToZoomlevel(strSelectedSearchRadius); // Ställ in zoomnivå utifrån given sökradie

	document.getElementById("results").style.display = ""; // Visa kartområde
	//if(map == null) {
		
	//} else {
	//	map.clearOverlays(); // Ta bort tidigare markeringar från kartan
	//}
	// addUnloadMap(); // Se till att kartan frigörs då besökaren lämnar sidan (body unload event körs)

	// Gör rätt typ av sökning beroende på om resultaten ska listas eller visas på karta
	if(bolResultsOnMap) {
		// Visa resultat på karta
		document.getElementById("resultMap").style.display = ""; // Visa kartområde
		document.getElementById("resultList").style.display = "none"; // Dölj resultatlista
		initializeMap(); // Initiera karta efter att den varit dold
		showAddress(strAddressOrCity, false); // Visa vald adress och närbelägna butiker på karta
	} else{
		// Visa resultat i träfflista
		secondSearchPerformed = false; // En ny sökning börjar, tillåt dubbla sökningar på först stad och sedan adress
		document.getElementById("resultMap").style.display = "none"; // Dölj kartområde
		document.getElementById("resultList").style.display = ""; // Visa resultatlista
		// findPricesForCity(strAddressOrCity); // Gör sökning för angiven postort, om inga träffar återfinns, slå upp adressen och sök därikring
		showAddress(strAddressOrCity, true); // Slå upp adressen och sök butiker i närheten
	}

	location.hash = 'searchResults';
	
    }

    function updateMap() {
	findShopsNearby(false); 
    }

    /**
     * Returnerar den zoomnivå som motsvarar en sökning inom givet
     * antal kilometer.
     * Endast parametrarna 0.5, 2, 5, 20 och 50 ger korrekta zoom-nivåer,
     * andra inparametrar ger alltid resultatet "13", vilket är standardzoomnivån.
     */
    function radiusToZoomlevel(radiusInKm) {
	// 9  = 46km radie
	// 10 = 23km radie
	// 11 = 11,6km radie
	// 12 = 5,6km radie
	// 13 = 2,2km radie
	// 14 = 1,1km radie
	// 15 = 0,568km radie
	// 16 = 0,27km radie
	var zoomLevel;
	if(radiusInKm == 0.5) { zoomLevel = 15; }
	else if(radiusInKm == 2) { zoomLevel = 13; }
	else if(radiusInKm == 5) { zoomLevel = 12; }
	else if(radiusInKm == 20) { zoomLevel = 10; }
	else if(radiusInKm == 50) { zoomLevel = 9; }
	else { zoomLevel = 13; }
	return zoomLevel;
    }

    /**
     * Hittar given adress på kartan, sätter en markör där och initierar 
     * sökfråga för butiker i närheten av den funna adressen. Om 
     * showResultInList är true visas resultaten i en lista istället för
     * på kartan.
     */
    function showAddress(address, showResultInList) {
      if (geocoder) {
	var blueIcon = new GIcon(G_DEFAULT_ICON);
	blueIcon.image = "images/ikon_hem.png";
	blueIcon.iconSize = new GSize(23, 32);

	markerOptions = { icon:blueIcon };

        geocoder.getLatLng(
          address,
          function(point) {
            if (!point) {
              alert(address + " hittades inte");
            } else {
              map.setCenter(point, currentZoomLevel); // Vid en ny sökning visas alltid kartan med aktuell zoom-nivå
              var marker = new GMarker(point, markerOptions);
              map.addOverlay(marker);
	      findShopsNearby(showResultInList);
            }
          }
        );
      }
    }

    /**
     * Initierar fråga för att hämta en lista med butiksnamn och priser med postadress i given stad.
     */
    function findPricesForCity(city){
	var strFormname = "priceSearchForm";
	var currentCheckbox;
	var strSelectedProductIds = "";
	var numSelectedProducts = 0;
	for(var i = 1; i<=82; i++){
	   currentCheckbox = eval("document." + strFormname + ".p" + i);
	   if(currentCheckbox.checked){
		strSelectedProductIds += "," + i;	
		numSelectedProducts++;
	   }
	}
	if(numSelectedProducts == 0) {
		alert("Välj minst en produkt");
	} else {
		xmlHttp=GetXmlHttpObject();
		if (xmlHttp==null)
		 {
		 alert ("Sökningen kan inte genomföras eftersom din webbläsare inte stödjer Ajax.\nUppdatera din webbläsare för att fortsätta.");
		 return;
		 }
		var url="ajax_backend.php";
		url += "?action=getPricesForCity";
		url += "&city="+ city;
		url += "&productIds=" + strSelectedProductIds;
		url += "&sid="+Math.random();
		xmlHttp.onreadystatechange=updateResultShopList; // Definiera funktion att anropa när svaret anländer
		xmlHttp.open("GET",url,true);
		xmlHttp.send(null);
	}
    }

    /* 
     * Startar asynkront anrop till server för att hitta butiker och 
     * priser i närheten av kartans nuvarande centerposition.
     */
    function findShopsNearby(showResultInList){
	var bounds = map.getBounds();
	var southWest = bounds.getSouthWest();
	var northEast = bounds.getNorthEast();	
	var strFormname = "priceSearchForm";
	var surveyType = document.getElementById("pricesToShow").value;
	var currentCheckbox;
	var strSelectedProductIds = "";
	var numSelectedProducts = 0;
	for(var i = 1; i<=82; i++){
	   currentCheckbox = eval("document." + strFormname + ".p" + i);
	   if(currentCheckbox != null && currentCheckbox.checked){
		strSelectedProductIds += "," + i;	
	   	numSelectedProducts++;
	   }
	}
 
	if(numSelectedProducts == 0) {
		alert("Välj minst en produkt");
	} else {
		xmlHttp=GetXmlHttpObject();
		if (xmlHttp==null)
		 {
		 alert ("Sökningen kan inte genomföras eftersom din webbläsare inte stödjer Ajax.\nUppdatera din webbläsare för att fortsätta.");
		 return;
		 }
		var url="ajax_backend.php";
		url += "?swLat="+southWest.lat();
		url += "&swLong="+southWest.lng();
		url += "&neLat="+northEast.lat();
		url += "&neLong="+northEast.lng();
		url += "&productIds=" + strSelectedProductIds;
		url += "&zoomlevel=" + currentZoomLevel;
		url += "&mapIsMinimized=" + showResultInList; // Om sökresultat ska visas i lista är kartan minimerad
		url += "&action=getShops";
		url += "&surveyType=" + surveyType; // "pro" / "user" / "all"
		url += "&sid="+Math.random();
		if(showResultInList) {
		  xmlHttp.onreadystatechange=updateResultShopList; // Visa sökresultaten i lista
		} else {
		  xmlHttp.onreadystatechange=stateChanged; // Visa sökresultaten på karta
		}
		xmlHttp.open("GET",url,true);
		xmlHttp.send(null);
	}
    }

    /**
     * Definition of the shop class
     */
    function Shop(){
	this.shopName = "No name";
	this.shopId = 0;
	this.lat = 0;
	this.lng = 0;
	this.avgCartPrice = 0;
	this.latestPriceUpdate = "Okänt";
	this.isBestOnMap = false;
	this.city = "okänd stad";
    }

    /** Körs då asynkront anrop till kartuppdatering resurnerar resultat */
    function stateChanged() { 
	if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete") { 
	   document.getElementById("searchInProgress").style.display = "none"; // Dölj informationsrutan "Sökning pågår..."
	   var xmlShops = xmlHttp.responseXML;

	   var root = xmlShops.getElementsByTagName('shops').item(0);
	   //alert(xmlHttp.responseText);

	   if(root == null) {
		alert("Hittade inga butiker. Prova att zooma ut, eller att söka \nefter butiker i en större närliggande stad.");
	   } else {
		   var warnings = xmlShops.getElementsByTagName("warning").item(0);
		   if(warnings != null && warnings.childNodes.item(0).data == 1){
			// Visa varning, kod 1
			alert("Det finns så många butiker i detta område att bara en del av dem kan visas. Zooma in för att visa alla butiker i området.");
	   	   } else if(warnings != null && warnings.childNodes.item(0).data == 2){
				// Visa varning, kod 2
				alert("Än så länge finns ekologiska priser bara i Uppsala och Halmstad. De ekologiska produkter du valt har inte räknats med i priserna i sökresultatet.");
	   	   } else if(warnings != null && warnings.childNodes.item(0).data == 3){
				// Visa varning, kod 3
				alert("Än så länge finns ekologiska priser bara i Uppsala och Halmstad. Eftersom du bara valt ekologiska produkter kan vi därför inte visa några prisuppgifter.");
		   } else if(warnings != null && warnings.childNodes.item(0).data == 4){
				// Visa varning, kod 4
				alert("Hittade inga prisuppgifter. Prova att zooma ut, söka \nefter butiker i en större närliggande stad, \neller välja bort några produkter.");
		   } else if(warnings != null && warnings.childNodes.item(0).data == 5){
				// Visa varning, kod 5
				alert("Hittade inga prisuppgifter. Priser för ekologiska och icke-ekologiska produkter undersöks \nofta vid olika tillfällen och är därför inte jämförbara. Fler priser kan därför visas om \ndu väljer enbart ekologiska eller enbart icke-ekologiska produkter.");
		   }





		   for(var idxShop=0; idxShop < root.childNodes.length; idxShop++){
			var oShop = new Shop();
			var currentShop = root.childNodes.item(idxShop);
			oShop.lat = currentShop.getElementsByTagName("latitude").item(0).childNodes.item(0).data;
			oShop.lng = currentShop.getElementsByTagName("longitude").item(0).childNodes.item(0).data;
			oShop.shopName = currentShop.getElementsByTagName("shopName").item(0).childNodes.item(0).data;
			oShop.shopId = currentShop.getElementsByTagName("shopId").item(0).childNodes.item(0).data;
			oShop.avgCartPrice = currentShop.getElementsByTagName("priceForCart").item(0).childNodes.item(0).data;
			oShop.latestPriceUpdate = currentShop.getElementsByTagName("latestPriceUpdate").item(0).childNodes.item(0).data;
			oShop.isBestOnMap = (currentShop.getElementsByTagName("isBestOnMap").item(0).childNodes.item(0).data == "true" ? true : false);
			oShop.city = currentShop.getElementsByTagName("city").item(0).childNodes.item(0).data;
			var storeMarker = createMarker(oShop);
			map.addOverlay(storeMarker);
		   }
	   }
	 } 
    }

    /** Funktion som körs då asynkront anrop till listuppdatering returnerar resultat */
    function updateResultShopList(){
	if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete") { 
		var strResultToPrint = "";
		var xmlShopList = xmlHttp.responseXML;
		//alert(xmlHttp.responseText);

		var root = xmlShopList.getElementsByTagName('shops').item(0);


		//if((root == null || root.childNodes.length == 0)&& !secondSearchPerformed) {
		//	// Gör om sökning ifall inga butiker påträffades // BORTTAGET Sedan sökning på postort inaktiverades
		//	var strAddressOrCity = document.getElementById("inputAddress").value;
		//	secondSearchPerformed = true; // Kom ihåg att sökningen har gjorts om för att undvika oändlig loop
		//	initializeMap();
		//	showAddress(strAddressOrCity, true);
		/*} else */ if(root == null || root.childNodes.length == 0) {
			alert("Hittade tyvärr inga butiker");
			document.getElementById("resultList").innerHTML = "<p>Tyvärr hittades inga butiker vid din sökning.</p>";
		} else {
			// Hittade butiker; visa dessa i listan
			var isEven;
		   	var warnings = xmlShopList.getElementsByTagName("warning").item(0);
		   	if(warnings != null && warnings.childNodes.item(0).data == 1){
				// Visa varning, kod 1
				alert("Det finns så många butiker i detta område att bara en del av dem kan visas. Välj ett mindre sökområde för att visa alla butiker i området.");
		   } else if(warnings != null && warnings.childNodes.item(0).data == 4){
				// Visa varning, kod 4
				alert("Hittade inga prisuppgifter. Prova att zooma ut, söka \nefter butiker i en större närliggande stad, \neller välja bort några produkter.");
		   }
		   // Varningskod 2, 3 och 5 användes tidigare för att informera användaren om att ekologiska produkter bara fanns i Uppsala och Halmstad

			var comparisonGroup = xmlShopList.getElementsByTagName("priceComparisonGroup").item(0);
			var strUpdatePeriod;
			var priceComparisonGroup = 1;
			if(comparisonGroup != null){
				// Visa information om vilken undersökning som resultat visas från
				strUpdatePeriod = "<p>Priser uppdaterade "
					  + comparisonGroup.getElementsByTagName("fromDate").item(0).childNodes.item(0).data
					  + " till "
					  + comparisonGroup.getElementsByTagName("toDate").item(0).childNodes.item(0).data
					  + ".</p>";
				priceComparisonGroup = comparisonGroup.getElementsByTagName("groupId").item(0).childNodes.item(0).data;
			}

		   	for(var idxShop=0; idxShop < root.childNodes.length; idxShop++){
				var oShop = new Shop();
				var currentShop = root.childNodes.item(idxShop);
				var isEven = (idxShop % 2 == 0);
				oShop.shopName = currentShop.getElementsByTagName("shopName").item(0).childNodes.item(0).data;
				oShop.shopId = currentShop.getElementsByTagName("shopId").item(0).childNodes.item(0).data;
				oShop.avgCartPrice = currentShop.getElementsByTagName("priceForCart").item(0).childNodes.item(0).data;
				oShop.city = currentShop.getElementsByTagName("city").item(0).childNodes.item(0).data;
				strResultToPrint += getResultlistHtml(oShop, priceComparisonGroup, isEven);

			}
			document.getElementById("resultMap").style.display = "none";
			var searchRadius = document.getElementById("searchRadius").value + "km";
			var strIntro = "<p>Visar priser för vald matkasse cirka "+ searchRadius +" från \""+ document.getElementById("inputAddress").value +"\". Listan är sorterad efter pris, billigast matkasse först. Observera att det i många fall finns butiker i området som inte är med i undersökningen.</p>";
			strIntro += strUpdatePeriod;
			strIntro += "<p><a href=\"dispatcher.php?action=giveFeedback\">Är någon uppgift fel, eller saknar du en butik?</a></p>";
			var strTableStart = "<table cellpadding=\"0\" cellspacing=\"0\" id=\"resultListTable\">" +
				"<tr><th>Butik (postort) </th><th>Pris, din matkasse</th></tr>";
			var strTableEnd = "</table>"; 
		
			document.getElementById("resultList").innerHTML = strIntro + strTableStart + strResultToPrint + strTableEnd; // Update html 

			location.hash = 'searchResults'; // Scrolla ned till sökresultatet
		}

	}
    }

    /** Skapa markör för given butik  */
    function createMarker(shop){
	if(shop.avgCartPrice == "null") {
		// Skapa ikon för butik som inte har priser
		var unknownPriceIcon = new GIcon(G_DEFAULT_ICON);
		unknownPriceIcon.image = "images/ikon_fraga-002.png";
		unknownPriceIcon.iconSize = new GSize(18, 25);

		markerOptions = { icon:unknownPriceIcon };

		var marker = new GMarker(new GLatLng(shop.lat, shop.lng), markerOptions);
		marker.html = "<div class=\"shopInfo\"><b>" + shop.shopName + "</b><br />Brukar du handla här?<br /> "
			+ "<a href=\"dispatcher.php?action=registerPrices&shopId="+ shop.shopId +"\">Berätta vad det kostade sist!</a></div>";
	} else {
		// Skapa ikon för butik med prisinformation
		if(shop.isBestOnMap) {
			// Skapa ikon för den butik med bäst priser på kartan
			var bestOnMapIcon = new GIcon(G_DEFAULT_ICON);
			bestOnMapIcon.image = "images/ikon_bastaButik.png";
			bestOnMapIcon.iconSize = new GSize(32, 32);

			markerOptions = { icon:bestOnMapIcon, zIndexProcess:function(marker,b){return 300000;} }; // Den bästa ikonen visas alltid med z-index 300000, vilket gör att den hamnar över alla andra ikoner (andra ikoner kan ha z-index -281250 till +281250)

			var marker = new GMarker(new GLatLng(shop.lat, shop.lng), markerOptions);
		} else {
			var shopIcon = new GIcon(G_DEFAULT_ICON);
			shopIcon.image = "images/ikon_butik.png";
			shopIcon.iconSize = new GSize(32, 32);

			markerOptions = { icon:shopIcon };
			var marker = new GMarker(new GLatLng(shop.lat, shop.lng), markerOptions);
		}

		marker.html = 
			"<div class=\"shopInfo\">"
			+ "<b>" + shop.shopName + "</b><br />\n"
			+ "Pris, din matkasse: " + shop.avgCartPrice + "kr<br />"
			+ "Uppdateringsdatum: " + shop.latestPriceUpdate + "<br />"
			+ "<a href=\"dispatcher.php?action=showDetailedPrices&amp;shopId="+ shop.shopId +"\">Visa detaljer</a><br />"
			+ "<a href=\"dispatcher.php?action=giveFeedback&amp;shopId="+ shop.shopId +"\">Är uppgiften fel?</a><br />"
			+ "<a href=\"dispatcher.php?action=registerPrices&amp;shopId="+ shop.shopId +"\">Har du handlat här nyligen?</a>"
			+ "</div>";
 	}
	  GEvent.addListener(marker, 'click', function() {
	    currentMarker = marker;
	    marker.openInfoWindowHtml(marker.html);
	  });
	  return marker;

    }

    /** Returnerar html-fragment för en butik (att visa i lista med priser) */
    function getResultlistHtml(oShop, priceComparisonGroup, isEven) {
	var cssClass = (isEven ? "even" : "odd");
	return "<tr class=\""+ cssClass +"\"><td><a href=\"dispatcher.php?action=showDetailedPrices&amp;shopId="+ oShop.shopId + "&amp;priceComparisonGroup="+ priceComparisonGroup +"\">" + oShop.shopName + "</a> (" + oShop.city +") </td><td>" + oShop.avgCartPrice + "kr</td></tr>";
    }

    function selectAllProducts() {
	var strFormname = "priceSearchForm";
	var currentCheckbox;
	var strSelectedProductIds = "";
	for(var i = 1; i<=82; i++){
	   currentCheckbox = eval("document." + strFormname + ".p" + i);
	   if(currentCheckbox != null)
	      currentCheckbox.checked = true;
	}
	//document.getElementById("ecoProductsNotAutoSelected").style.display = "";
    }
    
    function deSelectAllProducts() {
	var strFormname = "priceSearchForm";
	var currentCheckbox;
	var strSelectedProductIds = "";
	for(var i = 1; i<=82; i++){
	   currentCheckbox = eval("document." + strFormname + ".p" + i);
	   if(currentCheckbox != null)
	      currentCheckbox.checked = false;
	}
	//document.getElementById("ecoProductsNotAutoSelected").style.display = "none";
    }

    function selectProductCategory(categoryCheckbox, strCategory) {
	var strFormname = "priceSearchForm";

	var arrEkologiskt = [61,62,63,71,76,77,78,79,80,81];
	var arrBrod = [9,10,11,12];
	var arrFrukost = [13,4,58];
	var arrMejeri = [15,16,17,18,19,20,22,73];
	var arrBak = [1,2];
	var arrSmak = [21,48,51,23,44,3,56,49,50];
	var arrKottFisk = [30,34,35,46,45,37,60,33,74];
	var arrFardigmat = [59,31,32,38,39,47]
      	var arrBasmat = [14,41,52,5,6];
	var arrRotsaker = [43,40,42];
	var arrDryck = [7,8,53,57,75];
	var arrOvrigt = [25,26,27,28,29,55];

	var currentCheckbox;
	var arrCurrentCategory = eval("arr" + strCategory);
      	for(var i = 0; i<arrCurrentCategory.length; i++) {
	   currentCheckbox = eval("document." + strFormname + ".p" + arrCurrentCategory[i]);
	   currentCheckbox.checked = categoryCheckbox.checked;
      	}
    }

    function GetXmlHttpObject(){
	var xmlHttp=null;
	try
	 {
	 // Firefox, Opera 8.0+, Safari
	 xmlHttp=new XMLHttpRequest();
	 }
	catch (e)
	 {
	 //Internet Explorer
	 try
	  {
	  xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
	  }
	 catch (e)
	  {
	  xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
	  }
	 }
	return xmlHttp;
    }

    function displayMapCenter() {
	document.getElementById("centerCoordinates").innerHTML = map.getCenter();
    }

