/*global $, jQuery, window, swfobject, testId */
/**
 * jQuery Audio plugin
 * @package		jQuery audio
 * @copyright	Copyright (C) 2010 Mark Lynch / http://www.learnosity.com
 * @license		Released under the MIT, BSD, and GPL Licenses.
 * 
 * 
 * Usage:
 * <a type="text" class="playback" id="audio_[i]" href="[mp3 url]">
 *		optional wave image
 *		or <span class="audiobtn btnplay"></span> - this currently requires that you add exemplar class to the parent href. Should be refactored when a need arises. 
 * </a>
 * or
 * <input type="text" class="recorder" id="audio_[i]">
 * 
 * jQuery('.recorder').audioRecorder();
 * jQuery('.player').audioPlayer();
 * 
 * Note jquery swfobject must be loaded before this
 */

(function($) {
	var controlState = 'stopped',
		currentControl,
		mp3url,
		opts,
		swf;
	
	
	/*********************************************/	
	/* Common Functions
	 *********************************************/
	var commonUI = {
		js2flex: function(options) {
			try {
				swf = document.getElementById('audiocontrol');			
				var retObj = swf.js2flex(options);
				
				return retObj;
			} catch(err) { }
		},
		resetAudio: function() {
			if (controlState == 'playing' || controlState == 'recording') {
				currentControl.siblings('.btnstop').trigger('click');
			} else if (controlState == 'playback' && currentControl.hasClass('playing')) {
				playBackUI.events.stop(currentControl);
			} else if (controlState == 'setupRecording') {
				currentControl.removeClass('loading').empty()
			} else if (controlState == 'deleted') {
				recorderUI.disable('btndelete');
			}
		}
	};
	function handleError(msg) {
		recorderUI.enable('btnerror');
		$('.btnerror').attr('alt', msg).attr('title', msg).fadeIn();
	}
	
	
	/*********************************************/	
	/* Audio PlayBack
	 *********************************************/
	var audioplayerDefaults = {
		swf: '/commonskins/base/swf/JSAudioRecorder.swf',
		startupCheckTime: 200
	};
	
	
	$.fn.audioPlayer = function(options) {				
		var selfaudio = this;
		opts = $.extend({}, audiorecorderDefaults, audioplayerDefaults, opts, options);
		
		$(document).bind('flashready', function() {
			return selfaudio.each(function() {
				playBackUI.init(this);
			});
		});
		
		doSwfSetup(opts);
	};
	
	$.fn.audioPlayerInit = function() {				
		var selfaudio = this;
		
		if(swf.js2flex) {
			return selfaudio.each(function() {
				playBackUI.init(this, true);
			});
		} else {		
			$(document).bind('flashready', function() {
				return selfaudio.each(function() {
					playBackUI.init(this, true);
				});
			});
		}
	};
	
	var playBackUI = {
		duration: 0,
		init: function(self, dynamicInit) {
				var player = $(self);
				player.click(function(e){
					e.preventDefault();
					var scopedState = controlState;
					commonUI.resetAudio();
					playBackUI.events.click(player, scopedState);
				});	
				if (!dynamicInit) {
					currentControl = player;
				}
		},
		uiHtml: '<div class="timer">' +
				   '<span class="current">00:00</span> / <span class="total">--:--</span>' +
				'</div>' +
				'<div class="statusbar"><div>' +
				   '<div class="loaded"></div>' +
				   '<div class="progress"></div>' +
				'<div></div>',
		initProgress: function(player) {
			if(!player.has('.timer').length)
				player.append(playBackUI.uiHtml);
				
			player.find('.statusbar > div').click(function(e) {
				e.preventDefault();
				playBackUI.positionClick(e, this);
			});
			
			this.updateProgressUI(player);
			player.children('.timer').slideDown();
			player.children('.statusbar').slideDown();
		},
		time: function(msecs) {
			var mins = Math.floor((msecs / 60000) % 60);
			var secs = Math.floor((msecs / 1000) % 60);
			
			mins = mins < 10 ? '0' + mins : mins;
			secs = secs < 10 ? '0' + secs : secs;

			return mins + ':' + secs; 
		},
		totalTime: function(data) {
			this.duration = parseInt((data.total / data.loaded) * data.duration, 10);
			return this.duration;
		},
		updateProgressUI: function(player) {
			var progressBar = player.find('.progress');
			var progressTime = player.find('.current');
			
			function update() {
				var currentTime = commonUI.js2flex({cmd: 'currentPosition'});
				progressTime.html(playBackUI.time(currentTime));
				
				var width = currentTime / playBackUI.duration * 100;
				progressBar.width(Math.round(width) + '%');

				if(controlState == 'playback') {
					setTimeout(update, 100);
				}
			}
			update();
		},
		positionClick: function(e, elm) {
			e.stopPropagation();
			var position = Math.round((e.layerX ? e.layerX : e.offsetX) / $(elm).width() * this.duration);
			commonUI.js2flex({cmd: 'playMP3', position: position});
			this.updateProgressUI(currentControl);
		},
		events: {
			update: function(player, data) {
				player.find('.total').html(playBackUI.time(playBackUI.totalTime(data)));
				player.find('.loaded').width(data.loaded / data.total * 100 + '%');
			},
			click: function(player, scopedState) {
				if(currentControl[0] != player[0] || scopedState == 'stopped') {
					this.play(player);
				}
				currentControl = player;
			},
			play: function(player) {
				commonUI.js2flex({cmd: 'playMP3',file: player.attr('href')});
				player.addClass('playing');
				controlState = 'playback';
				playBackUI.initProgress(player);
			},
			stop: function(player) {
				commonUI.js2flex({cmd: 'stopMP3'});
				if(controlState == 'playback') {
					player.removeClass('playing');
					player.children('.timer').slideUp();
					player.children('.statusbar').slideUp();
				}
				controlState = 'stopped';
			}
		}
	};
	
	
	
	/*********************************************/	
	/* Audio Recorder
	 *********************************************/
	var audiorecorderDefaults = {
		rtmpURI: 'rtmp://localhost/voiceRecorderffff',
		swf: '/commonskins/base/swf/JSAudioRecorder.swf',
		mp3baseurl: '/assets/',
		prefix: '',
		startupCheckTime: 200,
		onSave: undefined,
		onDelete: undefined
	};
	
	$.fn.audioRecorder = function(options) {
		var self = this;
		opts = $.extend({}, audiorecorderDefaults, audioplayerDefaults, opts, options);

		doSwfSetup(opts);
		
		$(document).bind('flashready', function() {
			return self.each(function() {
				var audioInput = $(this);
				audioInput.wrap('<div class="audiocontrols"></div>');
				
				var buttons = {
					btnrec: $("<span class='btnrec audiobtn' title='Record' alt='Record'></span>"),
					btnplay: $("<span class='btnplay audiobtn disabled' title='Play' alt='Play'></span>"),
					btnstop: $("<span class='btnstop audiobtn disabled' title='Stop' alt='Stop'></span>"),
					btndelete: $("<span class='btndelete audiobtn disabled' title='Delete' alt='Delete'></span>"),
					btnerror: $("<span class='btnerror audiobtn disabled'></span>")
				};
				
				buttons.btnrec.click(recorderUI.events.btnrec);
				if(audioInput.val() !== '') {
					buttons.btnplay.click(recorderUI.events.btnplay).removeClass('disabled');
					buttons.btndelete.click(recorderUI.events.btndelete).removeClass('disabled');
					mp3url = opts.mp3baseurl + audioInput.attr('value') + '.mp3';
				}
				
				$.each(buttons, function(index, value) {
					var button = $(this);
					audioInput.before(this);
				});
				
				currentControl = buttons.btnstop;
			});
		});
	};

	var recorderUI = {
		disableAll: function() {
			var btns = currentControl.parent().children('span');
			$.each(btns, function(index, value) {
				$(this).unbind('click', recorderUI.events[index]);
			});
			btns.addClass('disabled');
		},
		disable: function() {
			var btns;
			for(var i = 0; i < arguments.length; i++) {
				btns = currentControl.parent().children('.' + arguments[i]);
				btns.unbind('click', recorderUI.events[arguments[i]]);
				btns.addClass('disabled');
			}
		},
		enable: function() {
			var btns;
			for(var i = 0; i < arguments.length; i++) {
				btns = currentControl.parent().children('.' + arguments[i]);
				btns.bind('click', recorderUI.events[arguments[i]]);
				btns.removeClass('disabled');
			}
		},
		requestAuthentication: function(showPrivacySettings) {
			if(showPrivacySettings) {
				commonUI.js2flex({cmd:'showPrivacySettings'});
				
			} else {
				this.swfnotice = $('#audiocontroldiv .swfnotice').html();
				$('#audiocontroldiv .swfnotice').html('<br/><br/>We\'ve been unable to access flash. Please ensure a blocker<br/> is not enabled and that you have the latest version of flash.');
			}
			
			$('#audiocontroldiv').css('left', '520px');
			$('#audiocontrol').focus();
		},
		hideAuthentication: function() {
			$('#audiocontroldiv .swfnotice').html(this.swfnotice);
			$('#audiocontroldiv').css('left', '-9999px');
			//MT: 24/Jun/2011 Throws an error.
			//currentControl.focus();
		},
		setupRecording: function() {
			controlState = 'setupRecording';
			if(!commonUI.js2flex({cmd:'isMicAuthorised'})) {
				recorderUI.requestAuthentication(true);
			} else if(!commonUI.js2flex({cmd:'isConnected'})) {
				commonUI.js2flex({cmd: 'connect',URI: opts.rtmpURI});
			} else {
				commonUI.js2flex({cmd:'playMP3',file:'/commonskins/base/audio/beep.mp3'});
			}
		},
		loading: function(scopedControl) {
			scopedControl.addClass('loading');
			scopedControl.append('<img src="/commonskins/base/images/audiorecorder/loading.gif" title="Processing audio, please wait" alt="Processing audio, please wait">');
		},
		mp3Ready: function(callback) {
			recorderUI.loading(currentControl.siblings('.btnplay'));
			setTimeout(fileExists, 1000);
			
			var i = 0;
			function fileExists() {
				var mp3Timeout;
				$.ajax({
				    url: mp3url,
				    type: 'HEAD',
				    error: function() {
						mp3Timeout = setTimeout(fileExists, 500);
					},
				    success: function() {
						if(mp3Timeout) {
							clearTimeout(mp3Timeout);
						}
						callback();
					}
				});
			}
		},
		flashRecBtn: function(recBtn) {
			var self = this;
			
			function flash() {
				$(recBtn).toggleClass("disabled");
				self.flashTimeout = setTimeout(flash, 1000);
			}
			flash();
		},
		events: {
			btnrec: function() {
				commonUI.resetAudio();
				currentControl = $(this);
				
				if(controlState == 'recordReady') {
					currentControl.removeClass('loading').empty();
					recorderUI.flashRecBtn(currentControl);
					
					controlState = 'recording';
					recorderUI.disableAll();
					recorderUI.enable('btnstop');
					currentControl.siblings('input').attr('value','');
					commonUI.js2flex({cmd:'record'});
				} else {
					recorderUI.loading(currentControl);
					recorderUI.setupRecording();
				}
			},
			btnplay: function() {
				commonUI.resetAudio();
				currentControl = $(this);
				
				recorderUI.disableAll();
				recorderUI.enable('btnstop');
				
				mp3url = opts.mp3baseurl + currentControl.siblings('input').attr('value') + '.mp3';
				commonUI.js2flex({cmd:'playMP3',file:mp3url});

				controlState = 'playing';
			},
			btnstop: function() {
				currentControl = $(this);
				recorderUI.disableAll();
				commonUI.js2flex({cmd:'stop'});
				if(currentControl.siblings('input').attr('value') !== '') {
					recorderUI.enable('btndelete');
				}
				if(controlState == 'recording') {
					clearTimeout(recorderUI.flashTimeout);
					var curFileName = commonUI.js2flex({cmd:'getFilename'});
					currentControl.siblings('input').attr('value',curFileName);
					mp3url = opts.mp3baseurl + currentControl.siblings('input').attr('value') + '.mp3';
					
					if(opts.onSave) {
						opts.onSave(curFileName);
					}
					
					var scopedControl = currentControl;
					recorderUI.mp3Ready(function() {
						scopedControl.siblings('.btnplay').removeClass('loading').empty();
						var orgCurrentControl = currentControl;
						currentControl = scopedControl;
						recorderUI.enable('btnplay', 'btndelete', 'btnrec');
						currentControl = orgCurrentControl;
					});
				} else if(controlState == 'playing') {
					recorderUI.enable('btnplay', 'btnrec');
					commonUI.js2flex({cmd:'stopMP3'});
				} else if(controlState == 'deleted') {
					recorderUI.enable('btnrec');
				}
				controlState = 'stopped';
			},
			btndelete: function() {
				currentControl = $(this);
				if(window.confirm("Are you sure you wish to delete this audio file?")){
					currentControl.siblings('input').attr('value',"");
					controlState = 'deleted';
					commonUI.resetAudio();
					if(opts.onDelete){
						opts.onDelete();
					}
				}
			},
			btnerror: function() {
				if(!commonUI.js2flex({cmd:'isConnected'})){
					commonUI.js2flex({cmd:'connect',URI:opts.rtmpURI});
					recorderUI.disable('btnerror');
					$('.btnerror').hide();
				}
			}
		}
	};
	

	/*********************************************/	
	/* Flash Core (js2flex function also needed)
	 *********************************************/
	$.fn.audio = {};
	var flashCheckCount = 0,		
	flashCeckTimeout,
	flashready = false;
	
	$.fn.audio.flexCallHandler =  function(o) {
		if (!handleError) {
			var handleError  = function(msg) { alert(msg) };
		}
		
		switch(o.e) {
			case "micUnmuted":
					recorderUI.hideAuthentication();
					currentControl.trigger('click');
				break;
			case "connected":
					$('.btnerror').hide();
					if(controlState == 'setupRecording') {
						currentControl.trigger('click');
					}
				break;
			case "mp3PlayComplete":
					if(controlState == 'setupRecording') {
						controlState = 'recordReady';
						currentControl.trigger('click');
					} else if (currentControl.hasClass('playback')) {
						playBackUI.events.stop(currentControl);
					} else {
						commonUI.resetAudio();
						currentControl = $(this);
					}
				break;
			case "mp3LoadProgress":
				if(currentControl.hasClass('playback')) {
					playBackUI.events.update(currentControl, o);
				}
				break;
			case "mp3LoadFailed":
					handleError('Audio not currently available:\n' + mp3url);
				break;
			case "diconnected":
					handleError('Disconnected from audio sever. Click to try again.');
				break;
			case "connectionfailed":
					handleError('Connection failed to audio sever. Click to try again.');
				break;
			case "invalidApp":
					handleError('Invalid Application, could not connect.');
				break;
		}
	};
	
	function doSwfSetup(opts) {
		if(!swf) {
			$('body').append('<div id="audiocontroldiv"><span id="audiocontrol"></span><span class="swfnotice"><br /><br />To record Audio you must select Allow above. <br />Select \'Remember\' to stop this dialog coming up every time <br /></span><a href="javascript:void(0);" class="closeSwf" title="Close This Window"></a></div>');
			$(".closeSwf").bind("click", function(objEvent) {
				recorderUI.hideAuthentication();
				if(!commonUI.js2flex({cmd:'isMicAuthorised'})) {
					commonUI.resetAudio();
				}
			});
			
			swfobject.switchOffAutoHideShow();
			swfobject.embedSWF(opts.swf,'audiocontrol','215','138','10',null,null,{ allowScriptAccess: "always" },null,function(e){checkFlashLoaded();});
		}
		
		function checkFlashLoaded() {
			swf = document.getElementById('audiocontrol');
			if(swf.js2flex){
				clearTimeout(flashCeckTimeout);
				commonUI.js2flex({cmd:'setJSHandler',handler:'jQuery.fn.audio.flexCallHandler'});
				commonUI.js2flex({cmd:'setFilePrefix',prefix:opts.prefix});
				recorderUI.hideAuthentication();
				if(!flashready) {
					$(document).trigger('flashready');
					flashready = true;
				}
			} else if(flashCheckCount++ < 50) {
				flashCeckTimeout = setTimeout(checkFlashLoaded, opts.startupCheckTime);
			} else {
				recorderUI.requestAuthentication(false);
				flashCheckCount = 0;
				checkFlashLoaded();
			}
		}
	}
})(jQuery);


/*********************************************/
/* AWS Audio Loader
 *********************************************/
var awsAudioLoader = {
	retry: 10,
	addLoadingNote: function() {
		$('.awsaudio:not(.loading)').html('<p><img style="margin-right:6px;vertical-align:middle;" src="/commonskins/base/images/loader-trans.gif">Retrieving your response, please wait...</p>');
		$('.awsaudio').addClass('loading');
	},
	addErrorNote: function() {
		$('.awsaudio').html('<p><img style="margin-right:6px;vertical-align:middle;" src="/commonskins/base/images/delete.png">Audio asset currently unavailable. Please try again later.</p>');
	},
	addAudioContent: function(name, urls) {
		if($('#' + name).hasClass("concatenateaudio")) {
			$('.concatenateaudio_download').removeClass("hide");
		}
		
		$('#' + name).replaceWith(
			'<a id="' + name + '" href="' + urls.audio + '" class="playback">' +
				'<img src="' + urls.wave + '" />' +
			'</a>'
		);
	},
	checkAndHandleErrors: function() {
		if($('.awsaudio').length && this.retry > 0) {
			setTimeout(this.getAudio, 10000);
			this.retry--;
			
			if($('.awsaudio:not(.loading)').length) {
				this.addLoadingNote();
			}
		} else if($('.awsaudio').length) {
			this.addErrorNote();
		}
	},
	getAudio: function(){
		var player, testUrls;
		
		if($('.awsaudio:not(.loading)').length) {
			awsAudioLoader.addLoadingNote();
		}
		
		$.ajax({
			url: '/api/?method=getTestReviewAssets&test_id=' + testId,
			cache: false,
			dataType: "json",
			success: function(data) {
				for(var testUrls in data.d) {
					if (data.d.hasOwnProperty(testUrls)) {
						player = $('#' + testUrls + '.awsaudio');
						if ($('#' + testUrls + '.awsaudio').length) {
							$.preLoadImages(data.d[testUrls].wave);
							awsAudioLoader.addAudioContent(testUrls, data.d[testUrls]);
	
							$('#' + testUrls).audioPlayerInit();
						}
					}
				}
				awsAudioLoader.checkAndHandleErrors();
			}
		});
	}
};
