HYSMaps.GeoCoords = function (latitude, longitude) {
	
	this.latitude = latitude;
	this.longitude = longitude;
};


HYSMaps.GeoCoords.prototype.calculateVectorDistance = function (coords, wrapLatitude, wrapLongitude) {
	
	var result = {};
	
	for (var i = 0; i < 2; ++i) {
		
		var direction = i ? 'latitude' : 'longitude';
		var length = i ? 'y' : 'x';
		var noWrap = i ? wrapLatitude === false : wrapLongitude === false;
		var distance1 = Math.abs(this[direction] - coords[direction]);
		var distance2 = Math.abs(distance1 - 360);
		result[length] = (distance1 < distance2 || noWrap) ? distance1 : distance2;
	}
	
	return result;
};

HYSMaps.GeoCoords.prototype.flip = function () {
	
	return new HYSMaps.GeoCoords(Math.abs(this.latitude - 360), Math.abs(this.longitude - 360));
};

HYSMaps.GeoCoords.prototype.toString = function () {
	
	return this.latitude + ',' + this.longitude;
};


HYSMaps.ScreenCoords = function (x, y) {
	
	this.x = x;
	this.y = y;
};


HYSMaps.Dimensions = function (width, height) {
	
	this.width = width;
	this.height = height;
};


HYSMaps.Bounds = function (nw, se) {
	
	this.nw = nw;
	this.se = se
};

HYSMaps.Bounds.prototype.contains = function (coords, extent) {
	
	var latitudinallyBounded = true;
	var longitudinallyBounded = true;
	
	if (extent == undefined || extent == 'latitude') {
		
		// check if point is south of north boundary
		var isSoutherly = (coords.latitude <= this.nw.latitude);
		// check if point is north of south boundary 
		var isNortherly = (coords.latitude >= this.se.latitude);
		// check if point is within latitude bounds (flipping logic if bounds wrap the equator)
		latitudinallyBounded = this.nw.latitude < this.se.latitude ? isSoutherly || isNortherly : isSoutherly && isNortherly;
	}
	if (extent == undefined || extent == 'longitude') {
		
		// check if point is east of west boundary
		var isEasterly = (coords.longitude >= this.nw.longitude);
		// check if point is west of east boundary
		var isWesterly = (coords.longitude <= this.se.longitude);
		// check if point is within longitude bounds (flipping logic if bounds wrap the prime meridian)
		longitudinallyBounded = this.nw.longitude > this.se.longitude ? isEasterly || isWesterly : isEasterly && isWesterly;
	}
	
	return latitudinallyBounded && longitudinallyBounded;
};

HYSMaps.Bounds.prototype.extend = function (coords) {
	
	if (!this.nw) {
		this.nw = new HYSMaps.GeoCoords(coords.latitude, coords.longitude);
		return;
	}
	
	if (!this.se) {
		this.se = new HYSMaps.GeoCoords(coords.latitude, coords.longitude);
		return;
	}
	
	var latitudinallyBounded = this.contains(coords, 'latitude');
	var longitudinallyBounded = this.contains(coords, 'longitude');
	if (latitudinallyBounded && longitudinallyBounded) {
		return;
	}
	
	var nwExtend = this.nw.calculateVectorDistance(coords);
	var seExtend = this.se.calculateVectorDistance(coords);
	
	// latitude
	if (!latitudinallyBounded) {
		var target = nwExtend.y < seExtend.y ? this.nw : this.se;
		target.latitude = coords.latitude;
	}
	
	// longitude
	if (!longitudinallyBounded) {
		var target = nwExtend.x < seExtend.x ? this.nw : this.se;
		target.longitude = coords.longitude;
	}
};

HYSMaps.Bounds.prototype.get = function () {
	
	if (!this.nw) return false;
	if (!this.se) return { nw: this.nw, se: this.nw };
	else return { nw: this.nw, se: this.se };
};


HYSMaps.Series = function () {
	this.active = true; // toggle on/off
	this.points = []; // the point objects
};

HYSMaps.Series.prototype.addPoint = function (point) {
	
	this.points.push(point);
};

HYSMaps.Series.prototype.initialise = function (name, image, grouped) { // to be called after adding points
	
	if (!name || !image || !this.points.length) return false; // validate
	
	this.name = name; // display name
	this.grouped = grouped; // grouping technique flag
	this.icon = new HYSMaps.Icon(image); //  series icon
	return true;
};

HYSMaps.Series.prototype.initMap = function (map) {
	
	map.addControl(this, this.name, this.icon);
};

HYSMaps.Series.prototype.updatePoints = function (map) {

	for (var i = 0, c = this.points.length; i < c; ++i) {
		this.points[i].plot(map, this.icon, this.active, this.grouped);
	}
};

HYSMaps.Series.prototype.toggle = function () {
	
	this.active = !this.active;
};


HYSMaps.TypedSeries = function () {
	
	HYSMaps.Series.call(this);
	this.types = {}; // array of point types
	this.filtering = true;
};
HYSMaps.TypedSeries.inherits(HYSMaps.Series);

HYSMaps.TypedSeries.prototype.addPoint = function (point, type, icons) {
	
	HYSMaps.Series.prototype.addPoint.call(this, point);
	
	if (type && !(type in this.types)) {
		this.types[type] = new HYSMaps.Type(type, 'icon-type.' + icons[type] + '.gif');
	}
};

HYSMaps.TypedSeries.prototype.initMap = function (map) {
	
	HYSMaps.Series.prototype.initMap.call(this, map);
	
	map.addDateFilter(this, HYSMaps.filtering.cutoff, '', '', true);
	map.addDateFilter(this, HYSMaps.filtering.maximum, "May slow your computer down");
	
	var indices = [];
	for (var i in this.types) {
		indices.push(i);
	}
	indices.sort();
	for (var i = 0; i < indices.length; ++i) {
		//this.types[indices[i]].icon = new HYSMaps.TypeIcon();
		map.addType(this, indices[i], this.types[indices[i]].icon);
	}
};

HYSMaps.TypedSeries.prototype.toggleType = function (type) {
	
	this.types[type].active = !this.types[type].active;
};

HYSMaps.TypedSeries.prototype.toggleFiltering = function (limit) {
	
	this.filtering = limit;
};

HYSMaps.TypedSeries.prototype.updatePoints = function (map) {
	
	var filter = {};
	for (var i in this.types) {
		if (this.types[i].active) filter[i] = this.types[i];
	}

	for (var i = 0; i < this.points.length; ++i) {

		if (this.filtering && i > this.filtering) break;
		this.points[i].plot(map, this.icon, this.active, this.grouped, filter);
	}
};


HYSMaps.Type = function (name, icon) {
	
	this.name = name;
	this.active = true;
	
	this.icon = new HYSMaps.TypeIcon(icon);
};


HYSMaps.Point = function () {};

HYSMaps.Point.prototype.initialise = function (title, summary, content, link, coords) {
	
	this.title = title;
	this.summary = summary;
	this.content = content;
	this.link = link;
	this.coords = coords;
	this.interactive = true;
	
	return !(isNaN(this.coords.longitude) || isNaN(this.coords.latitude)); // validate
};

HYSMaps.Point.prototype.setIcon = function (icon) {
	
	this.icon = icon;
};

HYSMaps.Point.prototype.toggleInteractivity = function () {
	
	this.interactive = ! this.interactive;
};

HYSMaps.Point.prototype.plot = function (map, icon, active, grouped) {
	
	if (active) map.addPoint(this, this.coords, icon, this.date, grouped);
};


HYSMaps.CommentPoint = function () {};
HYSMaps.CommentPoint.inherits(HYSMaps.Point);

HYSMaps.CommentPoint.prototype.initialise = function (date, name, content, link, alert, coords, type) {
	
	this.date = date;
	this.alert = alert;
	this.type = type;
	
	if (type == 'null') return false;
	
	return HYSMaps.Point.prototype.initialise.call(this, name, null, content, link, coords, null, true);
};

HYSMaps.CommentPoint.prototype.plot = function (map, icon, active, grouped, filter) {
	
	if (active && HYSMaps.isEmpty(filter)) {
		map.addPoint(this, this.coords, icon, this.date, grouped);
	}
	else if (active && !HYSMaps.isEmpty(filter) && this.type in filter) {
		map.addPoint(this, this.coords, filter[this.type].icon, this.date, grouped);
	}
};

HYSMaps.CommentPoint.prototype.makeClickEvent = function (element, content) {
	
	return new HYSMaps.CommentClick(element, content, this);
};


HYSMaps.TextPoint = function () {};
HYSMaps.TextPoint.inherits(HYSMaps.Point);

HYSMaps.TextPoint.prototype.makeClickEvent = function (element, content) {
	
	return new HYSMaps.TextClick(element, content, this);
};


HYSMaps.ImagesPoint = function () {};
HYSMaps.ImagesPoint.inherits(HYSMaps.Point);

HYSMaps.ImagesPoint.prototype.addMedia = function (media) {
	
	this.images = media.images;
};

HYSMaps.ImagesPoint.prototype.makeClickEvent = function (element, content) {
	
	return new HYSMaps.ImagesClick(element, content, this);
};


HYSMaps.AudioPoint = function () {};
HYSMaps.AudioPoint.inherits(HYSMaps.Point);

HYSMaps.AudioPoint.prototype.addMedia = function (media) {
	
	this.audio = media.audio;
};

HYSMaps.AudioPoint.prototype.makeClickEvent = function (element, content) {
	
	return new HYSMaps.AudioClick(element, content, this);
};


HYSMaps.VideoPoint = function () {};
HYSMaps.VideoPoint.inherits(HYSMaps.Point);

HYSMaps.VideoPoint.prototype.addMedia = function (media) {
	
	this.video = media.video;
};

HYSMaps.VideoPoint.prototype.makeClickEvent = function (element, content) {
	
	return new HYSMaps.VideoClick(element, content, this);
};


HYSMaps.CloseClick = function (output, content, data) {
	
	this.action = function () {
		output.style.display = 'none';
		return false;
	};
};


HYSMaps.CommentClick = function (output, content, data) {
	
	this.action = function () {

		var html = '<h3 class="hd map-title">User comment</h3>';
		html += '<h2 class="map-heading">' + data.name + '</h2>';
		if (data.date) {
			html += '<h4 class="map-date">' + data.date + '</h4>';
		}
		
		html += '<div class="map-content-holder">';
		html += '<div class="map-content-report"><p>' + data.content + '</p></div>';
		html += '</div>';
		if(data.link || data.alert) {
			html += '<div class="map-footer ft">';
			if (data.link) {
				html += '<p class="map-link"><a href="'+data.link+'">More on this discussion</a></p>';
			}
			if (data.alert) {
				html += '<p class="map-link"><a href="'+data.alert+'">Alert a moderator</a></p>';
			}
			html += '</div>';
		}
		content.innerHTML = html;
				
		//output.style.display = 'block';
		HYSMaps.createCustomInfoPanel({content: content, height: 307, extraClass: "cgpm-comment"} );

	};
};

HYSMaps.AudioClick = function (output, content, data) {
	
	this.action = function () {

		if (!data.interactive) {
			return false;
		}
	
		var specialBBCEdition = (window.airlock && window.airlock.edition) ? window.airlock.edition : ""; 
	
		var thumbImage = data.media.thumb || "";
		thumbImage = (!thumbImage && data.media.images && data.media.images[0]) ? data.media.images[0].image : thumbImage;  

		var thisAudio = (data.media.audio && data.media.audio[0]) ? data.media.audio[0].audio : "";
		var hasImage = false;
		var html = '<h3 class="hd map-title">' + data.title + '</h3>';
		
		html += '<div class="map-content-holder">';
		if (data.media.images && data.media.images[0]) {
			var hasImage = true;
			html += '<div class="map-content-report">';
			if (thumbImage) {
				html+='<div class="au-p-thumb-holder"><img src="'+thumbImage+'" alt="'+data.title+'" /></div>';
			}
			html+='<p class="au-p-summary">'+(data.media.audio[0].caption || data.summary)+'</p>';
			html += '</div>';
		}

		html += '<div id="emp">';
		html += '<object id="bbc_emp_fmtj_embed_obj" width="286" height="106" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">';
		html += '<param value="http://news.bbc.co.uk/player/emp/2_6_5222/player.swf" name="movie"/>';
		html += '<param value="default" name="wmode"/>';
		html += '<param value="true" name="allowFullScreen"/>';
		html += '<param value="embeddedPlayer" name="name"/>';
		html += '<param value="config=http://news.bbc.co.uk/player/emp/config/default.xml&companionSize=300x30&companionType=adi&preroll=&config_settings_autoPlay=false&playlist=' + thisAudio + '&config_plugin_fmtjLiveStats_pageType=eav2&embedReferer=&config_plugin_fmtjLiveStats_edition='+specialBBCEdition+'&embedPageUrl=/1/hi/world/americas/7351742.stm&" name="flashvars"/>';
		html += '<embed id="bbc_emp_fmtj_embed_emb" width="286" height="106" flashvars="config=http://news.bbc.co.uk/player/emp/config/default.xml&companionSize=300x30&companionType=adi&preroll=&config_settings_autoPlay=false&playlist=' + thisAudio + '&config_plugin_fmtjLiveStats_pageType=eav2&embedReferer=&config_plugin_fmtjLiveStats_edition='+specialBBCEdition+'&embedPageUrl=/1/hi/world/americas/7351742.stm&" name="embeddedPlayer" allowfullscreen="true" wmode="default" src="http://news.bbc.co.uk/player/emp/2_6_5222/player.swf" type="application/x-shockwave-flash"/>';
		html += '</object>';
		html += '</div>';
		html += '</div>';

		content.innerHTML = html;

		var panelHeight = (hasImage) ? 211 : 156;
			
		HYSMaps.createCustomInfoPanel({
			content: content, 
			height: panelHeight,
			width: 326,
			extraClass: "cgpm-audio",
			initEvents: function(dataObj) {
				var rootEl = dataObj.rootEl;
				var thisHolder = glow.dom.get(rootEl).get(".au-p-thumb-holder")[0];
				var boxWidth = thisHolder.offsetWidth;
				var boxHeight = thisHolder.offsetHeight;
				var thisThumb = glow.dom.get(rootEl).get(".au-p-thumb-holder img")[0];
				HYSMaps.fitImageWithinBoxAndFadeInOnload({
					domImage: thisThumb,
					boxDimensions: { width: boxWidth, height: boxHeight }
				});
			}
		});
		
	};
};


HYSMaps.TextClick = function (output, content, data) {
	
	this.action = function () {

		if (!data.interactive) {
			return false;
		}
		
		var html = '<h3 class="hd map-title">Report</h3>';
		html += '<h2 class="map-heading">' + data.title + '</h2>';
		if (data.date) {
			html += '<h4 class="map-date">' + data.date + '</h4>';
		}
		
		html += '<div class="map-content-holder">';
		html += '<div class="map-content-report">' + data.content + '</div>';
		html += '</div>';
		if(data.link) {
			html += '<div class="map-footer ft"><p class="map-link"><a href="'+data.link+'">Full story (you will leave this page)</a></p></div>';
		}
		content.innerHTML = html;
				
		//output.style.display = 'block';
		HYSMaps.createCustomInfoPanel({content: content, height: 307, extraClass: "cgpm-text"} );

	};
};


HYSMaps.ImagesClick = function (output, content, data) {
	
	this.action = function () {

		if (!data.interactive) {
			return false;
		}
		
		// WE have two types of image info panels, depending on whether the content field
		if (data.content) {
			var html = '<h3 class="hd map-title">Report</h3>';
			html += '<h2 class="map-heading">' + data.title + '</h2>';
			if (data.date) {
				html += '<h4 class="map-date">' + data.date + '</h4>';
			}
		}
		else {
			var html = '<h3 class="hd map-title">'+data.title+'</h3>';
		}
		
		html += '<div class="map-content-holder">';
		if (data.content) {
			html += '<div class="map-content-report">' + data.content + '</div>';
		}
		if (data.media.images) {
			var numImages = data.media.images.length;
			html += '<div class="carousel-holder">';
			html += '<div class="carousel">';
			html += '<div class="carousel-content">';
			
			for (var counter = 0; counter <numImages; counter++) {
				html += '<div class="carousel-item">';
				html += '<img src="'+data.media.images[counter].image+'" alt="'+data.title+'" />';
				html += '</div>';
			}			
			html += '</div>';
			html += '</div>';
			
			if (data.media.images[0] && data.media.images[0].caption && !data.content) {
				html += '<p class="carousel-summary">'+data.media.images[0].caption+'</p>';
			}
			if (numImages > 1) {
				html += '<div class="carousel-controls">';
				html += '<p><span class="num-image-text">1/'+numImages+'</span><a href="#" class="back">back<span>Previous</span></a><a href="#" class="forward">forward<span>Next</span></a>';
				html += '</div>';
			}
			
			
			html += '</div>';
		}
		html += '</div>';
		if(data.link && data.content) {
			html += '<div class="map-footer ft"><p class="map-link"><a href="'+data.link+'">Full story (you will leave this page)</a></p></div>';
		}
		content.innerHTML = html;

		var extraClass = (data.content) ? "cgpm-image" : "cgpm-image-no-content";
		var panelWidth = (data.content) ? "" : 507;

		HYSMaps.createCustomInfoPanel({
			content: content, 
			height: 307,
			width: panelWidth,
			extraClass: extraClass,
			initEvents: function(dataObj) { // This is the callback function that initialises the JS for the panel
				// Note that we use the numImages var from the scope of ImagesClick
				var rootEl = dataObj.rootEl;
				var selectedImage = 0;
				var glowCarouselContent = glow.dom.get(rootEl).get(".carousel-content");
				var glowBackButton = glow.dom.get(rootEl).get(".carousel-controls").get("a.back");
				var glowForwardButton = glow.dom.get(rootEl).get(".carousel-controls").get("a.forward");
				var glowSelectedImage = glow.dom.get(rootEl).get(".carousel-controls").get("span.num-image-text");
				var glowCaption = glow.dom.get(rootEl).get(".carousel-summary");
				var itemWidth = parseInt(glow.dom.get(rootEl).get(".carousel-item")[0].offsetWidth);
				var itemHeight = parseInt(glow.dom.get(rootEl).get(".carousel-item")[0].offsetHeight);
				var currentlyAnimating = false;
				// Firstly, we need to add load events to all the image
				// so that we can get their sizes and position them appropriately once loaded
				
				glowCarouselContent.
				get(".carousel-item img").
				each( function() {
					
					HYSMaps.fitImageWithinBoxAndFadeInOnload({
						domImage: this,
						boxDimensions: { width: itemWidth, height: itemHeight }
						
					});
				});
												
				var updateCarousel = function() {
					currentlyAnimating = true;
					updateArrows();
					glowSelectedImage[0].innerHTML = (selectedImage+1)+"/"+numImages;
					var anAnim = glow.anim.css(glowCarouselContent, 0.4, { 
						"left" : { to: (-itemWidth * selectedImage)+"px" } 
					},{
						tween: glow.tweens.easeBoth()
					});
					
					glow.events.addListener(anAnim, "complete", function() {
						currentlyAnimating = false;	
					});
					anAnim.start();

					if (glowCaption[0]) {
						// Here, we do the transition for the caption
						var captionAnim = glow.anim.css(glowCaption, 0.2, { 
							"opacity" : { to: 0 } 
						});
						glow.events.addListener(captionAnim, "complete", function() {
							glowCaption[0].innerHTML = data.media.images[selectedImage].caption;
							glow.anim.css(glowCaption, 0.2, { 
								"opacity" : { to: 1 } 
							}).start();
						});
						captionAnim.start();
					}
				}
				var updateArrows = function() {
					if (selectedImage <= 0) {
						glowBackButton.addClass("disabled");
					}
					else {
						glowBackButton.removeClass("disabled");
					}
					if (selectedImage >= (numImages-1)) {
						glowForwardButton.addClass("disabled");
					}
					else {
						glowForwardButton.removeClass("disabled");
					}
				}
				
				glow.events.addListener(
					glowBackButton,
					'click',
					function () {
						if (selectedImage > 0 && !currentlyAnimating) {
							selectedImage--;
							updateCarousel();
						}
						return false;
					}
				);
				glow.events.addListener(
					glowForwardButton,
					'click',
					function () {
						if (selectedImage < (numImages-1) && !currentlyAnimating) {
							selectedImage++;
							updateCarousel();
						}
						return false;
					}
				);

				updateArrows();
			}
		});
	};
};

HYSMaps.VideoClick = function (output, content, data) {
	
	this.action = function () {

		if (!data.interactive) {
			return false;
		}
	
		var thisVideo = (data.media.video && data.media.video[0]) ? data.media.video[0].video : "";
		
		var html = '<h3 class="hd map-title">'+ data.title +'</h3>';
		
		html += '<div class="map-content-holder">';

		html += '<div id="emp">';
		html += '<object id="bbc_emp_fmtj_embed_obj" width="448" height="287" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">';
		html += '<param value="http://news.bbc.co.uk/player/emp/2_2_1773/player.swf" name="movie"/>';
		html += '<param value="default" name="wmode"/>';
		html += '<param value="true" name="allowFullScreen"/>';
		html += '<param value="embeddedPlayer" name="name"/>';
		html += '<param value="config=http://news.bbc.co.uk/player/emp/config/default.xml&companionSize=300x30&companionType=adi&preroll=&config_settings_autoPlay=false&playlist=' + thisVideo + '&config_plugin_fmtjLiveStats_pageType=eav2&embedReferer=&config_plugin_fmtjLiveStats_edition=Domestic&embedPageUrl='+window.location.pathname+'&" name="flashvars"/>';
		html += '<embed id="bbc_emp_fmtj_embed_emb" width="448" height="287" flashvars="config=http://news.bbc.co.uk/player/emp/config/default.xml&companionSize=300x30&companionType=adi&preroll=&config_settings_autoPlay=false&playlist=' + thisVideo + '&config_plugin_fmtjLiveStats_pageType=eav2&embedReferer=&config_plugin_fmtjLiveStats_edition=Domestic&embedPageUrl='+window.location.pathname+'&" name="embeddedPlayer" allowfullscreen="true" wmode="default" src="http://news.bbc.co.uk/player/emp/2_2_1773/player.swf" type="application/x-shockwave-flash"/>';
		html += '</object>';
		html += '</div>';


		html += '</div>';
		if(data.link || data.media.video[0].caption) {
			html += '<div class="map-footer ft">';
			if (data.media.video[0].caption) {
				html += '<p class="map-link">'+data.media.video[0].caption+'</p>';
			}
			if (data.link) {
				html += '<p class="map-link"><a href="'+data.link+'">Full story (you will leave this page)</a></p>';
			}
			html += '</div>';
		}
		content.innerHTML = html;

		HYSMaps.createCustomInfoPanel({
			content: content, 
			height: 382, 
			width: 488,
			extraClass: "cgpm-video"
		} );

	};
	
	
};


HYSMaps.Icon = function (image, inputIcon) {
	
	this.image = (inputIcon) ? image : HYSMaps.assets + image;
	this.imageSize = { x:25, y:30 };
	this.shadow = HYSMaps.assets + 'icon-shadow.gif';
	this.shadowSize = { x:36, y:31 };
	this.iconAnchor = { x:12, y:30 };


	this.image = (inputIcon) ? image : HYSMaps.assets + image;
	this.imageSize = { x:5, y:5 };
	this.shadow = "";
	this.shadowSize = { x:5, y:5 };
	this.iconAnchor = { x:3, y:3 };
};


HYSMaps.ClusterIcon = function () {
	
	this.image = HYSMaps.assets + 'icon-cluster.gif';
	this.imageSize = { x:39, y:34 };
	this.shadow = HYSMaps.assets + 'icon-shadow.gif';
	this.shadowSize = { x:39, y:34 };
	this.iconAnchor = { x:19, y:34 };
};


HYSMaps.TypeIcon = function(image) {
	HYSMaps.Icon.call(this, image);
	
	this.imageSize = { x:25, y:30 };
	this.iconAnchor = { x:12.5, y:30 };
};
HYSMaps.TypeIcon.inherits(HYSMaps.Icon);


// HYSMaps.AutoPanelSizer - Displays alternative views based on marker density

HYSMaps.AutoPanelSizer = function(output) {
	this.output = output;
	this.panels = [];
	this.sequencedPanels = [];
	this.nonCommentPanels = [];
};

HYSMaps.AutoPanelSizer.prototype.XY_RATIO = 1;

HYSMaps.AutoPanelSizer.prototype.addPanel = function(latitude, longitude, data, series) {
	var aPanel = new this.constructor.Panel(latitude, longitude, data, series, this.output.map);
	if (data.sequenced === 0 || data.sequenced) { // Next prev will only work with panels with a sequenced val set
		this.insertPanelInCorrectSequencePosition({ aPanel: aPanel });
	}
	if (series != "Comments") {
		this.nonCommentPanels.push(aPanel);
	}
	return this.panels.push(aPanel);
};

HYSMaps.AutoPanelSizer.prototype.insertPanelInCorrectSequencePosition = function(dataObj) {
	var aPanel = dataObj.aPanel;
	var replacementArray = new Array();		
	var newPanelAdded=false;
	for (var counter = 0; counter < this.sequencedPanels.length; counter++) {
		if (!newPanelAdded && this.sequencedPanels[counter].data.sequenced > aPanel.data.sequenced) {
			replacementArray.push(aPanel);
			newPanelAdded = true;
		}
		replacementArray.push(this.sequencedPanels[counter]);
	}
	if (!newPanelAdded) {
		replacementArray.push(aPanel);
	}
	this.sequencedPanels = replacementArray;
}
/*
Panel Management - focusing panels

Use focusPreviousPanel() or focusNextPanel() to center the map at the previous/next panel in index order.
An optional first argument can be supplied to force focus on a given index.

E.g.,

	focusNextPanel(5) // center at sixth point
	focusNextPanel(-1) // center at last point
	focusPreviousPanel() // center at 2nd-last point
	focusNextPanel() // center at last point

These methods return the focused HYSMaps.AutoPanelSizer.Panel instance so that further processing can be
applied.
*/

HYSMaps.AutoPanelSizer.prototype.focusPreviousPanel = function() {
	if (this.focusedPanelIndex) {
		var v = this.sequencedPanels[this.focusedPanelIndex].view;
		v.className = v.className.replace(/\sfocused-panel(?=\s|$)/g, '');
	}

	var n = this.sequencedPanels.length,
	    i = (arguments[0] === 0) ? 0 : ((arguments[0] || this.focusedPanelIndex - 1 || 0) % n + n) % n,
	    p = this.sequencedPanels[this.focusedPanelIndex = i];

	this.output.map.setCenter(p.latitude, p.longitude);

	p.view.className += ' focused-panel';

	return p;
};

HYSMaps.AutoPanelSizer.prototype.focusNextPanel = function() {
	if (this.focusedPanelIndex) {
		var v = this.sequencedPanels[this.focusedPanelIndex].view;
		v.className = v.className.replace(/\sfocused-panel(?=\s|$)/g, '');
	}

	var n = this.sequencedPanels.length,
		i = (arguments[0] === 0) ? 0 : ((arguments[0] || this.focusedPanelIndex + 1 || 0) % n + n) % n,
		p = this.sequencedPanels[(this.focusedPanelIndex = i)];

	this.output.map.setCenter(p.latitude, p.longitude);

	p.view.className += ' focused-panel';
		
	return p;
};

HYSMaps.AutoPanelSizer.prototype.filterBySeries = function(series, isType) {
	if (isType) {
		for (var panel, i = 0; panel = this.panels[i]; ++i) {
			if (panel.data.type == series.category) {
				if (/\stype-irrelevant(?:\s|$)/.test(panel.view.className)) {
					panel.view.className = panel.view.className.replace(/\stype-irrelevant(?=\s|$)/g, '');
				} else {
					panel.view.className += ' type-irrelevant';
				}
			}
		}
	} else {
		for (var panel, i = 0; panel = this.panels[i]; ++i) {
			if (panel.series == series.name) {
				if (/\sirrelevant(?:\s|$)/.test(panel.view.className)) {
					panel.view.className = panel.view.className.replace(/\sirrelevant(?=\s|$)/g, '');
				} else {
					panel.view.className += ' irrelevant';
				}
			}
		}
	}
};

HYSMaps.AutoPanelSizer.prototype.toggleCommentsForType = function(category) {
	for (var panel, i = 0; panel = this.panels[i]; ++i) {
		if (panel.series == "Comments" && panel.data.type == category) {
			panel.view.style.display = (panel.view.style.display == 'none') ? 'block' : 'none';
		}
	}
}

HYSMaps.AutoPanelSizer.prototype.update = function(zoom) {
	var density    = this.getZoomRatio() / this.getDensityValue(),
	    thresholds = this.constructor.Panel.SIZING_THRESHOLDS,
	    i          = thresholds.length,
	    j          = this.panels.length;

	/*/ Toggle this comment between inline/block to enable/disable simple density reporting.
	document.title = density;
	//*/

	HYSMaps.currentPanelDensity = density; // We may need to use this value later so store somehwere accesible
	while (density > thresholds[--i]);
	
	if (++i !== this.mode) {
		this.mode = i;

		// Save the mode somewhere it can be accessed by GoogleMaps and MSMaps abstraction classes
		HYSMaps.densityMode = this.mode;

		while (j) {
			this.panels[--j].update(density, this.mode);
		}
	}
};

HYSMaps.AutoPanelSizer.prototype.getZoomRatio = function(zoom) {
	var map    = this.output.map,
	    ratios = map.constructor.__ZOOM_RATIOS__ || {},
	    edges  = map.getZoomRatio();

	var length = Math.sqrt(edges.x * edges.x + edges.y * edges.y);

	if (map.constructor.__ARC_LENGTH__) {
		return ratios[map.zoomLevel] = length / map.constructor.__ARC_LENGTH__;
	}

	if (map.zoomLevel !== map.OUTERMOST_ZOOM_LEVEL) {
		throw new Error("The first call to getZoomRatio() must occur at the map's outermost zoom level.");
	}

	map.constructor.__ZOOM_RATIOS__ = ratios;
	map.constructor.__ARC_LENGTH__  = length;

	return ratios[map.zoomLevel] = 1;
};

HYSMaps.AutoPanelSizer.prototype.getDensityValue = function() {
	if (this.value) {
		return this.value;
	}

	var x0, y0, dx, dy, ds, j;

	var i    = this.nonCommentPanels.length,
	    wrap = HYSMaps.AutoPanelSizer.wrapValue,
	    min  = Infinity;

	while (i) {
		panel = this.nonCommentPanels[--i];

		x0 = panel.latitude;
		y0 = panel.longitude;

		j = i;

		while (j) {
			panel = this.nonCommentPanels[--j];			

			dx = wrap(x0 - panel.latitude, 180);
			dy = y0 - panel.longitude;
			ds = dx * dx + dy * dy;

			if (ds < min) {
				min = ds;
			}
		}
	}

	return this.value = 1e-4 * Math.sqrt(min);
};


// Static helper function to calculate actual displacement over symmetric Mobius strip of given length

HYSMaps.AutoPanelSizer.wrapValue = function(displacement, length) {
	return (displacement > length || displacement < -length) ? 2 * length - Math.abs(displacement) : displacement;
};


// HYSMaps.AutoPanelSizer.Panel - Encapsulates displaying data in several modes

HYSMaps.AutoPanelSizer.Panel = function(latitude, longitude, data, series, map) {
	this.latitude  = latitude;
	this.longitude = longitude;
	this.data      = data;
	this.series    = series;
	this.map = map;
	
	if(this.data.isLimitedComment) {
		HYSMaps.limitedCommentsPanelArray.push(this);
	}
	
	this.data.interactive = !this.data.inert; // interactive is used by the VideoCLick objects below

	// Work out whether the panel is a text, audio or video panel
	// add an instance var to the data object identifying the panel type
	// Plus, cache the click action for each type of panel
	var mapDom = HYSMaps.mapHandler.map.dom;
	
	if (series == "Comments") { // Only comments have the alert field set
		this.panelType = "comment";
		this.clickFunc = new HYSMaps.CommentClick(mapDom.overlay.base, mapDom.overlay.content, this.data);
	}
	else if (series == "Incidents") {
		this.panelType = "incident";
		this.clickFunc = "";
	}
	else if (this.data.media.video && this.data.media.video[0]) {
		this.panelType = "video";
		this.clickFunc = new HYSMaps.VideoClick(mapDom.overlay.base, mapDom.overlay.content, this.data);
	}
	else if (this.data.media.audio && this.data.media.audio[0]) {
		this.panelType = "audio";
		this.clickFunc = new HYSMaps.AudioClick(mapDom.overlay.base, mapDom.overlay.content, this.data);
	}
	else if (this.data.media.images && this.data.media.images[0] && !this.data.content) {
		this.panelType = "images";	
		this.clickFunc = new HYSMaps.ImagesClick(mapDom.overlay.base, mapDom.overlay.content, this.data);
	}
	else if (this.data.media.images && this.data.media.images[0]) {
		this.panelType = "text";
		this.clickFunc = new HYSMaps.ImagesClick(mapDom.overlay.base, mapDom.overlay.content, this.data);
	}
	else {
		this.panelType = "text";
		this.clickFunc = new HYSMaps.TextClick(mapDom.overlay.base, mapDom.overlay.content, this.data);
	}
	
	if (this.data.carrierImage && this.data.carrierImage.image) {
		this.hasCarrierImage = true;
	}

	// Now set the icon for the panel
	if (this.data.icon) {
	// The author has specified an specific icon for this panel so we use that instead of the defaults  
		this.iconUrl = this.data.icon;
	}
	else {
		// We set the icon to the default for this panel type
		switch (this.panelType) {
			case "video":
				this.iconUrl = HYSMaps.mapHandler.map.series.video.icon.image;
			break;
			case "audio":
				this.iconUrl = HYSMaps.mapHandler.map.series.audio.icon.image;
			break;
			case "images":
				this.iconUrl = HYSMaps.mapHandler.map.series.images.icon.image;
			break;
			case "text":
				this.iconUrl = HYSMaps.mapHandler.map.series.text.icon.image;
			break;
			case "incident":
				this.iconUrl = HYSMaps.mapHandler.map.series.incident.icon.image;
			break;
			case "comment":
				// Comments have different icons depending on response to vote
				if (this.data.type) {
					this.iconUrl = HYSMaps.assets;
					this.iconUrl += HYSMaps.commentIconUrlTemplate.replace("????",HYSMaps.commentTypeIcons[this.data.type]);
				}
				else {
					this.iconUrl=HYSMaps.mapHandler.map.series.comments.icon.image;
				}
			break;
		}
	}	
	
	if (!this.data.isLimitedComment || this.data.shouldBeShownDespiteLimited) {
		this.addPanelToMap();
	}
};

HYSMaps.AutoPanelSizer.Panel.prototype.addPanelToMap = function() {
	var mapData = this.map.addPanel(this.latitude, this.longitude, this);
	this.mapPanelRef = mapData.mapPanelRef;
	this.view = mapData.domEl;
}

HYSMaps.AutoPanelSizer.Panel.prototype.removePanelFromMap = function() {
	this.map.removePanel({ panel: this.mapPanelRef, panelType: this.panelType});
	this.mapPanelRef = "";
	this.view = "";
}

HYSMaps.AutoPanelSizer.Panel.prototype.update = function(density, mode) {	
	if (this.data.isLimitedComment && !this.data.shouldBeShownDespiteLimited) {
		return;	
	}
	
	this.view.innerHTML = "";
	var thisPanel = this;

	var anEl = this.getPanelHTMLForMode({mode: mode, panelType: this.panelType });
	if (anEl) {
		this.view.appendChild(anEl);
	}

	if (this.panelType == "comment") {

		if (this.view.parentNode.className === 'panel-buffer') {
			this.view.parentNode.className += ' comment-panel';
		} else {
			this.view.className += ' comment-panel';
		}

		var commentIcon = anEl;
		glow.events.addListener(
			commentIcon,
			'click',
			function () {
				thisPanel.clickFunc.action();
				return false;
			}
		);
		return;
	}

	if (this.panelType == "incident") {
		return;
	}

	var moreLink = glow.dom.get(this.view).get("a.more-link")[0];
	var titleLink = glow.dom.get(this.view).get("a.title")[0];
	var closeButton = glow.dom.get(this.view).get("a.close-panel")[0];
	var imgThumb = glow.dom.get(this.view).get("img.thumb")[0];
	var smallPanel = glow.dom.get(this.view).get(".small-panel .sp-inner-panel")[0];
	var panelHoverEl = glow.dom.get(this.view).get(".panel-hover-el")[0];
	
	HYSMaps.panelPrevHoverEl = "";

	/*
	if (panelHoverEl && this.panelType != "comment") { // We don't want comments to come to the front
		glow.events.addListener(
			panelHoverEl,
			'click',
			function () {
				if (HYSMaps.panelPrevHoverEl) {
					HYSMaps.panelPrevHoverEl.parentNode.style.zIndex = 1;	
				}
				HYSMaps.panelPrevHoverEl = this;
				this.parentNode.style.zIndex = 1000;
				return false;
			}
		);
	}
	*/
		
	if (imgThumb) {
		var imageHolder = glow.dom.get(this.view).get(".lp-image-holder")[0];
		setTimeout( function() { // Solves an issue with MS Map where imageHolder has no dimensions
			if (!imageHolder.offsetHeight) { 
				// Image holder is hidden, so we set up a poll to find out
				// when the the image holder is shown again - then we show the image
				var func = arguments.callee;
				setTimeout( function() {
					func();
				},500);
				return;
			} 
			HYSMaps.fitImageWithinBoxAndFadeInOnload({
				domImage: imgThumb,
				boxDimensions: { width: imageHolder.offsetWidth, height: imageHolder.offsetHeight }
			});
		},1);
	}
	
	/* if (commentIcon) {
		glow.events.addListener(
			commentIcon,
			'click',
			function () {
				thisPanel.clickFunc.action();
				return false;
			}
		);
	} */
		
	if (moreLink) {
		glow.events.addListener(
			moreLink,
			'click',
			function () {
				thisPanel.clickFunc.action();
				return false;
			}
		);
	}
	
	if (smallPanel) {
		glow.events.addListener(
			smallPanel,
			'click',
			function () {
				thisPanel.clickFunc.action();
				return false;
			}
		);
	}
	
	if (titleLink) {
		glow.events.addListener(
			titleLink,
			'click',
			function () { 
				thisPanel.clickFunc.action();
				return false;
			}
		);
	}
	
	if (closeButton) {
		glow.events.addListener(
			closeButton,
			'click',
			function () { 
				return false;
			}
		);
	}
	
};

HYSMaps.AutoPanelSizer.Panel.SIZING_THRESHOLDS = [220, 115]; // Change me!

HYSMaps.AutoPanelSizer.Panel.prototype.getPanelHTMLForMode = function(dataObj) {
	
	var panelType = this.panelType;
	var mode = dataObj.mode;
	
	// If a panel has a carrier image, we use the image as the panel content
	// rather than defaults below. The same html is used regardless of zoom level 
	if (this.hasCarrierImage) {
		var carrierWidth = (this.data.carrierImage.width) ? this.data.carrierImage.width : HYSMaps.defaults.carrierImage.width;
		var carrierHeight = (this.data.carrierImage.height) ? this.data.carrierImage.height : HYSMaps.defaults.carrierImage.height;
		var containerWidth = parseInt(carrierWidth) + HYSMaps.defaults.carrierImage.padding;
		var lipOffset = HYSMaps.defaults.carrierImage.lipOffset({imgWidth: parseInt(this.data.carrierImage.width) });
		
		var returnEl = document.createElement("div");
		returnEl.className = "small-panel sp-carrier-image";
		
		if (!this.data.interactive) {
			returnEl.style.top = (parseInt(carrierHeight/2)+parseInt(HYSMaps.defaults.carrierImage.lipHeight))+"px";
		}
		returnEl.style.width = containerWidth+'px';
		returnEl.style.marginLeft = lipOffset+'px';
		
		var html = this.data.interactive ? '<div class="sp-shadow"></div>' : '<div class="sp-shadow2"></div>';
		html += '<div class="sp-inner-panel panel-hover-el">';
		html += '<div class="sp-top">';
		html += '<div class="sp-tl-corner"></div>';
		html += '<div class="sp-tr-corner"></div>';
		html += '<div class="sp-t-repeat"></div>';
		html += '</div>';
		html += '<div class="sp-content-container">';
		html += '<div class="sp-content-outer">';
		html += '<div class="sp-content">';
		html += '<img style="width:'+carrierWidth+'px" src="'+this.data.carrierImage.image+'" />';
		html += '</div>';
		html += '</div>';
		html += '</div>';
		html += '<div class="sp-bottom">';
		html += '<div class="sp-br-corner"></div>';
		html += '<div class="sp-bl-corner"></div>';
		html += '<div class="sp-b-repeat">';
		html += this.data.interactive ? '<div class="sp-b-lip"></div>' : '<div class="sp-b-lip2"></div>';
		html += '</div>';
		html += '</div>';
		html += '</div>';

		returnEl.innerHTML = html;
		return returnEl;
	}

	// Only display icons for comments
	if (panelType && panelType == "comment") {
		if (HYSMaps.browserType == "IE6" && this.iconUrl.indexOf(".png") !=-1) {
			var returnEl = document.createElement("div");
			returnEl.className = "ie-comment-icon-holder";
			returnEl.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+this.iconUrl+'", sizingMethod="crop")';
			returnEl.style.width = "18px";
			returnEl.style.height = "32px";
			
			var ieImage = document.createElement("img");
			ieImage.setAttribute('src', this.iconUrl);
			ieImage.setAttribute('alt', this.data.type);
			ieImage.style.height = "32px";

			returnEl.appendChild(ieImage);
			
			return returnEl;
		}
		else {
			var returnEl = document.createElement("img");
			returnEl.className = "comment-icon";
			returnEl.setAttribute('src', this.iconUrl);
			returnEl.setAttribute('alt', this.data.type);
			return returnEl;
		}
	}
		
	// Only display icons for comments
	if (panelType && panelType == "incident") {
		if (HYSMaps.browserType == "IE6") {
			var returnEl = document.createElement("div");
			returnEl.className = "ie-incident-icon-holder";
			returnEl.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+this.iconUrl+'", sizingMethod="crop")';
			returnEl.style.width = this.data.iconWidth+"px";
			
			var ieImage = document.createElement("img");
			ieImage.setAttribute('src', this.iconUrl);
			ieImage.style.width = this.data.iconWidth+"px";

			returnEl.appendChild(ieImage);
			
			return returnEl;
		}
		else {
			var returnEl = document.createElement("img");
			returnEl.className = "incident-icon";
			returnEl.setAttribute('src', this.iconUrl);
			returnEl.style.width = this.data.iconWidth+"px";
			return returnEl;
		}
	}
		
	switch (mode) {
		case 0:
			var returnEl = document.createElement("div");
			returnEl.className = "small-panel";
			// var html = this.data.interactive ? '<div class="sp-shadow"></div>' : '<div class="sp-shadow2"></div>';
			var html = '<div class="sp-shadow"></div>';
			html += '<div class="sp-inner-panel panel-hover-el">';
			html += '<div class="sp-top">';
			html += '<div class="sp-tl-corner"></div>';
			html += '<div class="sp-tr-corner"></div>';
			html += '<div class="sp-t-repeat"></div>';
			html += '</div>';
			html += '<div class="sp-content-container">';
			html += '<div class="sp-content-outer">';
			html += '<div class="sp-content">';
			html += '<img src="'+this.iconUrl+'" />';
			html += '</div>';
			html += '</div>';
			html += '</div>';
			html += '<div class="sp-bottom">';
			html += '<div class="sp-br-corner"></div>';
			html += '<div class="sp-bl-corner"></div>';
			html += '<div class="sp-b-repeat">';
			//html += this.data.interactive ? '<div class="sp-b-lip"></div>' : '<div class="sp-b-lip2"></div>';
			html += '<div class="sp-b-lip"></div>';
			html += '</div>';
			html += '</div>';
			html += '</div>';
			returnEl.innerHTML = html;
		break;
		case 1:
			var returnEl = document.createElement("div");
			returnEl.className = "medium-panel";

			//var html = this.data.interactive ? '<div class="mp-shadow"></div>' : '<div class="mp-shadow2"></div>';
			var html = '<div class="mp-shadow"></div>';
			html += '<div class="mp-inner-panel panel-hover-el">';
			html += '<div class="mp-outer-panel-top"></div>';
			html += '<div class="mp-outer-panel">';
			html += '<div class="mp-inner-panel">';
			html += '<a class="title" href="#">'+this.data.title+'<img class="icon" src="'+this.iconUrl+'" alt="" /></a>';
			html += '</div>';
			html += '</div>';
			//html += this.data.interactive ? '<div class="lip"></div>' : '<div class="lip2"></div>';
			html += '<div class="lip"></div>';
			html += '</div>';

			returnEl.innerHTML = html;

		break;
		case 2:
			var thumbImage = this.data.media.thumb || "";
			thumbImage = (!thumbImage && this.data.media.images && this.data.media.images[0]) ? this.data.media.images[0].image : thumbImage;  
			var returnEl = document.createElement("div");
			returnEl.className = "large-panel";

			//var html = this.data.interactive ? '<div class="lp-shadow"></div>' : '<div class="lp-shadow2"></div>';
			var html = '<div class="lp-shadow"></div>';
			html+= '<div class="lp-inner-panel panel-hover-el">';
			html+= '<div class="lp-outer-panel-top"></div>';
			html+= '<div class="lp-outer-panel">';
			html+= '<div class="lp-inner-panel">';
			html+= '<h3>'+this.data.title+'</h3>';
			if (thumbImage) {
				html+= '<div class="lp-image-holder"><img class="thumb" src="'+ thumbImage+'" alt="'+this.data.title+'" /></div>';
			}
			html+= '<p>'+this.data.summary+'</p>';
			if (this.data.interactive) {
			html+= '<a class="more-link" href="#">More'+'<img class="icon" src="'+this.iconUrl+'" alt="" /></a>';
			}
			html+= '<div class="clear"></div>';
			html+= '</div>';
			html+= '<a class="close-panel" href="#">Close panel</a>';
			html+= '</div>';
			//html += this.data.interactive ? '<div class="lip"></div>' : '<div class="lip2"></div>';
			html += '<div class="lip"></div>';
			html+= '</div>';
			returnEl.innerHTML = html;
		break;		
	}
	return returnEl || "";
}

// This variable is set to the last panel that was open
// We use this var to close a panel when a new panel is opened
HYSMaps.previousCustomInfoPanel = "";

// Function for creating a custom BBC Glow panel
HYSMaps.createCustomInfoPanel = function(dataObj) {
	var content = dataObj.content;
	var height = dataObj.height;
	var mapDom = HYSMaps.mapHandler.map.dom;
	var extraClass = (dataObj.extraClass) || "";
	var initEvents = dataObj.initEvents;
	var width = dataObj.width || 400; // Panel defaults to 400px in width

	var panelOffset = { x: 0, y: (HYSMaps.mapHandler.map.dom.commentLimiter.height + 50)+"px" };
	panelOffset.x = (HYSMaps.mapDimensions.width - width + 60);
	panelOffset.x = (panelOffset.x < 0) ? parseInt(panelOffset.x/2)+"px" : panelOffset.x+"px";
	
	var anInfoPanel = new glow.widgets.InfoPanel(content, {
		context: mapDom.base,
		pointerPosition: "t",
		theme: "light",
  		offsetInContext: panelOffset
	});
		
	anInfoPanel.content.addClass("custom-glow-panel-map");
	if (extraClass) {
		anInfoPanel.content.addClass(extraClass);
	}


	// Add panel close function
	HYSMaps.infoPanelStatus.isAPanelOpen = true;
	HYSMaps.mapHandler.map.disableNextPrevPanelControls();	
	glow.events.addListener(anInfoPanel, "afterHide", function() {
		HYSMaps.infoPanelStatus.isAPanelOpen = false;
		HYSMaps.mapHandler.map.enableNextPrevPanelControls();
		anInfoPanel.container[0].innerHTML="";
	});

	anInfoPanel.show();

	// Only need for HTML 4 transitional, which we are no longer supporting
	/*if (height) {
		var hEl = glow.dom.get(anInfoPanel.container[0]).get("div.c")[0];
		hEl.style.height = height+"px";
	}*/
	if (width) {
		anInfoPanel.container[0].style.width = width+"px";
	}

	if (initEvents) {
		initEvents({
			rootEl: anInfoPanel.content[0]
		});
	}
	
	if (HYSMaps.previousCustomInfoPanel) {
		HYSMaps.previousCustomInfoPanel.hide();
		HYSMaps.previousCustomInfoPanel.container[0].innerHTML="";
	}
	
	
	HYSMaps.previousCustomInfoPanel = anInfoPanel;
	
}


HYSMaps.fitImageWithinBoxAndFadeInOnload = function(dataObj) {
	var domImage = dataObj.domImage;
	var boxDimensions = dataObj.boxDimensions;
	
	var fitImageWithinBox = function(dataObj) {
		var anImage = dataObj.anImage;
		var myHeight = anImage.offsetHeight;
		var myWidth = anImage.offsetWidth; 
		
		var newDimensions = HYSMaps.getWidthHeightXYOffsetstoCropImagetoBounds({
			imageDimensions: { width: myWidth, height: myHeight },
			boundsDimensions: boxDimensions
		});

		anImage.style.top = newDimensions.top+"px";
		anImage.style.left = newDimensions.left+"px";
		anImage.style.width = newDimensions.width+"px";
		anImage.style.height = newDimensions.height+"px";
	};
	
	if (!domImage.complete) {
		glow.events.addListener(
			domImage,
			'load',
			function () {
				fitImageWithinBox({anImage: this });
				// Image is loaded and positioned correctly - now fade in;
				glow.anim.css(this, 0.5, { 
					"opacity" : { to: 1 } 
				}).start();
			}
		)
	}
	else {
		// Image already loaded in cache, so display it straight away
		fitImageWithinBox({anImage: domImage });	
		glow.anim.css(domImage, 0.01, { 
			"opacity" : { to: 1 } 
		}).start();
	}

}

// This funciton provides the width, height, top and left offsets to achieve the perfect fit
// of an image within a container (bounds), ensuring no distortion of the image
HYSMaps.getWidthHeightXYOffsetstoCropImagetoBounds = function(dataObj) {
	imageDimensions = dataObj.imageDimensions;
	boundsDimensions = dataObj.boundsDimensions;
	var retDimensions = { width: 0, height: 0, x: 0, y: 0 };
	
	if (imageDimensions.height/imageDimensions.width < boundsDimensions.height/boundsDimensions.width) {
		retDimensions.height = boundsDimensions.height;
		retDimensions.width = retDimensions.height/imageDimensions.height * imageDimensions.width;
		retDimensions.top = 0;
		retDimensions.left = parseInt((boundsDimensions.width - retDimensions.width)/2);  
	}
	else {
		retDimensions.width = boundsDimensions.width;
		retDimensions.height = retDimensions.width/imageDimensions.width * imageDimensions.height;
		retDimensions.left = 0;
		retDimensions.top = parseInt((boundsDimensions.height - retDimensions.height)/2);  
	}
	return retDimensions;
}

