var map;

var geocoder;

var defaultVolume = 75;

var sounds = new Array();

var projects = new Array();

var users = new Array();

var loggedOnUser;

var filterTypes=['project','user','tag'];

var activeFilters=new Array();

var inactivityTimer;

var inactivityInterval=90000; // plays random sound after interval has elapsed with no user activity

var defaultLat=52.48842;

var defaultLng=-1.9216;

var defaultZoom=13;

var initialCentre;

var initialZoom;

var mapMoved;

var zoomChangedListener;

var overlay;



// NavigationOverlay is derived from google.maps.OverlayView

NavigationOverlay.prototype = new google.maps.OverlayView();

NavigationOverlay.prototype.onAdd = function() {}

NavigationOverlay.prototype.onRemove = function() {}



// This overlay is re-drawn each time setBounds() is called. It ensures that no markers are obscured

// by the navigation area when the map bounds are redrawn to fit visible markers.

NavigationOverlay.prototype.draw = function() {

	// Take into account navigation area

	var navHeight = $('controlarea').getHeight();

	var navWidth = $('controlarea').getWidth();

	var overlayProjection;

	

	overlayProjection = this.getProjection();

	

	var navNE = overlayProjection.fromContainerPixelToLatLng(new google.maps.Point(navWidth,0));

	var navSW = overlayProjection.fromContainerPixelToLatLng(new google.maps.Point(0,navHeight));

	

	navBounds = new google.maps.LatLngBounds(navSW, navNE);

	

	// if the navigation area intersects the marker bounds, zoom out one notch

	if(this.bounds_.intersects(navBounds))

		this.map_.setZoom(this.zoom_ - 1);

	

	this.setMap(null);

}



function NavigationOverlay(map, bounds, zoom) {

    this.map_ = map;

	this.bounds_ = bounds;

	this.zoom_ = zoom;

    this.setMap(map);

}



//flash version URL switch (for this demo page)

if (window.location.toString().match(/flash9/i)) {

  soundManager.flashVersion = 9;

} else if (window.location.toString().match(/flash8/i)) {

  soundManager.flashVersion = 8;

}



// path to SoundManager2 SWF files (note trailing slash)

soundManager.url = 'swf/'; 

soundManager.debugMode = false;

soundManager.useFastPolling=false;

soundManager.consoleOnly = false;

soundManager.useHighPerformance=false;

soundManager.autoPlay=true;

//soundManager.onerror=function(){alert('soundmanager error');}

document.observe('dom:loaded', onLoad);



// Sets up map, left control area and loads map markers

function onLoad() {

	showWaitingMessage('application initialising, please wait...',false, 50);

	

	var mapOptions = {

		mapTypeId: google.maps.MapTypeId.HYBRID,

		zoom:defaultZoom,

		mapTypeControlOptions: { 

			style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,

			position: google.maps.ControlPosition.TOP_RIGHT 

		},

		navigationControlOptions: { position:google.maps.ControlPosition.TOP_RIGHT }

	}	

	

	if(startLat && startLng != null)

		mapOptions.center = new google.maps.LatLng(startLat, startLng);

	else

		mapOptions.center = new google.maps.LatLng(defaultLat, defaultLng);

	

	if(startZoom)

		mapOptions.zoom=startZoom;

	else

		mapOptions.zoom=defaultZoom;

	

	map = new google.maps.Map(document.getElementById("map"), mapOptions);

	geocoder = new google.maps.Geocoder();

	

	

	// Listen for map dragstart events - this is used to detect if map has been moved by user

	google.maps.event.addListener(map,'dragstart',function(){ mapMoved=true });

	



	

	tinyMCE.init({

		mode:'exact',

		elements:'projectdescription',

		theme:'advanced',

		plugins:'paste',

		relative_urls:false,

		convert_urls:true,

		theme_advanced_buttons1 : "newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontsizeselect",

		theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,cleanup,|,forecolor,backcolor",

		theme_advanced_buttons3 : "",

		theme_advanced_toolbar_location : "top",

		theme_advanced_toolbar_align : "left",

		theme_advanced_statusbar_location : "bottom",

		theme_advanced_resizing : true,

		theme_advanced_path : false,

		force_br_newlines:true,

		forced_root_block:'',

		content_css:'css/layout.css, css/font.css, css/color.css'

	});

		

	// Wait for soundmanager to load before creating sounds

	soundManager.onload=function(){

			new Ajax.Request('php/json.php',

					{ 	

						method:'get',			

						onComplete: getApplicationData,

						onFailure: function(){alert('something went wrong');}

					});

	}

	



	

	$('project_heading').observe('mouseup', function(e){Effect.toggle('project_filters', 'blind', {duration:0.1})});

	$('play_options_heading').observe('mouseup', function(){Effect.toggle('play_options','blind', {duration:0.1});});

	$('search_options_heading').observe('mouseup', function(){Effect.toggle('search_options','blind', {duration:0.1});});

	$('toggle_unattended').observe('mouseup', function(e){  

															e.element().toggleClassName('active'); 

															toggleUnattendedMode(); 

														});

	$('toggle_multiplay').observe('mouseup', function(e){ e.element().toggleClassName('active'); });

	$('navigationform').observe('submit', navigateToAddress); // Bind navigate to button event handler

	$('killemall').observe('click',removeAllSounds);

	$('loginform').observe('submit', authenticateUser); // Bind login handler

	$('add_project').observe('click', showEditFilter.bind($('add_project')));

	$('manage_tags').observe('click', showEditFilter.bind($('manage_tags')));

	$('manage_users').observe('click', showEditFilter.bind($('manage_users')));

	$('manageruser').observe('change', function(){

		var selected = $$('#manageruser option').find(function(ele){return !!ele.selected});

		users.each(function(s){

			if(s.id == selected.value){

				$('managerusername').value=s.username;

				$('manageremail').value=s.email;

				$('displayname').value=s.name;

				$('operation').value='updateuser';

				$('filtername').value=s.name;

				

				$('delete').show();

				throw $break;

			}else{

				$('operation').value='adduser';

				$('filtername').value

				$('delete').hide();	

				

			}

			

		});

	});

	$('canceledit').observe('click', function(){

												Effect.Fade('editcontainer',{duration:1.0});

	 										});

	$('delete').observe('click', function(){

		if($('filtermanagement').visible())

			$('operation').value='deletefilter';

		

		if($('usermanagement').visible())

			$('operation').value='deleteuser';

	});

	

	$('navigatetext').clear();

	$('latitude').disable();

	$('longitude').disable();

	$('usemapforlocation').checked=true;

	$('use_map_for_zoom').checked=true;

	$('use_map_for_zoom').disable();

	$('soundoperation').value='add';

	

	$('projectheader').observe('mouseup', function(){Effect.toggle('projectfields','blind', {duration:0.1});});

	

	google.maps.event.addListener(map, 'click', function(event) {

		$('latitude').value=event.latLng.lat();

	   	$('longitude').value=event.latLng.lng();

	});

	

	// Toggle find location

	$('usemapforlocation').observe('click', function(e){

														google.maps.event.clearListeners(map, 'click');

		

														if(e.element().checked) {

															$('latitude').disable();

															$('longitude').disable();

															

															var clickListener = google.maps.event.addListener(map, 'click', function(event) {

																$('latitude').value=event.latLng.lat();

																$('longitude').value=event.latLng.lng();

															});

														

														}

														else {

															$('latitude').enable();

															$('longitude').enable();

														}

												  });

	

	

	$('zoom_level').value=map.getZoom();

	$('zoom_level').disable();

	

	$('zoom_level').observe('change', function(e){

		map.setZoom(parseInt($('zoom_level').value));

	});

	

	zoomChangedListener = google.maps.event.addListener(map, 'zoom_changed', function(e){

		$('zoom_level').value = map.getZoom();

	});

	

	// toggle use map for zoom

	$('use_map_for_zoom').observe('click', function(e){

		google.maps.event.removeListener(zoomChangedListener);

		

		if(this.checked){

			$('zoom_level').value=map.getZoom();

			zoomChangedListener = google.maps.event.addListener(map, 'zoom_changed', function(e){

				$('zoom_level').value=map.getZoom();

			});

		}

	});

	

	$('selected_project').observe('mouseup', function(e){applyFilters();});



	// configure file upload

	new AjaxUpload($('file'), {

		action: 'php/upload.php?soundoperation=fileupload',

		name:'userfile',

		onSubmit : function(file,extension){

			$('file').hide();

			$('fileuploadstatus').show();

			$('fileuploadstatus').update(file+' uploading...');

			$('submitupload').disable();

			$('deletesound').disable();

			$('updatesound').disable();

			

			showWaitingMessage('file uploading, please wait...', false, 50);

			

		},

		onComplete : function(file, response){

			//alert(response);

			var result = response.evalJSON();

			

			if(result.status==true){

				// hide upload box and display uploaded filename

				$('file').hide();

				$('fileuploadstatus').show();

				$('fileuploadstatus').update(result.message);

				$('filename').value=result.filename;

				$('changefile').show();

				$('submitupload').enable();

				$('deletesound').enable();

				$('updatesound').enable();

			} else if(result.status==false){

				alert(result.message);

				$('filename').clear();

				$('file').show();

				$('fileuploadstatus').hide();

				$('changefile').hide();

				$('submitupload').enable();

				$('deletesound').enable();

				$('updatesound').enable();

			}

			

			$('waitingblock').hide(); // hide waiting message

		}		

	});



	

	

	$('changefile').observe('click', function(e){

		$('file').show();

		$('fileuploadstatus').hide();

		e.element().hide();

	});

	

	

	

	$('editmode').checked=false;

	// Add sound details for uploaded sound

	$('uploadform').observe('submit', uploadSound); // Bind upload handler

	$('editmode').observe('click', toggleEditMode.bind($('editmode')));

	$('updatesound').observe('click',function(){$('soundoperation').value='update';$('showstatus').value=true;});

	$('deletesound').observe('click',function(){$('soundoperation').value='delete';});

	

	// Initialise show/hide control area

	$('showHideControlArea').observe('click', toggleControlArea);

	

	// Save any sound edits before shutting down

	Event.observe(window, 'beforeunload',function(){ 

		if($('soundid')!='')

			uploadSound();

			

	});



}



function toggleControlArea(){

	var SHOW_HIDE_Y_POS = 2;

	var SHOW_HIDE_X_POS = 230;



	Effect.toggle('controlarea', 'appear');

	

	if($('controlarea').style.display=='none'){	

		$('showHideControlArea').innerHTML='&lt;&lt;';

		new Effect.Move('showHideControlArea', {x:SHOW_HIDE_X_POS, y:SHOW_HIDE_Y_POS, mode:'absolute'});

	}

	else{

		$('showHideControlArea').innerHTML='&gt;&gt;';

		new Effect.Move('showHideControlArea', {x:2, y:SHOW_HIDE_Y_POS, mode:'absolute'});

	}	

}





// Shows and hides the appropriate fields, sets marker click handler and resets the upload

// form when toggling edit mode. This function handles the click event of $('editmode')

function toggleEditMode()

{

	var isEditMode = this.checked;

	

	resetUploadForm();

	

	if(isEditMode)

		$('toggle_unattended').removeClassName('active');

	

	isEditMode ? setMarkerListeners(populateUpload,'yellow', true):setMarkerListeners(playSound,'blue',false); 

	isEditMode ? $('file').hide():$('file').show();

	isEditMode ? $('submitupload').hide():$('submitupload').show();

	isEditMode ? $('soundoperation').value='update':$('soundoperation').value='add';

	

	if(isEditMode){

		google.maps.event.clearListeners(map, 'click');

		google.maps.event.removeListener(zoomChangedListener);

		$('usemapforlocation').checked=false;

		$('usemapforlocation').disable();

		$('zoom_level').enable();

		$('use_map_for_zoom').checked=false;

		$('use_map_for_zoom').enable();

	}

	

	if(!isEditMode){

		$('usemapforlocation').checked=true;

		$('usemapforlocation').enable();

		$('use_map_for_zoom').checked=true;

		$('use_map_for_zoom').disable();

		$('use_map_for_zoom').disable();

		$('zoom_level').disable();

		

		google.maps.event.addListener(map, 'click', function(event) {

			$('latitude').value=event.latLng.lat();

		   	$('longitude').value=event.latLng.lng();

		});

		

		$('delete').hide;

		$('changefile').hide();

		$('fileuploadstatus').hide();

		$('deletesound').hide();

		$('updatesound').hide();

		$('file').show();

	}

}



// Sets listeners on markers for edit/new modes. In edit mode we populate the upload form, 

// otherwise we want to play the sound. Also sets marker colour for each mode

function setMarkerListeners(handler, iconColor, isDraggable){

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

		google.maps.event.clearListeners(sounds[i].marker,'mouseup');

		google.maps.event.clearListeners(sounds[i].marker,'mousedown');

		google.maps.event.clearListeners(sounds[i].marker,'drag');

		google.maps.event.clearListeners(sounds[i].marker,'dragend');

		

		updateMarker(sounds[i].id, false);

		

		if(handler){

			sounds[i].marker.setDraggable(isDraggable);

			

			// add mouseup handler 

			if(handler==playSound){

				google.maps.event.addListener(sounds[i].marker, 'mouseup', playSound.bindAsEventListener(this,sounds[i]));

			}

			else{

				google.maps.event.addListener(sounds[i].marker, 'mousedown', populateUpload.bindAsEventListener(this,sounds[i]));

				google.maps.event.addListenerOnce(sounds[i].marker, 'mousedown', applyZoom.bind(sounds[i], sounds[i]));

			}

			// add drag handlers

			if(isDraggable){

				google.maps.event.addListener(sounds[i].marker,'drag',updateLatLng.bindAsEventListener(this, sounds[i]));

				google.maps.event.addListener(sounds[i].marker,'dragend', function(){ uploadSound();});

			}

		}

	}

	

}



// Applies sound's default zoom level to the map and re-centres if increasing zoom

function applyZoom(sound){

	// if increasing zoom level, then reset centre

	if(sound.zoom_level > map.getZoom())

		map.panTo(new google.maps.LatLng(sound.lat,sound.lng));

	

	map.setZoom(parseInt(sound.zoom_level));

}



// updates lat and lng as marker is dragged

function updateLatLng(){

	var sound=$A(arguments)[1];

	var lat=sound.marker.getPosition().lat();

	var lng=sound.marker.getPosition().lng();

	

	$('latitude').value=lat;

	$('longitude').value=lng;

	$('latitude_submit').value=lat;

	$('longitude_submit').value=lng;

	

	var i = getSoundIndex(sound.id);

	

	sounds[i].lat=lat;

	sounds[i].lng=lng;

}





// Resets form fields but remembers state of editmode and use map for location boxes

// and shows file browse

function resetUploadForm(){

	//cache form values we want to preserve

	var usemap=$('usemapforlocation').checked;

	var usezoom=$('use_map_for_zoom').checked;

	var zoom=$('zoom_level').value;

	var editmode=$('editmode').checked;

	var operation=$('soundoperation').value;



	if($('soundid').value!='')

		uploadSound();

	

	$('uploadform').reset(); // this is the only reliable way to clear textareas

	$('filename').clear(); // need to explicitly clear hidden fields

	$('soundid').clear();

	$('latitude_submit').clear();

	$('longitude_submit').clear();

	$('soundoperation').value=operation;

	$('sounddescription').innerHTML='';

	$('tagbox').innerHTML='';

	$('usemapforlocation').checked=usemap;

	$('editmode').checked=editmode;	

	$('deletesound').hide();

	$('updatesound').hide();

	$('fileuploadstatus').hide();

	$('use_map_for_zoom').checked=usezoom;

	$('zoom_level').value=zoom;

}



function populateUpload()

{

	var event=$A(arguments)[0];

	var editSound=$A(arguments)[1];

	

	// make previous edit inactive

	updateMarker($('soundid').value,false);

	

	resetUploadForm();

	

	$('soundoperation').value=='update';

	

	$('soundid').value = editSound.id;

	$('soundtitle').value = editSound.name;

	

	// Description doesn't like being set to null - must use an empty string

	(editSound.description==null) ? $('sounddescription').update(''):$('sounddescription').update(editSound.description);

	

	editSound.recording_date ? $('daterecorded').value=editSound.recording_date:$('daterecorded').value='';



	for(var i=0;i<editSound.project.length;i++)

		$('project_'+editSound.project[i].id).checked=true;

	

	var tags='';

	

	for(var i=0;i<editSound.tag.length;i++){

		tags = tags + editSound.tag[i].name;

		

		if(i!=editSound.tag.length-1)

			tags=tags+', ';

	}	

	

	$('tagbox').update(tags);

	$$('#authorid option').each(function(o){

	      	if(o.value==editSound.user_id) o.selected = true; 

	});

	

	$$('#parent_id option').each(function(o){

			if(o.value==editSound.parent_id) o.selected=true;

	});

	

	$('latitude_submit').value=editSound.marker.getPosition().lat();

	$('longitude_submit').value=editSound.marker.getPosition().lng();

	$('latitude').value=editSound.marker.getPosition().lat();

	$('longitude').value=editSound.marker.getPosition().lng();

	$('zoom_level').value=editSound.zoom_level;

	

	// do file name

	$('filename').value=editSound.filelocation;

	$('fileuploadstatus').show();

	$('fileuploadstatus').update(editSound.filelocation);

	$('changefile').show();

	$('file').hide();

	$('deletesound').show();

	$('updatesound').show();

	

	// change marker color

	updateMarker(editSound.id, true);

}



// Uploads sound file and adds to database

function uploadSound()

{

	$('latitude_submit').value=$('latitude').value;

	$('longitude_submit').value=$('longitude').value;

	$('zoom_level_submit').value=$('zoom_level').value;

	

	var confirmDelete=true;

	

	if($('soundoperation').value=='delete')

		confirmDelete=confirm('You are about to delete sound: '+$('soundtitle').value+'. \nDo you wish to continue?');

	

	if(confirmDelete)

		new Ajax.Request('php/upload.php',{

											parameters:$('uploadform').serialize(),

											onSuccess: function(transport){

															var result=processAjax(transport);

															

															// If upload was success then add new marker and recenter map

															if(result.status){

																

																if(result.mode=='add'){

																	alert(result.message);

																	result.sound[0].smSound = createSound(result.sound[0]);

																	sounds.push(result.sound[0]);

																	createMarker(result.sound[0]);

																	$('soundid').value!='';

																	buildParentSounds();

																	resetUploadForm();

																	$('file').show();

																	$('changefile').hide();

																}

																else if (result.mode=='update'){

																	// display result if update button has been pressed

																	if($('showstatus').value)

																		alert(result.message);

																	

																	$('showstatus').clear();

																	

																	var i = getSoundIndex(result.sound[0].id);

																	soundManager.destroySound('sound_'+result.sound[0].id);

																	

																	sounds[i].smSound=createSound(result.sound[0]);

																	sounds[i].name=result.sound[0].name;

																	sounds[i].description=result.sound[0].description;

																	sounds[i].parent_id=result.sound[0].parent_id;

																	sounds[i].marker.setTitle(result.sound[0].name);

																	sounds[i].filelocation=result.sound[0].filelocation;

																	sounds[i].lat=result.sound[0].lat;

																	sounds[i].lng=result.sound[0].lng;

																	sounds[i].recording_date=result.sound[0].recording_date;

																	sounds[i].user_id=result.sound[0].user_id;

																	sounds[i].user_name=result.sound[0].user_name;

																	sounds[i].project=result.sound[0].project;

																	sounds[i].tag=result.sound[0].tag;

																	sounds[i].zoom_level=result.sound[0].zoom_level;

																	

																	//if($('showstatus').value)

																	//	buildParentSounds(sounds[i].parent_id);

																	

																	

																}

																else if(result.mode=='delete'){

																	var i = getSoundIndex(result.soundid);

																	sounds[i].smSound.destruct();

																	sounds[i].marker.setMap(null);

																	sounds.splice(i, 1);

																	

																	$('soundid').clear();

																	resetUploadForm();

																	buildParentSounds();

																	

																	//reset operation

																	$('soundoperation').value='update';

																}

																

																

																buildFilters(result.taglist,['tag']);	

																map.panTo(new goole.maps.LatLng(result.lat, result.lng));

																

															}

															else{

																alert(result.message);

															}

														},

											onFailure: function(){alert('An error occurred when processing upload');}

										  });

}



// Makes AJAX call to authentication script

function authenticateUser()

{

	new Ajax.Request('php/login.php',

						{

							method:'post',

							parameters: $('loginform').serialize(true), // object hash of form values

							onSuccess:showUploadForm,

							onFailure: function(){alert('an error occurred while attempting to log in');}

						});

}



function showUploadForm(ajaxAuthenticationResponse)

{

	var result = processAjax(ajaxAuthenticationResponse);

	

	// Hide login and show upload

	if(result.status){

		var loggedOnUser = result.user;

		

		if(loggedOnUser.is_admin==true)

			$('manage_users').show();

			

		

		$('uploadform').style.display='block';

		$('loginform').style.display='none';

	}

	else

	{

		alert(result.message);

		

	}

}





// AJAX response handler. Creates marker points by delegating to createMarker()

function getApplicationData(ajaxResponse)

{   

	//$('ajax-debug').update(ajaxResponse.responseText);

	

	var result = processAjax(ajaxResponse);

	var filters = result.filters;

	sounds = result.sounds;



	

	try{

		buildFilters(filters, filterTypes);

		buildUploadForm(filters, filterTypes);

	}catch(err){

		alert(err.message);

	}

	

	// create map markers

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

		createMarker(sounds[i]);

		try{

			sounds[i].smSound = createSound(sounds[i]);

		} catch(err){

			alert(err.message);

		}

	}

	

	$('waitingblock').hide();

}



// Adds new sound to sound manager

function createSound(sound){

	return soundManager.createSound(

		    {

		      multiShot:false,

		      id: 'sound_'+sound.id,

		      url: sound.filelocation,

		      whileplaying:function(){

						    	if(this.position % 2 == 0){

									var id=this.sID.match(/\d+/);

									var duration = Math.floor(this.duration/1000);

									var mins=Math.floor(duration/60);

									var secs=duration % 60;

									secs < 10?secs='0'+secs:secs;

				

									var position=Math.floor(this.position/1000);

									var posmins=Math.floor(position/60);

									var possecs=position%60;

									possecs < 10?possecs='0'+possecs:secs;

									

									$('duration_'+id).update(posmins+':'+possecs + '/' + mins+':'+secs);

						    	}

		    				},			

		      onplay:function(){		

		    			mapMoved=false;

		    					

		    			var sound=sounds[getSoundIndex(this.sID.match(/\d+/))];

		    			$(this.sID).removeClassName('notplayed');

		    			

		    			updateMarker(sound.id, true);

		    			

		    			// check for sequence

		    			if(!$$('#sound_'+sound.parent_id)[0]){

		    				initialCentre=map.getCenter();

		    				initialZoom=map.getZoom();

		    			}

		    			

		    			map.setZoom(parseInt(sound.zoom_level));

		    			

		    			// If the sound is not within the current map bounds then center on that

		    			if(map.getBounds().contains(sound.marker.getPosition())==false){

		    				map.setCenter(new google.maps.LatLng(sound.lat,sound.lng));

		    			}
				

		    		},

		      onfinish:function(){ 

		    				var id=this.sID.match(/\d+/);

		    				var sound=sounds[getSoundIndex(id)];

		    				updateMarker(id, false, 'images/single-played.png');

		    				

		    				$('duration_'+id).update();

		    				

		    				if($(this.sID).hasClassName('parent') || $(this.sID).hasClassName('child')){

		    					playNext(this.sID);

		    				}

		    				else {

		    					$(this.sID).remove();

		    					

		    					// If the map hasn't been moved, then go back to initial position

		    					if(!mapMoved){

		    						map.setCenter(initialCentre);

		    						map.setZoom(initialZoom);

		    					}

		    				}

		    				

		    				

		    				if($$('#soundlist li').length==0)

		    					$('killemall').hide();

		    				

		    				if($('toggle_unattended').hasClassName('active') && $$('#soundlist li').length==0)

		    					toggleUnattendedMode();

		    			},

		      onstop:function(){			

		    	  if($(this.sID).hasClassName('child'))

		    		  playNext(this.sID);

		    	  else

		    		  $(this.sID).remove();

		    	  

		    	  updateMarker(this.sID.match(/\d+/), false, 'images/single-played.png');

		      

		    	  if($$('#soundlist li').length==0){

					$('killemall').hide();

					

					if(!mapMoved){

						map.setCenter(initialCentre);

						map.setZoom(initialZoom);

					}

		    	  }

		    	  

		    	  if($('toggle_unattended').hasClassName('active') && $$('#soundlist li').length==0)

  					toggleUnattendedMode();

		    	  

		    	}
			
		    }
		    

		);



}



// Plays next sound in the sequence. Called by sound manager object's onfinish event

function playNext(id){

	$(id).addClassName('played');

	

	if($(id).hasClassName('parent')){

		if($$('#'+id+' .notplayed').length > 0)

			soundManager.play($$('#'+id+' .notplayed')[0].id, {volume:defaultVolume});

		else

			$('id').remove();

	}

	

	if($(id).hasClassName('child')){

		if($(id).nextSiblings().length > 0)

			soundManager.play($(id).nextSiblings()[0].id, {volume:defaultVolume});

		else{

			var sound = sounds[getSoundIndex($(id).up(1).id.match(/\d+/))];

			

			// Return to start position if the last location is not contained by the map bounds 

			if(!map.getBounds().contains(sound.marker.getPosition())){

				map.panTo(new google.maps.LatLng(sound.lat,sound.lng));

				map.setZoom(parseInt(sound.zoom_level));

			}

			

			$(id).up(1).remove();

		}

	}

}





function toggleUnattendedMode(){

	

	// do nothing if we're in edit mode

	if($('tabContent3').visible()){

		clearTimeout(inactivityTimer);

		return null;

	}

		

	var timeOut=1000; // timeout for unattended mode, millis between sounds

	var unattendedMode = $('toggle_unattended').hasClassName('active');

	

	removeAllSounds();

	sounds.each(function(s){

		if(getChildren(s.id).length > 0)

			updateMarker(s.id, false,'images/pink-dot.png');

		else

			updateMarker(s.id, false,'images/blue-dot.png');

	});

	

	

	$('navigatetext').clear();

	activeFilters=new Array();

	applyFilters(true);

	

	

	// leaving unattended

	if(!unattendedMode){

		map.setCenter(new google.maps.LatLng(defaultLat,defaultLng));

		map.setZoom(defaultZoom);

		

		setMarkerListeners(playSound, 'blue', false);

	}

	

	

	

	if(inactivityTimer)

		clearTimeout(inactivityTimer);

	

	if(unattendedMode){

		setMarkerListeners(null, 'blue', false);

		inactivityTimer= window.setTimeout(function(){

											if($$('#soundlist li').length == 0){

												activeFilters=new Array();

												applyFilters(true);

												playRandom();

											}

										}

	, timeOut);

	}

}



function playRandom(){

	var randomSound=getRandomSound();



	playSound(null,randomSound);

}



// gets random sound from the array

function getRandomSound(){

	return sounds[Math.floor(Math.random()*sounds.length+1)];

}



// Takes the first search result and centers map on that location

function navigateToAddress()

{

	var address = $('navigatetext').value;

	

    if (geocoder) {

		geocoder.geocode( { 'address': address}, 

							function(results, status) {

								if (status == google.maps.GeocoderStatus.OK){ 

									map.setCenter(results[0].geometry.location);

									map.fitBounds(results[0].geometry.viewport);

								

								    // reset filters

									activeFilters=new Array();

									applyFilters(true);

								}

								else 

									alert("Geocode was not successful for the following reason: " + status);

								

					});

    }



}





// Builds dynamic parts of upload form

function buildUploadForm(filters, filterTypes){

	// remove current filters

	filterTypes.each(function(s){

						$$('#'+s+'fields div').each(function(e){e.remove();});

	});

	

	filters.each(function(s){

					if(s.type=='project'){

						var container = new Element('div');

						var checkBox = new Element('input', {'type':'checkbox', 'id':s.type+'_'+s.id,'name':s.type+'_list[]','value':s.id});

						var label = new Element('label', {'for':s.type+'_'+s.id}).update(s.name);

						var edit = new Element('a',{'href':'javascript:void(0)','id':s.type+'_'+s.id}).update(' [edit]');

						container.insert(checkBox);

						container.insert(label);

						container.insert(edit);

						

						// show and populate edit form

						edit.observe('click', showEditFilter.bind(edit, s.name));

							

						$(s.type+'fields').insert(container, {after:$(s.type+'header')});

					}

					else if(s.type=='user'){	

						var userOption = new Element('option', {'value':s.id}).update(s.name);

						$('authorid').appendChild(userOption);

					}

				});

	

	

	

	buildParentSounds();

}



//Add parent sounds drop down

function buildParentSounds(selectedId){

	// Clear existing values

	$$('#parent_id option').each(function(s){ s.remove(); });

	

	var parentSounds = sounds.findAll(function(s){

		return s.parent_id==0;

	});

	

	parentSounds.sort(function(a,b){

		var x = a.name.toLowerCase();

	    var y = b.name.toLowerCase();

	    return ((x < y) ? -1 : ((x > y) ? 1 : 0));

		

	});

	

	$('parent_id').insert(new Element('option').update('none'));

	

	parentSounds.each(function(s){

		$('parent_id').insert(new Element('option',{'value':s.id}).update(s.name));

	});

	

	if(selectedId){

		$$('#parent_id option').each(function(o){

			if(o.value==selectedId){

				o.selected=true;

			}

		});	

	}

}



function showEditFilter(filterValue)

{

	// Clear event handlers

	$('editfilterform').stopObserving();

		

	var filterType = this.id.match(/project|tag|user/);

	var filterId = this.id.match(/\d+/);

	

	$('filtertype').value=filterType;

	$('filterid').value=filterId;

	

	tinyMCE.activeEditor.setContent('');

	

	// Display appropriate fields

	if(filterType=='user'){ 

		$('operation').value='adduser';

		$('filtermanagement').hide();

		$('usermanagement').show();

		

		$('editfieldslegend').update('manage users');

	}else{

		$('filtermanagement').show();

		$('usermanagement').hide();

		

		filterId ? $('operation').value='updatefilter': $('operation').value='addfilter'; 

		filterId ? $('delete').show() : $('delete').hide();

		typeof filterValue=='string' ? $('filtername').value=filterValue : $('filtername').value=''; 

		

		if(filterType=='project'){

			$('tagmanagerfields').hide();

			$('projectmanagerfields').show();

			$('editfieldslegend').update('add new '+filterType);

			

			// set description and multiplay

			projects.each(function(s){

				if(s.id==filterId){

					s.description ? tinyMCE.activeEditor.setContent(s.description) : tinyMCE.activeEditor.setContent('');

					s.multiplay==1 ? $('multiplay').checked=true : $('multiplay').checked=false; 

				}

			});

		}

		else{

			$('editfieldslegend').update('edit '+filterType);

			

			if(this.id=='manage_tags'){

				$('projectmanagerfields').hide();

				$('tagmanagerfields').show();

				$('delete').hide();

			}

		}

	}

	

	

	Effect.Appear('editcontainer',{duration:0.5});

	$('editfilterform').observe('submit',function(e){

													

													

													// If deleting display confirm

													var confirmDelete=false;

													

													if($('operation').value=='deleteuser' || $('operation').value=='deletefilter')

														confirmDelete = confirm("You are about to delete " + filterType + " "+$('filtername').value+". \nDo you wish to continue?");

													else

														confirmDelete = true;

													

													if(confirmDelete){

														new Ajax.Request('php/edit.php',

																{

																	parameters:$('editfilterform').serialize(),

																	onSuccess: function(transport){

																					var result=processAjax(transport);

																					

																					if(result.status){

																						buildFilters(result.filters,[filterType]); // rebuild filter list

																						buildUploadForm(result.filters,[filterType]); // rebuild upload

																						Effect.Fade('editcontainer',{duration:0.5});

																						$('editfilterform').reset();

																					}

																					

																					alert(result.message);

																				},

																	onFailure:function(){

																					alert("an error occured when updating the filter");

																					Effect.Fade('editcontainer',{duration:0.5});

																				}

																});

														

													}

												});



	

}



//AJAX response handler which adds filter drop-downs to the DOM

//and binds each item's click event to addFilter()

function buildFilters(filters,filterTypes){

	

	// clear existing

	filterTypes.each(function(s){ 

		$$('#'+s+'_filters .notall').each(function(e){e.remove();} );

		Event.observe($(s+'_all'),'click',addFilter.bindAsEventListener());

		

		if(s=='project')

			projects = new Array();

		

		// clear tag manager values

		if(s=='tag')

			$$('#taglist a').each(function(s){s.remove();});

		

		if(s=='user'){

			users=new Array();

			

			// clear authors in upload form

			$$('#authorid option').each(function(s){

				if(s.value!='')

					s.remove();

			});

			

			// clear user management form

			$$('#manageruser option').each(function(s){s.remove();});

			$('manageruser').insert(new Element('option', {'value':''}).update('-select existing user to edit details-'));

		}	

	});

	

	filters.each(function(s){

			var container = new Element('li',{'class':'notall ' + s.type});

			var filterLink = new Element('a', {'href':'javascript:void(0);', 'class':s.type,'id':s.type+'__'+s.id}).update(s.name);

			container.insert(filterLink);

			$(s.type+'_filters').insert(container);

			

			// add click handler

			filterLink.observe('mouseup', addFilter.bindAsEventListener());

			

			if(s.type=='project')

				projects.push(s);

			

			

			

			// Build tag manager form

			if(s.type=='tag'){

				var tagmanager = new Element('a',{'href':'javascript:void(0);','id':'tagmanager_'+s.id});

				tagmanager.update(s.name);

				

				$('clearing').insert({before:tagmanager});

				tagmanager.observe('click',function(){

					this.toggleClassName('managerselected');

					$('filterid').value=this.id.match(/\d+/);

					$('filtername').value=this.innerHTML;

					$('operation').value='updatefilter';

					$('delete').show();

				});

			}

			

			// add users to user manager form

			if(s.type=='user'){

				var userOption = new Element('option',{'value':s.id}).update(s.name);

				$('manageruser').insert(userOption);

		

				users.push(s);

				

				// check logged on user

				if(userId && userId==s.id){

					loggedOnUser=s;

					$('manage_users').show();

				}

			}

			

	});

}



//Adds filter to active filter list and removes any existing filters that are of the same type

function addFilter(){

	var element=$A(arguments)[0].element();

	var filterType = element.id.match(/[^_]*/)[0];

	var filterId = element.id.match(/\d+/);

	

	// If changing project, then clear tag and author filters

	if(filterType=='project'){

		$$('#project_filters a').each(function(s){s.show();});

		

		activeFilters=new Array();

		$$('#tag_filters a').each(function(s){s.removeClassName('filterselected');});

		$$('#user_filters a').each(function(s){s.removeClassName('filterselected');});

		

		$$('#tag_filters a.all')[0].addClassName('filterselected');

		$$('#user_filters a.all')[0].addClassName('filterselected');

		

		if(filterId){

			$('project__'+filterId).hide();

		}

		else{

			$('project_all').hide();

			$('aboutcontainer').hide();

			$('defaultblurb').show();

		}

		

		// display project description and set multiplay variable

		projects.each(function(s){

			if(s.id==filterId){

				$('aboutcontainer').update(s.description.gsub(/\\"/,'"'));

				$('aboutcontainer').show();

				$('defaultblurb').hide();

				

				if((s.multiplay==1))

					$('toggle_multiplay').addClassName('active');

				else

					$('toggle_multiplay').removeClassName('active');

			

			}

		});

	

	}

	

	

	

	$$('#'+filterType+'_filters a').each(function(s){

		s.removeClassName('filterselected')

	});

	

	element.addClassName('filterselected');

	

	if(filterType=='project'){

		Effect.BlindUp(filterType+'_filters', {duration:0.1});

		$('selected_'+filterType).update(element.innerHTML);

		$('selected_'+filterType).show();

	}

	// remove existing filters of the same type

	activeFilters.each(function(s){

		if(s.type==filterType)

			activeFilters.splice(activeFilters.indexOf(s), 1);

	

	});

	

	if(filterId)

		activeFilters.push({id:filterId,type:filterType});

		

	applyFilters();

}







//Filters map marker/active sounds based on active filters

function applyFilters(noBounds)

{	

	// reset visibilty of all markers before applying filters

	sounds.each(function(s){s.marker.setVisible(true);});



	

	// Reset selected filters to "all" if no active filters

	if(activeFilters.length==0){

		$$('.filterselected').each(function(s){s.removeClassName('filterselected');});

		$$('.all').each(function(s){s.addClassName('filterselected');});

	}

	

	activeFilters.each(function(s){

							if(s.type != 'user'){

								for(var i=0; i < sounds.length; i++)

								{	

									var isMatch=false;

									for(var j=0; j < eval('sounds[i].'+s.type+'.length'); j++){

										if(s.id == eval('sounds[i].'+s.type+'[j].id') && sounds[i].marker.getVisible()){

											isMatch=true;

											break;

										}		

									}

									sounds[i].marker.setVisible(isMatch);

								}	

							}else{

								for(var i=0; i < sounds.length; i++)

								{	

									var isMatch=false;

								

									if(s.id == sounds[i].user_id && sounds[i].marker.getVisible()){

										isMatch=true;

									}		

								

									sounds[i].marker.setVisible(isMatch);

								}

							}		

	});	

	

	// we don't always want to set bounds when applying filters

	if(noBounds==null){

		var visibleMarkers=new Array();

		var tagFilterOn = activeFilters.findAll(function(s){return s.type=='tag'}).length;

		

		sounds.each(function(s){

						// Include only visible markers and top-level sounds, or all markers if the tag filter has been selected

						if(s.marker.getVisible() && (s.parent_id==0 || tagFilterOn))

							visibleMarkers.push(s.marker);

					});

		

		if(visibleMarkers.length > 0)

			setBounds(visibleMarkers);

		else

			alert('The selected combination of project/tag/recordist does not match any sounds. \nTry widening your search by selecting "all" for either project, tag or recordist.');

	}

}



// Searches through visible markers and sets zoom level and map centre

// so that all visible markers are in the viewport

function setBounds(markers){

	var maxNorth=90; // North pole

	var maxEast=180; // far east 

	

	var minNorth = -90; // south pole

	var minEast = -180; // far west

	

	// find max and min for visible markers

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

		if (maxNorth > markers[i].getPosition().lat())

			maxNorth=markers[i].getPosition().lat();

	

		if (maxEast > markers[i].getPosition().lng())

			maxEast = markers[i].getPosition().lng();

		

		if (minNorth < markers[i].getPosition().lat())

			minNorth=markers[i].getPosition().lat();

	

		if (minEast < markers[i].getPosition().lng())

			minEast=markers[i].getPosition().lng();

	}

	

	var ne = new google.maps.LatLng(minNorth, minEast);

	var sw = new google.maps.LatLng(maxNorth, maxEast);

	

	var bounds = new google.maps.LatLngBounds(sw,ne);

	

	map.fitBounds(bounds);

	

	// Use custom overlay to ensure that markers are not hidden under nav area

	overlay = new NavigationOverlay(map, bounds, map.getZoom());	

}







// Remove filter for selected filter type

function removeFilter()

{

	var event=$A(arguments)[0];

	var filterType=$A(arguments)[1];                   

	

	for(var i=0; i<sounds.length;i++)

		sounds[i].marker.setVisible(true);

}







// Removes all sounds from list and stops playing

function removeAllSounds()

{	

	soundManager.stopAll();

	$('killemall').hide();



}



// Add markers to the map

function createMarker(sound)

{		

	var iconURL='images/single.png';

	

	if(getChildren(sound.id).length>0)

		iconURL='images/sequence.png';

	

	var markerImage = new google.maps.MarkerImage(iconURL, null, null, new google.maps.Point(7,7));

	

	var markerOptions = { 

			position: new google.maps.LatLng(sound.lat, sound.lng),

			title:sound.name,

			icon: markerImage,

			map:map,

			draggable: false,

			clickable: true,

			dragCrossMove: true,

			flat:false,
			
			optimized:false

			};

	

	var marker = new google.maps.Marker(markerOptions);

	

	google.maps.event.addListener(marker, 'mouseup', function() {playSound(null, sound);});

	sound.marker=marker;

	return marker;

}



// Get children

function getChildren(parentId){

	var children=new Array();

	

	sounds.each(function(s){

		if(s.parent_id==parentId)

			children.push(s);

	});

	

	return children;

}





// Plays sound and adds it to the sound list. Note the

// obj parameter which is the event triggered the function - this is provider

// by prototype's bindAsEventListener().

function playSound(obj, sound)

{

	if(!$('sound_'+sound.id)){	

		var isSequencePlaying = ($$('#soundlist .parent').length > 0);

		

		if(!$('toggle_multiplay').hasClassName('active') || getChildren(sound.id).length > 0 || isSequencePlaying)

			soundManager.stopAll();	

		

		addToSoundList(null, sound);

		sound.smSound.play({volume:defaultVolume});

		//updateMarker(sound.id, true);

	}else{

		updateMarker(sound.id, false);

		soundManager.stop('sound_'+sound.id);

	}

}



// Function changes marker icon depending on active state of sound

function updateMarker(id, isActive, iconUrl) {

	var ACTIVE_MARKER_URL = 'images/active.gif';

	var INACTIVE_MARKER_URL='images/single.png';

	

	if(iconUrl)

		INACTIVE_MARKER_URL=iconUrl;

	else if($('editmode').checked)

		INACTIVE_MARKER_URL = 'images/yellow-dot.png';

	

	

	if(getChildren(id).length > 0)

		INACTIVE_MARKER_URL='images/sequence-played.png';

	

	var markerImage = new google.maps.MarkerImage(

			isActive?ACTIVE_MARKER_URL:INACTIVE_MARKER_URL,

			null, 

			null,

			new google.maps.Point(7,7)

		);
	

	//update marker to playing icon

	for(var i=0; i < sounds.length; i++)

		if(sounds[i].id==id)

			sounds[i].marker.setIcon(markerImage);

		

	

}





// add title, description, volume slider and mute button to active sound list

// note that obj is used by prototype's bindAsEventListener to pass the event object

function addToSoundList(obj, sound)

{	

	var soundContainer = new Element('li',{'id':'sound_'+sound.id}); // container for slider and text description

	soundContainer.insert(getSoundTitle(sound));

	soundContainer.insert(getSoundDescription(sound)); 

	soundContainer.insert(getSlider(sound.id, 150));

	soundContainer.insert(getStopButton(sound));

	soundContainer.insert(new Element('p',{id:'duration_'+sound.id}));



	$('soundlist').insert(soundContainer);

	$('killemall').show();

	

	// now add children (if any)

	var children = getChildren(sound.id);

	var childList=new Element('ul',{'id':'children_'+sound.id});

	

	if(children.length > 0){

		soundContainer.insert(childList);

		soundContainer.addClassName('parent');

	}	

	

	children.each(function(s){

				var childSound = new Element('li',{'id':'sound_'+s.id});

				childSound.addClassName('notplayed');

				childSound.addClassName('child');

				childSound.insert(getSoundTitle(s));

				childSound.insert(getSoundDescription(s));

				childSound.insert(getSlider(s.id, 145));

				childSound.insert(getStopButton(s));

				childSound.insert(new Element('p',{id:'duration_'+s.id}));

				childList.insert(childSound);

	   });



}



// returns 

function getSoundTitle(sound){

	 	

	var soundTitle = new Element('div',{'id':'title_'+sound.id}).update(sound.name);

	soundTitle.addClassName('activetitle');

	

	return soundTitle;

}



function getSoundDescription(sound){

	var description = sound.description;

	

	if(!sound.description)

		description='';

	

	if(sound.recording_date)

		description+=' '+sound.recording_date;

	

	if(sound.user_name)

		description+=' '+sound.user_name;

	

	return new Element('p',{'class':'sounddescription'}).update(description);

}



// Creates new slider element for the given sound id

function getSlider(soundId, sliderWidth){

	// Create new slider vol control

	var volumeSlider = new Element('div',{'id':'slider_'+soundId,'class':'slider'});

	var volumeHandle = new Element('div',{'id':'handle_'+soundId,'class':'handle'});

	  

	// Note - height and width styles are added here as sliders don't get initialised properly

	// when hidden if these attribs assigned using CSS

	volumeHandle.style.cssText='height:13px;width:8px;margin-top:-4px';

	volumeSlider.insert(volumeHandle);

	  

	// See above

	volumeSlider.style.cssText='width:'+sliderWidth+'px;height:5px;';

	

	var slider = new Control.Slider(

				volumeHandle, 

				volumeSlider, 

				{

					range: $R(0, 100),

					sliderValue: defaultVolume,

					onSlide: 	function(value) {

									soundManager.setVolume('sound_'+soundId,Math.floor(value));

								},

					onChange: 	function(value) { 

									soundManager.setVolume('sound_'+soundId,Math.floor(value));

								}

				});



	  

	return volumeSlider;

}



// Creates a new stop button for each sound

function getStopButton(sound){

	var removeButton = new Element('a',{'id':'remove_sound_'+sound.id,'value':sound.id,'href':'javascript:void(0);'}).update('stop');

	Event.observe(removeButton,'mouseup', function(){sound.smSound.stop();});

	removeButton.addClassName('stopbutton');

	return removeButton;

}



// Searches global sounds array and returns its array index 

function getSoundIndex(id){

	var i=0;

	

	while(id != sounds[i].id)

		i++;	

	

	return i;

}



// Deletes DOM element containing sound details and slider

function removeFromSoundList(id){

	$('sound_'+id).remove();

}



// check if sound is currently active

function isActive(id)

{

   for (var i=0; i < activeSounds.length; i++)

	   if (activeSounds[i] == id)

		   return true;

  

}



// Displays and centres messages that are displayed while waiting for AJAX response

function showWaitingMessage(message, transparentBackground, topPosition)

{

	$('waitingmessage').update(message);

	$('waitingblock').show();

	

	var marginLeft=-($('waitingmessage').getWidth()/2)+'px;';

	

	$('waitingmessage').style.cssText='top:'+topPosition+'%;background-color:#000;z-index:-1;opacity:1;margin-left:'+marginLeft;

	

	if(transparentBackground)

		$('waitingblock').style.cssText='z-index:1;background-color:transparent;';

}



// Evals JSON response and handles escaped chars

function processAjax(ajaxResponse){

	

	result=ajaxResponse.responseText.gsub(/\\'/, "'").evalJSON(true); 

	return result;

}



/*-----------------------------------------------------------

Toggles element's display value

Input: any number of element id's

Output: none 

---------------------------------------------------------*/

function toggleDisp() {

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

	    var d = $(arguments[i]);

	    

	    if (d.style.display == 'none')

	        d.style.display = 'block';

	    else

	        d.style.display = 'none';

	}

}



/*-----------------------------------------------------------

Toggles tabs - Closes any open tabs, and then opens current tab

Input:     1.The number of the current tab

                2.The number of tabs

                3.(optional)The number of the tab to leave open

                4.(optional)Pass in true or false whether or not to animate the open/close of the tabs

Output: none 

---------------------------------------------------------*/

function toggleTab(num,numelems,opennum,animate) {

	if ($('tabContent'+num).style.display == 'none'){

	    for (var i=1;i<=numelems;i++){

	        if ((opennum == null) || (opennum != i)){

	            var temph = 'tabHeader'+i;

	            var h = $(temph);

	            if (!h){

	                var h = $('tabHeaderActive');

	                h.id = temph;

	            }

	            var tempc = 'tabContent'+i;

	            var c = $(tempc);

	            if(c.style.display != 'none'){

	                if (animate || typeof animate == 'undefined')

	                    Effect.toggle(tempc,'appear',{duration:0.5, queue:{scope:'menus', limit: 3}});

	                else

	                    toggleDisp(tempc);

	            }

	        }

	    }

	    var h = $('tabHeader'+num);

	    if (h)

	        h.id = 'tabHeaderActive';

	    h.blur();

	    var c = $('tabContent'+num);

	    c.style.marginTop = '2px';

	    if (animate || typeof animate == 'undefined'){

	        Effect.toggle('tabContent'+num,'blind',{duration:0.5, queue:{scope:'menus', position:'end', limit: 3}});

	    }else{

	        toggleDisp('tabContent'+num);

	    }

	}

}


