/**
 * HYSMaps, Javascript file
 * 
 * The Have Your Say UGC Map system is a framework for
 * visualising geographically specific user-generated content 
 *
 * @author Rob Stanford <rob.stanford@airlock.com>
 * @version 2.1
 * @copyright Copyright (c) 2008 Airlock Limited <http://www.airlock.com>
 */

/**
 * Main namespace and constants
 */
 
/* IE6 IMAGE CACHING BUG SOLVE */
 try {
  document.execCommand("BackgroundImageCache", false, true);
} catch(err) {}

var HYSMaps = {
	
	browserType: "", // This will be set to the browser type - ie IE6
	
	helperFunctions: {
		removeItemFromArray: function(dataObj) {
			var item = dataObj.item;
			var anArray = dataObj.anArray;
			var returnArray = new Array();
			for (var counter = 0; counter < anArray.length; counter++) {
				if (anArray[counter] != item) {
					returnArray.push(anArray[counter]);	
				}
			}
			return returnArray;
		},
		cloneArray: function(dataObj) {
			var anArray = dataObj.anArray;
			var returnArray = new Array();
			for (var counter = 0; counter < anArray.length; counter++) {
				returnArray.push(anArray[counter]);	
			}
			return returnArray;
		}
	},
	type: {
		road:		1,
		aerial:		2,
		hybrid:		3,
		terrain:	4
	},
	zoom: {
		minimum:	1,
		maximum:	12
	},
	clustering: {
		grid:		50,
		threshold:	3
	},
	defaults: {
		latitude:	51.5001,
		longitude: -0.1262,
		zoom:		8,
		carrierImage: {
			height: 100,
			width: 100,
			padding: 35,
			lipHeight: 8,
			lipOffset: function(dataObj) {
				return -parseInt((dataObj.imgWidth+16)/2);
			}
		},
		nextPrevPanelControls: {
			controlWidth: 88,
			numButtonWidth: 32
		},
		typeIconColours:['green', 'gold', 'blue', 'red', 'purple', 'turquoise', 'yellow', 'mint', 'grey', 'black']
	},
	modes: {
		input:		0,
		output:		1
	},
	filtering: {
		cutoff:		250,
		maximum:	500
	},
	mapDimensions: { // Default map sizes - these will be overridden by the styles set for div#map
		width: 786,
		height: 387
	},
	infoPanelStatus: {
		isAPanelOpen: false	
	},
	currentPanelDensity: 0, // This value will updated with the latest panel density value

	mode:			0,
	
	assets:			'/nol/shared/bsp/hi/have_your_say/maps/airlock/3_0/ui/',
	//assets:			'ui/',
	commentIconUrlTemplate: "icon-type.????.png", // ???? will be replaced with the relevent colour
	
	mapHandler: "", // This will later be set to the maphandler object, providing easy access to this object's methods
	
	commentsArray: "", // This will later be set to an array containing all the comments
	
	limitedCommentsPanelArray: new Array(),

	showCommentLimit: 250,

	totalCommentLimit: 500

};


/**
 * Handler function to setup dom and control input
 */
HYSMaps.MapHandler = function (element) {

	// Provide access to this object and its methods via the HYSMaps namespace
	HYSMaps.mapHandler = this;
	
	// Browser detection
	var isIE = window.ActiveXObject ? true : false; // ActiveX is only used in Internet Explorer
	var isIE6=isIE;
	    
	var isIE7=false;
	if (window.external && (typeof window.XMLHttpRequest == "object")) {
		isIE7=true;
		isIE6=false;
	}

	var isFireFoxMac = false;
	if (navigator.userAgent.indexOf("Firefox")!=-1 && navigator.userAgent.indexOf("Macintosh")!=-1) {
		isFireFoxMac = true;
	}
	


	if (isIE6) {
		HYSMaps.browserType="IE6";	
	}
	else if (isIE7) {
		HYSMaps.browserType="IE7";	
	}
	else if (isFireFoxMac) {
		HYSMaps.browserType="FireFoxMac";	
	}
	else {
		HYSMaps.browserType="Standards";	
	}	



	// Let's store the map dimensions - these are set in the css for the div#map el
	HYSMaps.mapDimensions.width = element.offsetWidth || HYSMaps.mapDimensions.width; 
	HYSMaps.mapDimensions.height = element.offsetHeight || HYSMaps.mapDimensions.height;
	
	// We also, set the height of the div#map to auto
	element.style.height = "auto";
		
	this.dom = {
		
		base: element,
		wrapper: document.createElement('div'),
		map: document.createElement('div')
	};

	this.dom.map.id = 'map-canvas';
	this.dom.map.style.width = '100%';
	this.dom.map.style.height = '100%';
	this.dom.map.style.position = 'relative';
	
	this.dom.wrapper.className = 'map-container';
	
	this.dom.wrapper.style.width = HYSMaps.mapDimensions.width+"px";
	this.dom.wrapper.style.height = HYSMaps.mapDimensions.height+"px";
		
	this.dom.wrapper.appendChild(this.dom.map);
	this.dom.base.appendChild(this.dom.wrapper);
	
	// add unload handler to clean up objects
	window.onunload = this.unload.bind(this, window.onunload);
};

/**
 * Instantiates the input map for locating a user
 */
HYSMaps.MapHandler.prototype.input = function (coords, location, clear, icon) {
	
	this.map = new HYSMaps.InputMap(new HYSMaps.MapFactory(this.dom.map, HYSMaps.modes.input), coords, location, clear, icon);
	this.map.initialise();
	return this.map;
};

/**
 * Instantiates the output map for displaying generated content
 */
HYSMaps.MapHandler.prototype.output = function (input) {
	this.map = new HYSMaps.OutputMap(new HYSMaps.MapFactory(this.dom.map, HYSMaps.modes.output), input, this.dom.base);
	this.map.initialise();
	return this.map;
};

HYSMaps.MapHandler.prototype.unload = function (chain) {
	
	if (this.map) this.map.unload();
	if (chain) chain(); // call any existing unload handlers
};


/**
 * Map Factory class to handle selection of the
 * relevent map abstraction
 */
HYSMaps.MapFactory = function (element, mode) {
	this.dom = element;
	this.dom.className += ' initialised';
	this.mode = mode;
};

HYSMaps.MapFactory.prototype.createMap = function (provider, type, plotterType, showControls, ugc) {
	
	/*var plotter = {} ;
	if (plotterType && plotterType.toLowerCase() == 'clustered'){
		plotter = new HYSMaps.ClusterPlotter();
	} else if (plotterType && plotterType.toLowerCase() == 'input'){
		plotter = new HYSMaps.InputPlotter();
	} else {
		plotter = new HYSMaps.MarkerPlotter();
	}*/
	
	var plotter = (plotterType && plotterType.toLowerCase() == 'clustered') ? new HYSMaps.ClusterPlotter() : (plotterType && plotterType.toLowerCase() == 'input') ? new HYSMaps.InputPlotter() : new HYSMaps.MarkerPlotter() ;
	
	if (!ugc && typeof(HYSMaps.hack_lockzoom) == 'undefined') { 
		// 2009/04/06 - Changelog:
		// Edit: Hieu Luu Danh
		// Summary: added HYSMaps.hack_lockzoom to be able to lock non-ugc maps
		// on a zoom level (see map id 7, about italian earthquake)
		HYSMaps.zoom.minimum = 1;
		HYSMaps.zoom.maximum = 99;
	}
	
	switch (provider.toLowerCase()) {
		
		case 'google':
			var map = new HYSMaps.GoogleMap(plotter);
			break;
			
		case 'microsoft':
			var map = new HYSMaps.MicrosoftMap(plotter);
			break;
	}
	
	HYSMaps.mode = this.mode;
	
	return map.initialise(this.dom, type, showControls);
};


(function () {
	
// bind event handlers with object context
Function.prototype.bind = function (object) {
	
	var method = this;
	var oldArguments = toArray(arguments).slice(1);
	return function (argument) {
		if (argument == Function.prototype.unbind) {
			method = null;
			oldArguments = null;
		} else if (method) {
			var newArguments = toArray(arguments);
			return method.apply(object, oldArguments.concat(newArguments));
		}
	};
};

Function.prototype.unbind = new Object;

// add inheritance
Function.prototype.inherits = function (superclass) { 
	
	var x = function () {}; 
	x.prototype = superclass.prototype; 
	this.prototype = new x(); 
};

function toArray(pseudoArray) {
	
	var result = [];
	for (var i = 0; i < pseudoArray.length; i++) {
		result.push(pseudoArray[i]);
	}
	return result;
};

})();


HYSMaps.isEmpty = function (object) {
	
	for (var i in object) return false;
	return true;
};


HYSMaps.InputParser = function () {};

HYSMaps.InputParser.prototype.parse = function (url, map) {
	
	// do ajax request to post back address
	this.ajax = new XMLHttpRequest();
	this.ajax.open('GET', url + '?' + Math.ceil(1000000 * Math.random()), true);
	this.ajax.onreadystatechange = this.onLoad.bind(this, map);
	this.ajax.send(null);
};

HYSMaps.InputParser.prototype.unescapeHTMLDecode=function(str) 
{
     var div=document.createElement('div');
	div.innerHTML=str;
	//console.log(div.textContent);
	return div.textContent || div.innerText;
};

HYSMaps.InputParser.prototype.onLoad = function (map) {
	
	if (this.ajax.readyState == 4) {

		var data = eval('(' + this.ajax.responseText + ')');
		var result = {
			map: data.map,
			series: {}
		};

		// Save the typeIcon infor somewhere we can access it
		HYSMaps.commentTypeIcons = data.map.typeIcons;
		HYSMaps.commentTypeCounts = data.map.typeCounts;

		for (var i in data.series) {
			
			if (data.series[i].typed) {
				var series = new HYSMaps.TypedSeries();
			} else {
				var series = new HYSMaps.Series();
			}

			var showCommentLimit = HYSMaps.showCommentLimit;
			var totalCommentLimit = HYSMaps.totalCommentLimit;
			var commentCounter = 0;
			
			for (var j = 0; j < data.series[i].points.length; ++j) { // loop through points
				
				if (data.series[i].name == "Comments" && commentCounter++ === totalCommentLimit) {
					break;
				}

				var p = data.series[i].points[j]; // get point
				
				if (commentCounter > showCommentLimit && data.series[i].name == "Comments") {
					p.isLimitedComment = true;
					p.shouldBeShownDespiteLimited = false;
				}

				if (!p) continue;

				// get coordinates
				var split = p.coords.split(',');
				var x = parseFloat(split[1]);
				var y = parseFloat(split[0]);

				map.sizer.isSequenced = data.map.displayNextPrevPanelControls;

				map.sizer._waitingPanels.push(y, x, p, data.series[i].name);
				/*
				map.sizer._waitingPanels is an array to cache arguments for future calls to the
				map.sizer.addPanel method. This intermediate step is necessary since the map has
				not yet been initialised. But for this workaround, the code above is equivalent
				to the following:

				map.sizer.addPanel(y, x, p, data.series[i].name);

				See HYSMaps.OutputMap and HYSMaps.OutputMap.prototype.initMap (output-map.js)
				for the rest of the delayed panel-adding implementation.
				*/

				switch (i) {
					
					case 'comments':
						var point = new HYSMaps.CommentPoint();
						break;
					case 'text':
						var point = new HYSMaps.TextPoint();
						break;
					case 'images':
						var point = new HYSMaps.ImagesPoint();
						break;
					case 'audio':
						var point = new HYSMaps.AudioPoint();
						break;
					case 'video':
						var point = new HYSMaps.VideoPoint();
						break;
				}

				switch (i) {
					
					case 'comments':
						if (!point.initialise(p.date, p.name, this.unescapeHTMLDecode(p.content), p.link, p.alert, new HYSMaps.GeoCoords(y, x), p.type)) {
							continue;
						}
						break;
					case 'text':
					case 'images':
					case 'audio':
					case 'video':
						if (!point.initialise(p.title, p.summary, p.content, p.link, new HYSMaps.GeoCoords(y, x))) {
							continue;
						}
						if (p.icon) {
							point.setIcon(p.icon);
						}
						if (p.inert) {
							point.toggleInteractivity();
						}
						break;
				}

				switch (i) {
					
					case 'images':
					case 'audio':
					case 'video':
						if (p.media) {
							point.addMedia(p.media);
						}
						break;
				}
				
				if (data.series[i].typed) {
					series.addPoint(point, p.typed, data.map.typeIcons);
				} else {
					series.addPoint(point);
				}
			}
			
			if (series.initialise(data.series[i].name, data.series[i].icon, data.series[i].grouped)) {
				result.series[i] = series;
			}
		}

		if (typeof data.series.comments === 'undefined') {
			HYSMaps.zoom.maximum = 30; // must cap this at 30 to avoid GMap errors
		}

		map.onData(result);
	}
};


// create AJAX wrapper for IE
if (typeof XMLHttpRequest == 'undefined') {
	
	XMLHttpRequest = function () {
		
		return new ActiveXObject(
			//IE 5 uses a different XMLHTTP object from IE 6
			navigator.userAgent.indexOf('MSIE 5') >= 0 ? 'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP'
		);
	};
}