// =============================================
// =============================================
// =====================================================
// CONSTRUCTOR
NearestPointContainer = function(pSize){
	this.points = [];
	this.size = pSize;
	this.furthest = 0;
	this.nearest = 0;
};

NearestPointContainer.prototype.reset = function(){
	this.points = []
	this.furthest = 0;
	this.nearest = 0;
};

NearestPointContainer.prototype.getNearestDist = function(){
	return this.nearest;
};

NearestPointContainer.prototype.test = function(pDist, pData){
	
	
	var dataItem = {dist:pDist, data:pData};
	
	if(this.points.length && (dataItem.dist <= this.furthest)){
		// item needs to be added to our array... but we need to find out where...
		for(var i=0; i<this.points.length; i++){
			if(this.points[i].dist > dataItem.dist){
				this.points.splice(i, 0, dataItem);
				break;
			}
		}
	}else if(!this.points.length){
		// nothing in our array... so we are safe to add this...
		this.points.push(dataItem);
	}
	
	// remove end items if our array is now too large
	while(this.points.length > this.size){
		this.points.splice(this.size, 1);
	}
	
	if(this.points.length){
		this.furthest = this.points[this.points.length-1].dist;
		this.nearest = this.points[0].dist;
	}
	
};

NearestPointContainer.prototype.get = function(){
	return this.points;
};

// =============================================
// =============================================
// =====================================================
// map parameters
var map = null; // map reference in a global scope
var geo = null; // Google Maps Client Geocoder
var localSearch = null; // Google Local Search
var mgr = null; // reference to our marker manager in global scope
var home = {x:52.8691, y:-1.8457}; // long & lat for England
var minZoom = 6;
var maxZoom = 15;
var gridSize = 50;
var startZoom = 6; // start point for zoom
var searchZoom = 11; // amount to zoom to after a search
var markerCutOffZoom = 8; // zoom level at which markers are displayed
var DOMContainer = "#map"; // DOM object into which the map gets loaded
var GMarkers = []; // array of markers in use on the map at any moment in time
var data = []; // container for our data to use on the map
var subData = []; // container for our filtered data to use on the map
var geoStatusCode = []; // status code array
var nearestSearchResults = []; 
var searchResults = [];
var searchForm = null;
var showingSearchResult = false;
var infoWindowMarkerID = 0; // data ID of currently displayed info marker.
var regionalPoints = []; // array of regional markers to be used when the map is zoomed out past the markerCutOffZoom point
var regionalMarker = null;
var officeMarker = null;
var searchMode = "NEAR"; // NEAR | RADIUS
var showImages = true; // flag that turns office images on an off
var mc = null;
var markers = [];
var whichIcon = null; //which icon we use to show our maker
// object used to manage the nearest points following a geo search
var NearestPoints = new NearestPointContainer(20);

var ajaxPath = "/ajax/dignityPledge/";


// initialise the map
function loadMap(){
	if(GBrowserIsCompatible()){
		
		searchForm = document.searchForm; // get our search form
		
		// define map in DOM
		map = new GMap2($(DOMContainer).get(0));
		
		//add zoom control 
		map.addControl(new GLargeMapControl());

		map.setCenter(new GLatLng(home.x, home.y), startZoom);
		
		loadMarkerData();
		
		//=============================================
		// initiate our Geocoder
		geo = new GClientGeocoder(); 
		
		// Array for decoding the failure codes ======
		geoStatusCode[G_GEO_SUCCESS]            = "Success";
		geoStatusCode[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
		geoStatusCode[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
		geoStatusCode[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
		geoStatusCode[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
		geoStatusCode[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
		geoStatusCode[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";
		//=============================================
		
		
		//=============================================
		//marker icons create our 5 different marker icons
		pledgeIcon = new GIcon(G_DEFAULT_ICON);
		pledgeIcon.image = "/graphics/dignityPledge/icon_pledge.gif";
		pledgeIcon.iconSize = new GSize(21, 21);
		pledgeIcon.iconAnchor = new GPoint(9, 26);
		pledgeIcon.infoWindowAnchor = new GPoint(9, 8);
		//pledgeIcon.shadowSize = new GSize(37, 26);
		pledgeIcon.shadow = null; //no shadow required
		
		pledgeNeedHelpIcon = new GIcon(G_DEFAULT_ICON);
		pledgeNeedHelpIcon.image = "/graphics/dignityPledge/icon_pledgeNeedHelp.gif";
		pledgeNeedHelpIcon.iconSize = new GSize(21, 21);
		pledgeNeedHelpIcon.iconAnchor = new GPoint(9, 26);
		pledgeNeedHelpIcon.infoWindowAnchor = new GPoint(9, 8);
		//pledgeNeedHelpIcon.shadowSize = new GSize(60, 26);
		pledgeNeedHelpIcon.shadow = null; //no shadow required
		
		pledgeNoNeedHelpIcon = new GIcon(G_DEFAULT_ICON);
		pledgeNoNeedHelpIcon.image = "/graphics/dignityPledge/icon_pledge.gif";
		pledgeNoNeedHelpIcon.iconSize = new GSize(21, 21);
		pledgeNoNeedHelpIcon.iconAnchor = new GPoint(9, 26);
		pledgeNoNeedHelpIcon.infoWindowAnchor = new GPoint(9, 8);
		//pledgeNoNeedHelpIcon.shadowSize = new GSize(60, 26);
		pledgeNoNeedHelpIcon.shadow = null; //no shadow required
		
		activityIcon = new GIcon(G_DEFAULT_ICON);
		activityIcon.image = "/graphics/dignityPledge/icon_activity.gif";
		activityIcon.iconSize = new GSize(21, 21);
		activityIcon.iconAnchor = new GPoint(9, 26);
		activityIcon.infoWindowAnchor = new GPoint(9, 8);
		//activityIcon.shadowSize = new GSize(37, 26);
		activityIcon.shadow = null; //no shadow required
		
		activityNeedHelpIcon = new GIcon(G_DEFAULT_ICON);
		activityNeedHelpIcon.image = "/graphics/dignityPledge/icon_activityNeedHelp.gif";
		activityNeedHelpIcon.iconSize = new GSize(21, 21);
		activityNeedHelpIcon.iconAnchor = new GPoint(9, 26);
		activityNeedHelpIcon.infoWindowAnchor = new GPoint(9, 8);
		//activityNeedHelpIcon.shadowSize = new GSize(37, 26);
		activityNeedHelpIcon.shadow = null; //no shadow required
		
		/*
		activityWillHelpIcon = new GIcon(G_DEFAULT_ICON);
		activityWillHelpIcon.image = "/graphics/dignityPledge/icon_activityNeedHelp.gif";
		activityWillHelpIcon.iconSize = new GSize(21, 21);
		activityWillHelpIcon.iconAnchor = new GPoint(9, 26);
		activityWillHelpIcon.infoWindowAnchor = new GPoint(9, 8);
		//activityWillHelpIcon.shadowSize = new GSize(37, 26);
		activityWillHelpIcon.shadow = null; //no shadow required*/
		
		//add marker to our markers array
		for(var i in data){
		
			var m = data[i];
			var mPoint = new GLatLng(m.lat, m.long);
			
			//pass in our user count
			var marker = createMarker(mPoint, buildMarkerHTML(m), m.ID, m.isPledge, m.isHelpNeeded, m.willHelp);
			
			addMarker(marker);
		}
		
		drawSidePanel(data, "20 Nearest Pledges or Events");
		
	}
}


// =============================================
// =============================================
// =====================================================
// DATA

function addData(pLat, pLong, pTitle, pID, pIsPledge, pIsHelpNeeded, pWillHelp, pUserFullName, pPledgeDate){
	
	// define data object
	//user count, how many users are at the same longitude and latitude place
	var o = {long:pLong, lat:pLat, title:pTitle, ID:pID, isPledge:pIsPledge, isHelpNeeded:pIsHelpNeeded, willHelp:pWillHelp, userFullName:pUserFullName, pledgeDate:pPledgeDate };
	//data.push(o);
	data["ID_" + pID] = o;
	//alert(pID);
}

function getDataByID(pID){
	return data["ID_" + pID];
}


function buildMarkerHTML(pData){
	var html = "<div class=\"markerPledgeWrapper\">";
	
	html += buildSummaryHTML(pData);
	
	html += "<a href=\"\" onclick=\"viewMoreDetails("+ pData.ID + "); return false\"><strong>More information<\/strong></a>";
	html += "<\/div>";
	return html
}

function buildSummaryHTML(pData){
	var html = "";
	if(pData.title.length){html += "<strong class=\"markerPledgeTitle\">" + pData.title + "<\/strong><br \/>";}
	if(pData.userFullName.length){html += pData.userFullName + "<br \/>";}
	return html
}

//get pledge details in a modal window
function viewMoreDetails(pledgeID){
	
	var pledgeDetailsPath = ajaxPath + "pledgeDetails.cfm";
	
	$.get(pledgeDetailsPath, {pledgeID:pledgeID}, function(data){
		
		if(data.length){
			$.modal(data,{position: ["25%","25%"]});
		}else{
			alert("Pledge or event detail is not available at the moment");
		}
	});
}


// ============================================================
// SEARCH FORM AND GEO CODING
// ============================================================

function search(){
	var didYouMeanHTML = "";
	
	if(searchForm){
		
		//are we search pledge or activities, or both
		//alert(searchForm.event.checked);
		
		var searchCondition = "";
		
		if(searchForm.activity.checked == true ){
			searchCondition = "m.isPledge == false";
		}
		if(searchForm.pledge.checked == true){
			searchCondition = "m.isPledge == true";
		}
		if((searchForm.activity.checked == true && searchForm.pledge.checked == true ) || (searchForm.activity.checked == false && searchForm.pledge.checked == false) ){
			searchCondition = "";
		}
		
		if(searchForm.volunteersRequired.checked == true && searchForm.volunteersNotRequired.checked == false){
			if(searchCondition.length > 0){
				searchCondition = searchCondition + " && ";
			}
			searchCondition = searchCondition + "m.isHelpNeeded == true";
		}
		
		if(searchForm.volunteersRequired.checked == false && searchForm.volunteersNotRequired.checked == true){
			if(searchCondition.length > 0){
				searchCondition = searchCondition + " && ";
			}
			searchCondition = searchCondition + "m.isHelpNeeded == false";
		}
		
		if(searchForm.peopleVolunteering.checked == true){
			if(searchCondition.length > 0){
				searchCondition = searchCondition + " && ";
			}
			searchCondition = searchCondition + "m.willHelp == true";
		}
		
		
		//clear our markers, then re set based on our search criteria
		clearMarkers();
		
		//set our counter to count how many result we need to show
		
		var resultCounter = 0;
		var resultLimit = 0;
		
		if(searchForm.latest20.checked){
			resultLimit = 20;
		}
		
		// loop through all our data to filter
		//empty our subdata first
		
		subData = [];
		
		for(var i in data){
			var m = data[i];
			
			resultCounter = resultCounter + 1;
			
			
			//if no result limit, we show all, or if with result limit, we only show top result limit amount
			if((resultLimit == 0) || (resultLimit > 0 && resultCounter <= resultLimit)){
				if(m.ID){ // check for our object as IE include additional properties here...
			
					//get search condition, only show what searched then

					if(searchCondition.length > 0){
						if(eval(searchCondition)){
							subData["ID_" + m.ID] = m;
						}
					}else{
						subData["ID_" + m.ID] = m;
					}
					
					
					
				}
			}
			
		}
		
		
		// did user search town or postcode
		if(searchForm.address.value.length){
			// NOTE: searches include 'UK' by default to force results to the UK
			geo.getLocations(searchForm.address.value + ",UK", function(result){
				if(result.Status.code == G_GEO_SUCCESS){
					showingSearchResult = true;
					if(result.Placemark.length > 1){
						// multiple results - ask user to select an address
						//document.getElementById("mapMsg").innerHTML = "Did you mean:";
						//didYouMeanHTML = "Did you mean:";
						didYouMeanHTML = "<ol>";
						// Loop through the results
						for(var i=0; i<result.Placemark.length; i++){
							var p = result.Placemark[i].Point.coordinates;
							didYouMeanHTML += "<li><a href='javascript:findNearestPoint(" +p[1]+","+p[0]+");$.modal.close();'>"+ result.Placemark[i].address+"<\/a><\/li>";
						}
						didYouMeanHTML += "<\/ol>";
						$.modal(didYouMeanHTML, {position: ["25%","25%"]});
					}else{
						// single result - go straight to it
						//document.getElementById("mapMsg").innerHTML = "";
						//$("mapMsg").innerHTML = "";
						var p = result.Placemark[0].Point.coordinates;
						
						findNearestPoint(p[1],p[0],true);
					}
				}else{
					// error with search - inform user
					var reason = "Code " + result.Status.code;
					if (geoStatusCode[result.Status.code]) {
						reason = geoStatusCode[result.Status.code]
					} 
					alert("Could not find '" + searchForm.address.value + "'\r\n" + reason);
				}
			});
		}else{
				
				map.setCenter(new GLatLng(home.x, home.y), startZoom);
				
				for(var i in subData){
		
					var m = subData[i];
					var mPoint = new GLatLng(m.lat, m.long);
					
					
					//pass in our user count
					var marker = createMarker(mPoint, buildMarkerHTML(m), m.ID, m.isPledge, m.isHelpNeeded, m.willHelp);
					
					addMarker(marker);
				}
		
				drawSidePanel(subData, "20 Nearest Pledges or Events Matching search criteria");
		}
		
	}
}


function getSearchRadius(){
	return 10; //10 km
}

// search for markers near a given point
function findNearest(point,isSubData){

	
	
	var r = getSearchRadius(); //we can have a default value for this, as user doesn't have an option to choose the radius

	NearestPoints.reset(); // reset our nearest point object
	
	//map.clearOverlays(); // clear all existing markers from the map
	clearMarkers();
	
	if(isSubData){
		//using our subdata
		for(var i in subData){
			var m = subData[i];
			//alert(m);
			
			if(m.ID){ // check for our object as IE include additional properties here...
				var mPoint = new GLatLng(m.lat, m.long);
				
				var d = point.distanceFrom(mPoint)/1000; // calculate the distance from our given point
				
				//alert("A: " + m);
				NearestPoints.test(d, m); // log this with our nearest point object
				
				// if our dispance is within our search radius, we create a marker
				if((searchMode == "RADIUS") && (d<=r)){
					// create and display a marker
					var marker = createMarker(mPoint, buildMarkerHTML(m), m.ID, m.isPledge, m.isHelpNeeded, m.willHelp);
					//map.addOverlay(marker);
					addMarker(marker);
				}
			}
		}

	}else{
		for(var i in data){
			var m = data[i];
			//alert(m);
			
			if(m.ID){ // check for our object as IE include additional properties here...
				var mPoint = new GLatLng(m.lat, m.long);
				
				var d = point.distanceFrom(mPoint)/1000; // calculate the distance from our given point
				
				//alert("A: " + m);
				NearestPoints.test(d, m); // log this with our nearest point object
				
				// if our dispance is within our search radius, we create a marker
				if((searchMode == "RADIUS") && (d<=r)){
					// create and display a marker
					var marker = createMarker(mPoint, buildMarkerHTML(m), m.ID, m.isPledge, m.isHelpNeeded, m.willHelp);
					//map.addOverlay(marker);
					addMarker(marker);
				}
			}
		}
		
	}
	
	// loop through all our data
	//for(var i=0; i<data.length; i++) {
	
	
	if(searchMode == "NEAR"){
		showNearestMarkers();
	}
	//drawSidePanel();
	
}


function findNearestPoint(lat, lng,isSubData){
	var point = new GLatLng(lat, lng);
	map.setCenter(point, searchZoom);
	findNearest(point,isSubData);
	//$("mapMsg").innerHTML = "";
}


function showNearestMarkers(){
	var aNearest = NearestPoints.get();
	
	for(var i=0; i<aNearest.length; i++){
		var m = aNearest[i].data;
		var mPoint = new GLatLng(m.lat, m.long);
		// create and display a marker
		var marker = createMarker(mPoint, buildMarkerHTML(m), m.ID, m.isPledge, m.isHelpNeeded, m.willHelp);
		addMarker(marker);
	}
	
	drawSidePanelNearest(NearestPoints.get(), "Nearest Pledges or Events");
}


// ============================================================
// MARKERS
// ============================================================

function createMarker(point, html, id, isPledge, isHelpNeeded, willHelp) {
	//we present the marker with differentlly
	//m.isPledge, m.isHelpNeeded, m.willHelp
	
	if(isPledge == true){
		if(isHelpNeeded == ""){
			whichIcon = pledgeIcon;
		}
		if(isHelpNeeded == true){
			whichIcon = pledgeNeedHelpIcon;
		}
		if(isHelpNeeded == false){
			whichIcon = pledgeIcon;
		}
	}else{
		if(isHelpNeeded == ""){
			whichIcon = activityIcon;
		}
		if(isHelpNeeded == true){
			whichIcon = activityNeedHelpIcon;
		}
		if(isHelpNeeded == false){
			whichIcon = activityIcon;
		}
	}
	
	var marker = new GMarker(point, {icon:whichIcon});
	marker.MYid = id;
	GEvent.addListener(marker, "click", function() {
		marker.openInfoWindowHtml(html);
		infoWindowMarkerID = marker.MYid;
	});
	return marker;
}

// ======================================
// keep track of our markers...
function addMarker(m){
	map.addOverlay(m);
	GMarkers.push(m); // add reference to marker
}

function removeMarker(m){
	// find our marker in our reference array and remove it
	for(var i=0; i<GMarkers.length; i++){
		if(GMarkers[i] == m){
			GMarkers.splice(i, 1);
			break;
		}
	}
	map.removeOverlay(m);
}

function clearMarkers(){
	map.clearOverlays(); // clear all existing markers from the map
	GMarkers = []; // clear our reference array
}

function getMarkerByID(pID){
	// search through our visible markers to look for a given ID 
	for(var i=0; i<GMarkers.length; i++){
		if(GMarkers[i].MYid == pID){
			return GMarkers[i];
		}
	}
	return null;
}

// bring up our marker and marker label
function togglePledge(pID){
	var marker = getMarkerByID(pID);
	var mPoint = null;
	var d = null;
	
	if(!marker){
		// marker not found...
		var d = getDataByID(pID);
		if(d){
			mPoint = new GLatLng(d.lat, d.long);
			// create and display a marker
			marker = createMarker(mPoint, buildMarkerHTML(d), d.ID);					
			//map.addOverlay(marker);
			addMarker(marker);
		}
	}
	
	if(marker){
		GEvent.trigger(marker, "click");
	}
}

// ============================================================
// SIDE PANEL
// ============================================================

// populates our side panel with our 'nearest' search results, 
// this function process our pledge data object directly
function drawSidePanel(pData, pTitle){

	//var aNearest = NearestPoints.get();
	var html = "<div class=\"searchResults\">";
	//var html = "<div class=\"searchResults\"><h2>" + pTitle + "<\/h2>";
	var itemDist = null;
	var m = {};
	
	for(var i in pData){
	
		var m = pData[i];
		
		if(m.isPledge == true && m.isHelpNeeded == false){
			html += "<p class=\"pledgeIcon\">";
		}
		if(m.isPledge == true && m.isHelpNeeded == true){
			html += "<p class=\"pledgeNeedHelpIcon\">";
		}
		if(m.isPledge == false && m.isHelpNeeded == false){
			html += "<p class=\"activityIcon\">";
		}
		if(m.isPledge == false && m.isHelpNeeded == true){
			html += "<p class=\"activityNeedHelpIcon\">";
		}
		
		html += "<strong class=\"title\"><a href=\"javascript:void(0);\" onclick=\"togglePledge(" + m.ID + ");\">" + m.title + "<\/a><\/strong><br \/>";
		
		if(m.isPledge == false){
			html +=  m.pledgeDate + " - ";
		}
		
		html += m.userFullName;
		html += "<\/p>";
		
	}
	
	html += "<\/div>";
	
	$("#mapSide").scrollTop = 0;
	$("#mapSide").html(html);
	// ======================
}


//this function for processing data from nearestPoints object
function drawSidePanelNearest(pData, pTitle){
	
	
	//var aNearest = NearestPoints.get();
	//var html = "<div class=\"searchResults\"><h2>" + pTitle + "<\/h2>";
	var html = "<div class=\"searchResults\">";
	var itemDist = null;
	var itemData = {};
	
	for(var i=0; i<pData.length; i++){
		if(pData[i].dist){
			itemDist = pData[i].dist
		}else{
			itemDist = null;
		}
		if(pData[i].data){
			itemData = pData[i].data;
		}else{
			itemData = pData[i];
		}
			
		if(itemData.isPledge == true && itemData.isHelpNeeded == false){
			html += "<p class=\"pledgeIcon\">";
		}
		if(itemData.isPledge == true && itemData.isHelpNeeded == true){
			html += "<p class=\"pledgeNeedHelpIcon\">";
		}
		if(itemData.isPledge == false && itemData.isHelpNeeded == false){
			html += "<p class=\"activityIcon\">";
		}
		if(itemData.isPledge == false && itemData.isHelpNeeded == true){
			html += "<p class=\"activityNeedHelpIcon\">";
		}
		
		html += "<strong class=\"title\"><a href=\"javascript:void(0);\" onclick=\"togglePledge(" + itemData.ID + ");\">" + itemData.title + "<\/a><\/strong>";
		
		html += "<span class=\"distMarker\"> - ";
		if(itemDist){
			html += Math.round(itemDist * 10)/10 + "km";
		}
		html += "<\/span><br \/>";
		
		if(itemData.isPledge == false){
			html +=  itemData.pledgeDate + " - ";
		}
		html += itemData.userFullName;
		html += "<\/p>";
	}
	html += "<\/div>";
	$("#mapSide").scrollTop = 0;
	$("#mapSide").html(html);
	// ======================
}

