var maps = {};

$(document).ready(function(){
    
    //var xmlData = null;
    
	$.ajax({
	    type: "GET",
	    url: "?alttemplate=xmlguides",
	    //dataType: "xml",
	    success: function(data) {
	        //xmlData = data;
	        ParseXML(data);
	    }
	});
	
	var map;
	var rootCity;
	var markers = [];
	var types = [];
	var guides = [];
	var hotels = [];
	var iconDirectory = "/images/generic/markers/";
	var infoBoxMaxWidth = 350;
	
	function ParseXML(data)
	{
	    map = CreateMap();
	    var bounds = new GLatLngBounds(); //use bounds to auto zoom and center
	    
	    //gets whether the directions will be drawn on the map or not
	    var directionsOn = $(data).find("guides").attr('directions');
	    var checkboxesOn = $(data).find("guides").attr('checkboxes');
	    var zoomType = $(data).find("guides").attr('zoomtype');
	    
	    window.log("Directions: " + directionsOn);
	    window.log("Checkboxes: " + checkboxesOn);
	    window.log("ZoomType: " + zoomType);
	    
	    $(data).find("guide").each(function(i){
	        
	        //initialise variables
	        var id = $(this).attr('id');
	        var name = $(this).attr('name');
	        var type = $(this).attr('type');
	        var desc = $(this).attr('description');
	        var address = $(this).attr('address');
	        var city = $(this).attr('city');
	        var phone = $(this).attr('phone');
	        var latitude = $(this).attr('latitude');
	        var longitude = $(this).attr('longitude');
	        var zoom = $(this).attr('zoom');
	        var website = $(this).attr('website');
	        var url = $(this).attr('url');
	        var linktoguideitem = $(this).attr('linktoguideitem');
	        var typecount = $(this).attr("typecount");
	        
	        if(type == "Hotel")
	        {
	            var hotel = new Hotel();
	            hotel.name = name;
	            hotel.latitude = latitude;
	            hotel.longitude = longitude;
	            hotel.url = url;
	            hotel.address = address;
	            hotels.push(hotel);
	        }
	        
	        //Create an object to store all guide info in one place.
	        var guide = new Guide(id, name, type, desc, address, city, phone, latitude, longitude, zoom, website, url, linktoguideitem, typecount);
	        rootCity = guide.city;
	        
	        //seperate icon if it's a hotel
	        var iconImg; //for use in log
	        if(type == "Hotel")
	        {
	            iconImg = GetIcon(guide.name.toLowerCase()); //use name for hotel rather than type
	            var icon = new GIcon(G_DEFAULT_ICON, iconImg);
	            icon.iconSize = new GSize(26, 32)
	            icon.shadow = "/images/generic/markers/hotel-icon-shadow.png";
	            icon.shadowSize = new GSize(43, 32);
	        }
	        else
	        {
	            iconImg = GetIcon(guide.type.toLowerCase());
	            var icon = new GIcon(G_DEFAULT_ICON, iconImg);
	            icon.iconAnchor = new GPoint(6,20);
	            icon.iconSize = new GSize(12, 20);
	            icon.shadow = "/images/generic/markers/shadow.png";
	            icon.shadowSize = new GSize(22, 20);
	        }
	        
	        //set the point
	        var point = new GLatLng(guide.latitude, guide.longitude);
	        
	        //if hotel just use hotel locs for bounds.
	        if(zoomType == "hotel") {
	            if(type == "Hotel") bounds.extend(point);
	        }
	        else {
	            bounds.extend(point);
	        }
	        
	        var marker = new GMarker(point, icon);
	        window.log("Marker " + i + ": " + guide.name + ", Point: " + point + ", Icon: " + iconImg);
	        
	        //add some variables to the marker object
	        marker.type = guide.type;
	        marker.name = guide.name;
	        marker.x = guide.latitude;
	        marker.y = guide.longitude;
	        marker.id = guide.id;
	        
	        map.addOverlay(marker);
	        
	        //click event
	        GEvent.addListener(marker, "click", function(){
	            marker.openInfoWindowHtml(BuildInfoBox(guide, marker, directionsOn), {maxWidth:infoBoxMaxWidth});
	        });
	        
	        markers.push(marker);
	        types.push(guide.type);	
	        guides.push(guide);
	    });
	    
	    map.setZoom(map.getBoundsZoomLevel(bounds)-1);
	    var centralLatitude = (bounds.getNorthEast().lat() + bounds.getSouthWest().lat()) /2;
	    var centralLongitude = (bounds.getNorthEast().lng() + bounds.getSouthWest().lng()) /2;
	    map.setCenter(new GLatLng(centralLatitude, centralLongitude));
	    
	    CreateCustomControls(map);
	    if(checkboxesOn == "true")
	    {
	        CreateCheckBoxes(data, rootCity);
	        $("#guide-map-checkboxes").animate({'height':'100%'}, 600);
	    }
	    GEvent.addListener(map, "tilesloaded", LoadFinished);
	}

	//guide class
	function Guide(id, name, type, desc, address, city, phone, latitude, longitude, zoom, website, url, linktoguideitem, typecount)
	{
	    this.id = id;
	    this.name = name;
	    this.type = type;
	    this.desc = desc;
	    this.address = address;
	    this.city = city;
	    this.phone = phone;
	    this.latitude = latitude;
	    this.longitude = longitude;
	    this.zoom = zoom;
	    this.website = website;
	    this.url = url;
	    this.linktoguideitem = linktoguideitem;
	    this.typecount = typecount;
	}
	
	function Hotel(){}
	
	function CreateMap()
	{
	    var gmap = new GMap2(document.getElementById("guide-map"));
	    var mapCentre = new GLatLng(51.504468609578,-0.149688720703);
	    gmap.setCenter(mapCentre, 12);
	    //map.enableGoogleBar();
	    return gmap;
	}
	
	maps.OpenMarker = function(index)
	{
	    GEvent.trigger(markers[index],"click");
	}
	
	maps.HideBanner = function()
	{
	    $("#guide-map-banner").fadeOut("slow");
	    $("#guide-map-overlay-banner").fadeIn("slow");
	    return false;
	}
	
	maps.ShowBanner = function()
	{
	    $("#guide-map-banner").fadeIn("slow");
	    $("#guide-map-overlay-banner").fadeOut("slow");
	    return false;
	}
	
	function CreateCheckBoxes(data, city)
	{
	    $(GetUniqueArray(types)).each(function(i, type){
	        if(type != "Hotel") //dont show hotel in checkboxlist
	        {
	            var label = $("<label />").html("<span>" + city + " " + type + "<span id='guide-key-" + type.stripChars() + "'>(" + GetCountOfType(type, data) + ")</span></span>").appendTo("#guide-map-checkboxes");
	            var checkbox = $("<input type='checkbox' />").attr("value", type).attr("checked", "checked").appendTo(label);
	            window.log("Checkbox " + i + ": " + city + " " + type);
	            $(checkbox).click(function(){
	                ToggleMarkers(this, type);
	            });
	        }
	    });
	}
	
	function GetCountOfType(type, data)
	{
	    var counter = 0;
	    $(data).find('guide').each(function(i){
	        if($(this).attr("type")==type) counter++;
	    });
	    return counter;
	}
	
	function CreateCustomControls(map)
	{
	    var zoomWrapper = "<div id='guide-map-zoomcontrols' />";
	    var zoomIn = "<div id='guide-map-zoom-in'><a href='#'><img src='/images/generic/maps/zoom-in.gif' border='0'/></a></div>";
	    var zoomOut = "<div id='guide-map-zoom-out'><a href='#'><img src='/images/generic/maps/zoom-out.gif' border='0'/></a></div>";
	    var mapTerrainWrapper = "<div id='guide-map-terraincontrols' />";
	    var mapView = "<div id='guide-map-mapview'><a href='#'>Map</a></div>";
	    var satelliteView = "<div id='guide-map-satelliteview'><a href='#'>Satellite</a></div>";
	    var hybridView = "<div id='guide-map-hybridview'><a href='#'>Hybrid</a></div>";
	    
	    $("#guide-map").append(zoomWrapper);
	    $("#guide-map-zoomcontrols").append(zoomIn);
	    $("#guide-map-zoomcontrols").append(zoomOut);
	    
	    $("#guide-map").append(mapTerrainWrapper);
	    $("#guide-map-terraincontrols").append(mapView);
	    $("#guide-map-terraincontrols").append(satelliteView);
	    $("#guide-map-terraincontrols").append(hybridView);
	    
	    $("#guide-map-zoom-in").click(function(){map.zoomIn();});
	    $("#guide-map-zoom-out").click(function(){map.zoomOut();});
	    $("#guide-map-mapview a").click(function(){map.setMapType(G_NORMAL_MAP);});
	    $("#guide-map-satelliteview a").click(function(){map.setMapType(G_SATELLITE_MAP);});
	    $("#guide-map-hybridview a").click(function(){map.setMapType(G_HYBRID_MAP);});
	    
	    window.log("Custom controls: Added");
	}
	
	function BuildInfoBox(guide, marker, directionsOn)
	{
	    var infoBox = [];
	    var metresInAMile = 1609.344;
	    window.log("Clicked: " + guide.name);
	    infoBox.push("<div class='guide-map-infobox'>");
	        //Add inline styles otherwise box height is calculated wrong.
	        infoBox.push("<h1 style='padding:0; margin:0; border:none; font-size:15px;'>" + guide.name + "</h1>");
	        infoBox.push("<p style='padding:0; margin:4px 0 0;'>" + guide.desc + "</p>");
	        infoBox.push("<address style='padding:0; margin:10px 0 0;'>");
	        if(guide.address) infoBox.push("<strong>Address: </strong>" + guide.address + "<br/>");
	        if(guide.phone) infoBox.push("<strong>Tel: </strong>" + guide.phone + "<br/>");
	        if(guide.website) infoBox.push("<strong>Website: </strong><a target=\"_blank\" href=\"http://" + guide.website + "\">" + guide.website + "</a>");
	        infoBox.push("</address>");
	        if(guide.type != "Hotel" && directionsOn=="true")
	        {
	            infoBox.push("<div class=\"guide-map-distances\" style='border-bottom:none;border-top:1px solid #E5E5E5;margin:10px 0 0;padding:10px 0 0;'>");
	            for(i=0; i<hotels.length; i++)
	            {
	                var hotel = hotels[i];
	                var distance = marker.getPoint().distanceFrom(new GLatLng(hotel.latitude, hotel.longitude))/metresInAMile;
	                window.log("Distance: " + distance);
	                if(distance<10){
	                    infoBox.push("<strong><a href=\"#\" onclick=\"maps.GetDirections('" + guide.name + "', " + guide.latitude + ", " + guide.longitude + ", '" + hotel.name + "', " + hotel.latitude + ", " + hotel.longitude + ")\">" + hotel.name + "</a></strong>: " + distance.toFixed(2) + " Miles<br/>");
	                }
	                else if(distance<10)
	                {
	                    infoBox.push("<strong><a href=\"" + hotel.url + "\">" + hotel.name + "</a></strong>: " + distance.toFixed(2) + " Miles<br/>");
	                }
	            }
	            infoBox.push("</div>");
	        }
	    infoBox.push("</div>");
	    return infoBox.join("");
	}
	
	//needs to be accessed from the html onclick, hence being a variable of maps var.
	maps.GetDirections = function(guideName, guideLat, guideLong, hotelName, hotelLat, hotelLong)
	{
	    var displayElement = $("#guide-map-directions").get(0);
	    $(displayElement).show();
	    var directions = new GDirections(map, displayElement);
	    displayElement.innerHTML = ""; //empty the container or it stacks each new result
	    var directionQuery = "from: " + hotelName + "@" + hotelLat + "," + hotelLong + " to: " + guideName + "@" + guideLat + "," + guideLong;
	    window.log("Get Directions: " + directionQuery);
	    directions.load(directionQuery);
	    GEvent.addListener(directions, "error", HandleErrors); // handle errors
	}
	
	function HandleErrors(directions){
	    switch(directions.getStatus().code)
	    {
	        case "G_GEO_UNKNOWN_ADDRESS":
	            window.log("Google Maps Error : 'No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.'");
	            alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.");
	            break;
	        case "G_GEO_SERVER_ERROR":
	            window.log("Google Maps Error : 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.'");
	            alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.");
	            break;
	        case "G_GEO_MISSING_QUERY":
	            window.log("Google Maps Error : 'The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.'");
	            alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.");
	            break;
	        case "G_GEO_BAD_KEY":
	            window.log("Google Maps Error : 'The given key is either invalid or does not match the domain for which it was given.'");
	            alert("The given key is either invalid or does not match the domain for which it was given.");
	            break;
	        case "G_GEO_BAD_REQUEST":
	            window.log("Google Maps Error : 'A directions request could not be successfully parsed.'");
	            alert("A directions request could not be successfully parsed.");
	            break;
	        case "G_GEO_UNAVAILABLE_ADDRESS":
	            window.log("Google Maps Error : 'The route for for the given directions query cannot be returned due to legal or contractual reasons.'");
	            alert("The route for for the given directions query cannot be returned due to legal or contractual reasons.");
	            break;
	        case "G_GEO_UNKNOWN_DIRECTIONS":
	            window.log("Google Maps Error : 'The route for for the given directions query cannot be returned due to legal or contractual reasons.'");
	            alert("We could not compute directions between the points mentioned in this search. This is usually because there is no route available between the two points, or because we do not have data for routing in that region.");
	            break;
	    }
	}
	
	function ToggleMarkers(checkbox, type)
	{
	    (checkbox.checked) ? ShowMarkers(type) : HideMarkers(type);
	}
	
	function ShowMarkers(type)
	{
	    for(i = 0; i < markers.length; i++)
	        if(markers[i].type == type)
	            markers[i].show();
	}
	
	function HideMarkers(type)
	{
	    for(i = 0; i < markers.length; i++)
	        if(markers[i].type == type)
	            markers[i].hide();
	}

	function GetIcon(type)
	{
	    //trim space and ampersand, because it won't find the images with those chars in the file name.
	    var trimmedType = type.stripChars();
	    var icon = iconDirectory + trimmedType + ".png";
	    return icon;
	}
	
	function GetUniqueArray(oldArray)
	{
	    var cleanArray = new Array();
	    o:for(var i = 0, n = oldArray.length; i < n; i++)
	    {
	        for(var x = 0, y = cleanArray.length; x < y; x++)
	        {
	            if(cleanArray[x]==oldArray[i]) continue o;
	        }
	        cleanArray[cleanArray.length] = oldArray[i];
	    }
	    return cleanArray;
	}
	
	function LoadFinished()
	{
	    $("#loader-box").fadeOut();
	    window.log("Map Loaded: True");
	}
	
	String.prototype.stripChars = function()
	{
	    var str = this;
	    var toReplace = ['&','-', '(', ')', / /g, 'underrefurbishment', /[\xC0-\xC2]/g, /[\xE0-\xE2]/g, /[\xC8-\xCA]/g, /[\xE8-\xEB]/g, /[\xCC-\xCE]/g, /[\xEC-\xEE]/g, /[\xD2-\xD4]/g, /[\xF2-\xF4]/g, /[\xD9-\xDB]/g, /[\xF9-\xFB]/g];
	    var replacements = ['','','','','','','A','a','E','e','I','i','O','o','U','u'];
	    
	    for(i=0; i<toReplace.length; i++){
	        str = str.replace(toReplace[i], replacements[i]);
	    }
	    return str;
	}
	
	//debug log
	window.log = function(string)
	{
	    if(typeof console == 'object') console.log(string);
	}
});
