/**
 * Implements jPlayer
 * @see http://www.happyworm.com/jquery/jplayer/latest/developer-guide.htm
 * @author DiS http://dis.dj
 */
(function($) {

	var debug = false;
	var players = [];

	/**
	 * Creates or updates waveform player
	 * @param {Object|String} action
	 * @param {Object} value
	 * @return {jQuery}
	 */
	$.fn.waveform = function(action, value) {

		var track = {
			media: {
				oga: '',
				m4a: '',
				mp3: ''
			},
			image: '',
			title: '',
			duration: 0,
			size: 0,
			durationFormatted: '',
			sizeFormatted: '',
			createDate: '',
			path: '',
			compact: false
		};
		var isPlaying = false;

		var container = $(this).eq(0);

		var id = container.data('waveform');
		if (id != null) {

			// Get objects
			container = players[id];
			player = container.getPlayer();
			track = container.getTrack();

			// Decode action
			switch (action) {
				case "setTrack":
					container.setTrack(value);
					break;
				case "getTrack":
					return track;
					break;
				case "getPlayer":
					return player;
					break;
				case "play":
					player.jPlayer("play");
					break;
				case "pause":
					player.jPlayer("pause");
					break;
				case "stop":
					player.jPlayer("stop");
					break;
				default:
					throw "Action \"" + action + "\" is not defined";
					break;
			}

			return container;

		}

		id = players.length;
		container.empty().data('waveform', id); // Clean graceful degradation data

		var loading = $('<div class="waveform-loading">Loading player…</div>').appendTo(container);
		var info = $('<div class="waveform-info waveform-loadable"></div>').appendTo(container);
		var download = $('<div class="waveform-download waveform-loadable"></div>').appendTo(container);
		var title = $('<h3 class="waveform-title waveform-loadable"></h3>').appendTo(container);
		var wrapper = $('<div class="waveform-wrapper"></div>').appendTo(container);
		var waveform = $('<div class="waveform-waveform"></div>').appendTo(wrapper);
		var player = $('<div class="waveform-player" id="waveform-' + id + '-player"></div>').appendTo('body');
		var img = $('<img class="waveform-image waveform-loadable" src="">').appendTo(waveform);
		var loaded = $('<div class="waveform-loaded waveform-loadable"></div>').appendTo(waveform);
		var progress = $('<div class="waveform-progress waveform-loadable"></div>').appendTo(waveform);
		var progressBg = $('<div class="waveform-progress-bg waveform-loadable"></div>').appendTo(waveform);
		var time = $('<div class="waveform-time waveform-loadable"></div>').appendTo(waveform);
		var play = $('<div class="waveform-play waveform-loadable"></div>').appendTo(wrapper);
		var stop = $('<div class="waveform-stop waveform-loadable"></div>').appendTo(wrapper);
		var volume = $('<div class="waveform-volume waveform-loadable"><div></div><span></span></div>').appendTo(wrapper);

		if (action.compact && action.compact != 'false') container.addClass('waveform-compact');

		function setPlaying(flag) {

			isPlaying = !!flag;
			container.removeClass('waveform-playing');
			if (isPlaying) container.addClass('waveform-playing');

		}

		function updateProgress(status) {

			var waveformWidth = parseInt(waveform.width());
			var loadedWidth = Math.round(status.seekPercent / 100 * waveformWidth) + 'px';
			var progressWidth = Math.round(status.currentPercentAbsolute / 100 * waveformWidth) + 'px';

			loaded.css({width: loadedWidth});
			progress.html('<span>' + $.jPlayer.convertTime(status.currentTime) + '</span>').css({width: progressWidth});
			progressBg.css({width: progressWidth});

		}

		/**
		 * Get player object
		 * @return {jQuery}
		 */
		container.getPlayer = function() {
			return player;
		};

		/**
		 * Get current track object
		 * @return {Object}
		 */
		container.getTrack = function() {
			return track;
		};

		/**
		 * Set new track object
		 * @param newTrack
		 */
		container.setTrack = function(newTrack) {

			track = $.extend({}, newTrack);

			container.stop();
			player.jPlayer('setMedia', track.media);

			img.attr('src', track.image);
			title.html(track.title);
			info.html('<span class="size">' + track.sizeFormatted + '</span>');
			download.html('<a href="' + track.media.mp3 + '" target="_blank">Скачать трек</a>');
			track.duration *= 1000;
			time.html(track.durationFormatted);

		};

		var isReady = false;

		/**
		 * Player init
		 */
		player.jPlayer({
			ready: function () {

				if (isReady) return false;
				isReady = true;
				
				container.addClass('waveform-ready').waveform("setTrack", action);

			},
			volume: 75,
			errorAlerts: debug, // This is for debug purposes
			warningAlerts: debug, // This is for debug purposes
			preload: 'none',
			solution: action.solution,
			supplied: action.supplied,
			swfPath: action.path
		});


		/**
		 * Disable drag-drop
		 */
		waveform.mousedown(function(e) {
			e.stopPropagation();
			e.preventDefault();
			return false;
		});

		/**
		 * Progress
		 */
		waveform.mouseup(function(e) {

			e.stopPropagation();
			e.preventDefault();

			if (isPlaying) {

				var coords = waveform.offset();
				var percent = (e.pageX - coords.left) * 100 / loaded.width();
				if (percent < 0) percent = 0;
				if (percent > 100) percent = 100;

				player.jPlayer('playHead', percent); //TODO Buggy when not fully loaded, unsing playHeadTime doesn't solve the problem

			}

			return false;

		});

		var volumeDrag = function(e){

			var pos = volume.offset();
			var width = parseInt(volume.width());
			var vol = ((parseInt(e.pageX) - parseInt(pos.left)) / width);
			if (vol < 0) vol = 0;
			if (vol > 1) vol = 1;

			player.jPlayer('volume', vol);
			
		};

		$(window).mouseup(function(e){
			$(window).unbind('mousemove', volumeDrag);
		});

		volume.mousedown(function(e){
			e.stopPropagation();
			e.preventDefault();
			volumeDrag(e);
			$(window).mousemove(volumeDrag);
			return false;
		});

		/**
		 * Playing
		 */
		play.mouseup(function(e) {

			e.stopPropagation();
			e.preventDefault();

			player.jPlayer(isPlaying ? 'pause' : 'play');

			return false;

		});
		
		stop.mouseup(function(e) {

			e.stopPropagation();
			e.preventDefault();

			player.jPlayer('stop');

			return false;

		});

		player.bind($.jPlayer.event.progress, function(e) {

			updateProgress(e.jPlayer.status);

		});
		
		player.bind($.jPlayer.event.timeupdate, function(e) {

			updateProgress(e.jPlayer.status);

		});

		player.bind($.jPlayer.event.play, function() {

			player.jPlayer('pauseOthers');
			setPlaying(true);

		});

		player.bind($.jPlayer.event.pause, function() {

			setPlaying(false);

		});

		player.bind($.jPlayer.event.ended, function() {

			setPlaying(false);

		});

		player.bind($.jPlayer.event.volumechange, function(e) {

			volume.find('div').width((100 * e.jPlayer.status.volume) + '%');

		});


		// Add container to an array
		players.push(container);

		return this;

	};

})(jQuery);
