(function( $ ){
	
	var defaults = {
		selector: null,
		template: '<div class="total-duration">Duration: <span class="total-duration-value">{duration}mins</span></div><ul class="jplaylist-content"></ul>',
		type: 'ul',
		child: '<li id="jpl-{chapter}"><span class="l"><span class="chap-num">{index}</span> <span class="chap-title">{title}</span></span> <span class="chap-duration">{duration}</span></li>',
		imageSelector: '#artwork',
		autoplay: true
	}
		
	var nextOffset = 0;
	var prevOffset = 0;
	var images = {};
	
	var methods = {
		init: function(options) {
			if (options == undefined || typeof options != 'object') {
				$.error('jPlaylist requires a JSON object containing initialisation options');
			}
			if (options['playlistURL'] == undefined || typeof options['playlistURL'] != 'string') {	
				$.error('jPlaylist requires a playlist URL in the initialisation options');
			}
			
			return this.each(function(){
				var $this = $(this),
					data = $this.data('jplaylist');
					
				if (!data) {
					
					data = {
						target: $this,
						playlistURL: options.playlistURL,
						playing: false,
						control: $('.jpl-controls')
					}
					data.isiPad = navigator.userAgent.match(/iPad/i) != null;
					data.isiPhone = navigator.userAgent.match(/iPhone/i) != null;
					data.isAndroid = navigator.userAgent.match(/Android/i) != null;
					if (data.isiPad || data.isiPhone) {
						data.control.find('.jp-mute, .jp-unmute').parent().hide();
					}
					
					data.options = $.extend({},defaults,options);					
					
					$this.data('jplaylist',data);
					if (data.isiPhone) {
						$(options.selector).css('clear','left');
					}
					
					$.ajax({
						url: data.options.playlistURL,
						dataType:'json',
						error: function() {
							privateMethods.error($this);
						},
						success: function(ret,textStatus,jqXHR) {
							var data = $this.data('jplaylist');
							data.playlist = ret;
							$this.data('jplaylist',data);
							var jpopts = {
								ready: function() {										
									if (data.loaded) {
										return;
									}
									$this.jplaylist('display');
									$this.jplaylist('load');
								},
								ended: function(event) {
									if (privateMethods.autoNext($this)) {
										if (!data.isiPad) {
											$this.jplaylist('play');
										} else {
											$this.data.playing = false;
											privateMethods.showButton($this);
										}
									}
								},
								play: function() {
									privateMethods.hideButton($this);
									data.playing = true;
								},
								pause: function() {
									privateMethods.showButton($this);
									data.playing = false;
								},
								warning: function(event) {
									return;
									alert(event.jPlayer.warning.type+" error: \nContext: "+event.jPlayer.warning.context+"\nMessage: "+event.jPlayer.warning.message+"\nHint: "+event.jPlayer.warning.hint);
									privateMethods.error($this,true);
								},
								seeked: function(event) {
									privateMethods.changeImage($this,event.jPlayer.status.currentTime);
								},
								timeupdate: function(event) {
									if (event.jPlayer.status.currentTime > nextOffset || event.jPlayer.status.currentTime < prevOffset) {
										privateMethods.changeImage($this,event.jPlayer.status.currentTime);
									}
								},
								error: function(event) {
									//return;
									//alert(event.jPlayer.error.type+" error: \nContext: "+event.jPlayer.error.context+"\nMessage: "+event.jPlayer.error.message+"\nHint: "+event.jPlayer.error.hint);
									privateMethods.error($this,true);
								},
								swfPath: "../../../../js",
								supplied: "mp3",
								errorAlerts: false,
								warningAlerts: false
							};
							if (data.isAndroid) {
								jpopts.solution = 'flash';
							}
							$this.jPlayer(jpopts);
						}
					});
				}
				
			})
		},
		
		load: function() {
			return this.each(function(){
				var $this = $(this);
				var data = $this.data('jplaylist');
				$(data.options.imageSelector).click(function(){
					if (data.playing) {
						privateMethods.pause($this);
					} else {
						privateMethods.play($this);
					}
				});
				data.control.find('.jpl-next').click(function(){
					$this.jplaylist('next');
				});
				data.control.find('.jpl-previous').click(function(){
					$this.jplaylist('previous');
				});
				data.control.find('.jpl-play').click(function(){
					$this.jplaylist('play');
				});
				data.control.find('.jpl-pause').click(function(){
					$this.jplaylist('pause');
				});
				privateMethods.select($(this),0);
				if ($this.data('jplaylist').options.autoplay) {
					privateMethods.play($this);
				}
				data.loaded = true;
			});
		},
		
		display: function() {
			return this.each(function(){
				var data = $(this).data('jplaylist'),
					chapIdx,
					chap,
					template;
				
				var mins = Math.round(data.playlist.duration/60);
			
				var playlist = $(data.options.selector);
				playlist.empty();
				template = tpl_replace(data.options.template,'duration',mins);
				playlist.append(template);
				
				var tpl = playlist.find(data.options.type);
				
				for (var i=0; i < data.playlist.chapters.length; i++) {
					chapIdx = i;
					chap = data.playlist.chapters[chapIdx];
					var tplChild = data.options.child;
					
					var el, cDur = 0, prevDur = 0;
					
					 var elIdx = 0;
					for (var j = 0; j < chap.elements.length; j++) {
                                                elIdx = j;
						el = chap.elements[elIdx];
						cDur += prevDur;
						prevDur = parseFloat(el.duration);
						el.offset = cDur;
					}
					
					var mtc = chap.name.match(/^([0-9]+)\./);
					var idx = '&nbsp;';
					if (mtc != null) {
						idx = mtc[1] + '.';
						chap.name = chap.name.replace(idx,'');
					}
					
					tplChild = tpl_replace(tplChild,'index',idx);
					tplChild = tpl_replace(tplChild,'chapter',chapIdx);
					tplChild = tpl_replace(tplChild,'title',chap.name);
					var durInt = Math.round(parseFloat(chap.duration));
					tplChild = tpl_replace(tplChild,'duration',privateMethods.formatDuration(durInt));
					tpl.append(tplChild);
					idx++;
				}
				tpl.children().each(function(){
					$(this).click(function(){
						var id = $(this).attr('id');
						var parts = id.split('-');
						data.target.jplaylist('select',parts[1]);
					});
					$(this).hover(function(){
						$(this).addClass('hover');
					},function(){
						$(this).removeClass('hover')
					});
				});
			});
		},
		
		play: function() {
			return this.each(function(){
				//privateMethods.autoNext($(this));
				privateMethods.play($(this));
			});
		},
		
		pause: function() {
			return this.each(function(){
				privateMethods.pause($(this));
			});
		},
		
		next: function() {
			return this.each(function(){
				privateMethods.move($(this),'+');
				privateMethods.play($(this));
			});
		},
		
		previous: function() {
			return this.each(function(){
				privateMethods.move($(this),'-');
				privateMethods.play($(this));
			});
		},
		
		select: function(index) {
			return this.each(function() {
				privateMethods.select($(this),index);
				privateMethods.play($(this));
			});
		}
		
	}
	
	var privateMethods = {
		
		formatDuration: function(length) {
			var hrs = 0, secs = 0;
				
			if (length <= 60) {
				secs = length;
			} else {
				var div = length/60;
				hrs = Math.floor(div);
				secs = length % 60;
			}
			if (secs < 10) {
				secs = '0'+secs;
			}
			return hrs+':'+secs;
		},
		
		changeImage: function($p,currentTime) {
			var data = $p.data('jplaylist'), elIdx, el, useElIdx;
			var chap = data.playlist.chapters[data.currentChapter];
			//alert(chap.elements.length +" elements in chapter, current time "+currentTime);
			for (elIdx in chap.elements) {
				el = chap.elements[elIdx];
				if (el.offset < currentTime) {
					useElIdx = elIdx;
				} else {
					break;
				}
			}
			useElIdx = parseInt(useElIdx);
			
			$(data.options.imageSelector + ' img').attr('src',chap.elements[useElIdx].image);

			if (chap.elements.length >= useElIdx + 2) {
				nextOffset = chap.elements[useElIdx+1].offset;
				prevOffset = chap.elements[useElIdx].offset;
			} else {
				nextOffset = 0;
				prevOffset = 0;
			}
		},
		
		error: function($p,to) {
			var data = $p.data('jplaylist');
			var parent = $p.parent();
			parent.next('.jwarning').remove();
			if (to != undefined && to) {
				var msg = "Your playlist may have timed out: try reloading this page.";
			} else {
				var msg = "There is a problem with this stream. Try reloading this page, or contact support if the error continues.";
				$('#playlist').empty();
			}
			parent.after('<p class="jwarning"><span class="bold">An error has occured</span> '+msg+'</p>');
			
		},
		
		autoNext: function($p) {
			var data = $p.data('jplaylist'),
				nextChapter,
				nextElement;

			if (data.currentChapter == undefined) {
				nextChapter = 0;
			} else {
				var cChapData = data.playlist.chapters[data.currentChapter];
				var cChap = parseInt(data.currentChapter);
				if (data.playlist.chapters.length < (cChap + 2)) {
					//Reached the end
					this.hideButton($p);
					return false;
				} else {
					nextChapter = cChap + 1;
				}
			}
			this.load($p,data,nextChapter);
			return true;
		},
		
		select: function($p,chapter) {
			var data = $p.data('jplaylist');
			this.load($p,data,chapter);
		},
		
		pause: function ($p) {
			$p.jPlayer('pause');
		},
		
		move: function($p,direction) {
			var data = $p.data('jplaylist'),
				nextChapter = 0;
			data.currentChapter = parseInt(data.currentChapter);
			if (data.currentChapter == undefined) {
				switch (direction) {
					case '+':
						nextChapter = 1;
						break;
					case '-':
						break;
				}
			} else {
				switch (direction) {
					case '+':
						if (data.playlist.chapters.length < data.currentChapter + 2) {
							return;
						} else {
							nextChapter = data.currentChapter + 1;
						}
						break;
					case '-':
						if (data.currentChapter > 0) {
							nextChapter = data.currentChapter - 1;
						} else {
							nextChapter = 0;
						}
						break;
				}
			}
			this.load($p,data,nextChapter);
		},
		
		load: function($p,data,chapter) {
			prevOffset = 0;
			nextOffset = 0;
			var chap = data.playlist.chapters[chapter];
			$.get('/z_ajax/log_stream.php',{title: document.titleID, chapter: chapter});
			
			$p.jPlayer("setMedia",{mp3:chap.audio});
			
			$(data.options.imageSelector + ' img').attr('src',chap.elements[0].image);
			data.currentChapter = chapter;
			if (chap.elements.length > 1) {
				nextOffset = chap.elements[1].offset;
			} else {
				nextOffset = 0;
			}
			
			var pl = $(data.options.selector);
			pl.find('li').each(function(){
				var id = $(this).attr('id');
				var cid = 'jpl-'+data.currentChapter;
				if (id == cid) {
					$(this).addClass('playing');
				} else {
					$(this).removeClass('playing');
				}
			})
			pl.find('jpl-'+chapter).addClass('playing');
			$p.data('jplaylist',data);
		},
		
		play: function($p) {
			$p.jPlayer('play');
		},
		
		showButton: function($p) {
			var data = $p.data('jplaylist');
			var imgCont = $(data.options.imageSelector);
			imgCont.find('div').show();
			data.control.find('.jpl-play').show();
			data.control.find('.jpl-pause').hide();
		},
		
		hideButton: function($p) {
			var data = $p.data('jplaylist');
			var imgCont = $(data.options.imageSelector);
			imgCont.find('div').hide();
			data.control.find('.jpl-play').hide();
			data.control.find('.jpl-pause').show();
		}
	}
	
	$.fn.jplaylist = function( method ) {
		if ( methods[method] ) {
			return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.jplaylist' );
			return false;
		}
	};
	
})( jQuery );

function tpl_replace(str,token,value) {
	if (value == undefined) {
		value = '';
	}
	return str.replace('{'+token+'}',value);
}
