/**
 * Google Map Initialisation and Customisation
 * @author George Steel <george@net-glue.co.uk>
 * @copyright Copyright (c) 2010, Net Glue Ltd
 * @license http://opensource.org/licenses/mit-license.php MIT License
 * @version $Id: map.js 381 2010-07-21 16:10:57Z george $
 */

/**
 * Uses Version 3 of the Google Map API
 * http://code.google.com/apis/maps/documentation/javascript/reference.html
 */

function aceMapInit() {
	var map = new ACEMAP();
}



/**
 * Map Instance
 * @var google.maps.Map
 */
function ACEMAP() {
	
	this.map = null;
	
	this.miniMap = null;
	
	/**
	 * URL where to get info on projects and categories
	 * @var string
	 */
	this.projectDataUrl = '/project/ajax-project-info/format/json';
	
	this.initialLatitude = -27.722436;
	this.initialLongitude = 23.906250;
	this.initialZoom = 5;
	
	this.markerShadow = '../images/maps/shadow.png';
	this.basicMarker = '../images/maps/basicMarker.png';
	this.markerDirectory = '../images/maps/markers/';
	this.mapCanvasId = "map_canvas";
	this.miniMapCanvasId = "miniMap";
	this.projects = null;

	this.categories = null;
	
	this.markers = new Object();
	
	this.EXCEPTION_ENCOUNTERED = false;
	
	this.maxLongitude = 'foo';
	this.init();
}

ACEMAP.prototype.init = function() {
	this.loadProjectData();
	this.initMap();
}


ACEMAP.prototype.loadProjectData = function() {
	var info = false;
	$.ajax({
		url: this.projectDataUrl,
		cache: true,
		async: false,
		dataType: 'json',
		error: function(XmlHttpReq, textStatus, error) {
			return false;
		},
		success: function(data, status) {
			info = data;
		}
	});
	if(false == info) {
		this.throwError();
		return false;
	}
	this.setProjectData(info.projects, info.categories);
	return true;
};

ACEMAP.prototype.setProjectData = function(projects, categories) {
	this.projects = projects;
	this.categories = categories;
}

ACEMAP.prototype.throwError = function() {
	alert('Error');
}

ACEMAP.prototype.initMap = function() {
	var initialLatLng = new google.maps.LatLng(this.initialLatitude, this.initialLongitude);
	var acemap = this;
	var myOptions = {
		//zoom: this.initialZoom,
		//center: initialLatLng,
		//mapTypeId: google.maps.MapTypeId.HYBRID,
		disableDefaultUI: true, // Disable Default UI
		navigationControl: true, // The disc with compass click controls and Zoom Bar
		navigationControlOptions: {
			style: google.maps.NavigationControlStyle.SMALL, // Just zoom in/out buttons
			position: google.maps.ControlPosition.TOP_LEFT
		},
		mapTypeControl: false, // We'll add custom map type changers outside map viewport
		scaleControl: false // Shows a scale bar/ruler
	};
	this.map = new google.maps.Map(document.getElementById(this.mapCanvasId), myOptions);
	
	this.miniMap = new google.maps.Map(document.getElementById(this.miniMapCanvasId), {
		disableDefaultUI: true,
		mapTypeId: google.maps.MapTypeId.TERRAIN
	});
	
	google.maps.event.addListener(this.map, 'zoom_changed', function() {
		var newZoom = Math.max(acemap.map.getZoom() -3, 0);
		if(acemap.miniMap.getZoom() != newZoom) acemap.miniMap.setZoom(newZoom);
	});
	google.maps.event.addListener(this.miniMap, 'zoom_changed', function() {
		var newZoom = acemap.miniMap.getZoom() + 3;
		if(acemap.map.getZoom() != newZoom) acemap.map.setZoom(newZoom);
	});
	
	this.miniMap.bindTo('center', this.map, 'center');
	this.map.setZoom(this.initialZoom);
	this.map.setCenter(initialLatLng);
	this.map.setMapTypeId(google.maps.MapTypeId.HYBRID);
	
	var overlay = this.miniMap.getDiv();
	this.map.getDiv().appendChild(overlay);
	overlay.style.position = "absolute";
	overlay.style.right = "0px";
	overlay.style.bottom = "14px";
	overlay.style.zIndex = 10;
	
	google.maps.event.addListener(this.miniMap, 'idle', function() {
		acemap.miniMap.getDiv().style.zIndex = 10;
	});
	
	/**
	 * Discover highest latitude - this will give us the "highest" marker
	 */
	var maxLat = 0;
	var minLat = 0;
	$.each(this.projects, function(key, project) {
		if(project.latitude < minLat) {
			minLat = project.latitude;
		}
	});
	
	var latPlus = Math.abs(minLat);
	$.each(this.projects, function(key, project) {
		project.zIndex = Math.floor(100000 - (1 + (project.latitude + Math.abs(minLat)) * 100.0000));
		if(project.zIndex > maxLat) {
			maxLat = project.zIndex;
		}
	});
	this.maxLatitude = maxLat;
	$.each(this.projects, function(key, project) {
		var markerImage = acemap.markerDirectory + project.id + ".png";
		var marker = acemap.createMarker(markerImage);
		var latLng = new google.maps.LatLng(project.latitude, project.longitude);
		
		marker.setPosition(latLng);
		marker.setTitle(project.name);
		marker.setZIndex(project.zIndex);
		marker.project = project;
		acemap.addMarker(project.categoryId, project.id, marker);
	});
	
	/**
	 * Now all markers have been initially set up, loop over them and add event listeners
	 */
	var catId;
	$.each(this.markers, function(catId, markers) {
		$.each(markers, function(markerId, marker) {
			google.maps.event.addListener(marker, 'mouseover', function() {
				acemap.raiseZIndexOfCategory(catId);
				this.setZIndex( 1 + this.getZIndex()); // Increase zindex 1 more for current hover
				/**
				 * Expand Project Nav on hover
				 */
				var mark = this;
				$('#projectNav a').each(function(index, el) {
					if($(el).attr('href') == mark.project.url) {
						// Find parent : #projectNav > ul li of this el
						$(el).parent('li').parent('ul').slideToggle(0);
					}
				});
			});
			google.maps.event.addListener(marker, 'mouseout', function() {
				acemap.resetZIndex();
				var mark = this;
				/**
				 * Contract Project Nav on mouseout
				 */
				$('#projectNav a').each(function(index, el) {
					if($(el).attr('href') == mark.project.url) {
						// Find parent : #projectNav > ul li of this el
						$(el).parent('li').parent('ul').slideToggle(0);
					}
				});
			});
			google.maps.event.addListener(marker, 'click', function() {
				if(this.project.url) {
					window.location.href = this.project.url;
				}
			});
		});
	});
	
	/**
	 * Loop over project Navigation and add hover to reveal markers
	 * in hovered category - need to use URL to locate appropriate marker
	 */
	$('#projectNav a').hover(function(evt) {
		var link = $(this).attr('href');
		$.each(acemap.markers, function(index, cat) {
			$.each(cat, function(key, marker) {
				if(marker.project.url == link) {
					acemap.raiseZIndexOfCategory(marker.project.categoryId);
					marker.setZIndex( 1 + marker.getZIndex());
					acemap.map.setCenter(marker.getPosition());
				}
			});
		});
	}, function(evt) {
		acemap.resetZIndex();
	});
	
	
}

ACEMAP.prototype.raiseZIndexOfCategory = function(catId) {
	var acemap = this;
	$.each(this.getMarkersInCategory(catId), function(key, marker) {
		marker.setZIndex(acemap.maxLatitude);
	});
}

ACEMAP.prototype.resetZIndex = function() {
	$.each(this.markers, function(catId, markers) {
		$.each(markers, function(markerId, marker) {
			marker.setZIndex(marker.project.zIndex);
		});
	});
}

ACEMAP.prototype.getMarkersInCategory = function(catId) {
	return this.markers[catId];
}

ACEMAP.prototype.addMarker = function(categoryId, projectId, marker) {
	if(!this.markers[categoryId]) {
		this.markers[categoryId] = new Object();
	}
	this.markers[categoryId][projectId] = marker;
}



/**
 * @return google.maps.Marker
 */
ACEMAP.prototype.createMarker = function(imageUrl) {
	var image = new google.maps.MarkerImage(
		imageUrl,
		new google.maps.Size(74, 83), // Size
		new google.maps.Point(0,0), // Origin
		new google.maps.Point(37, 83) // Anchor
	);
	
	var shadow = new google.maps.MarkerImage(
		this.markerShadow,
		new google.maps.Size(183, 83), // Size
		new google.maps.Point(0,0), // Origin
		new google.maps.Point(37, 83) // Anchor
	);
	
	var shape = {
		coord: [0,0, 0,53, 23,53, 37,83, 51,53, 74,53, 74,0, 0],
		type: 'poly'
	};
	
	var marker = new google.maps.Marker({
		map: this.map,
		shadow: shadow,
		icon: image,
		shape: shape
	});
	return marker;
}


/**
 * Information I need to create each marker
 * Category: so we can show and hide all markers in relevant category
 * Project: so we can display appropropriate information
 * Project Name
 * URL
 * Short Description
 * Project Lat and Lng
 */
