/**
 *	RAD_IMAGE_SQUENCE_PLAYER
 *	@author RadMedia - Richard Burkhardt
 *	@version 1.1beta
 *	
 *	This is a jQuery-plugin for jQuery 1.4.2+ (tested). This plugin enables you
 *	to play imagesequences without flash or HTML5 with the benefit of playing
 *	your movies backwards and having PNG images animated.
 *
 *	SETTINGS
 *	@param images	-	array of images that are played in this order ! important image names my not contain any spaces
 *	@param path		-	string that contains the image folder
 *	@param grid		-	object that contans the structure of an image, i.e. {height:800,width:600,rows:1,columns:1}
 *	@param grid.height	-	integer value that represents the image height of the resultung frame in a multi-frame image
 *	@param grid.width	-	integer value that represents the image width of the resultung frame in a multi-frame image
 *	@param grid.rows	-	integer value that represents the number of frame rows in a multi-frame image
 *	@param grid.columns	-	integer value that represents the number of frame columns in a multi-frame image
 *	@param loader	-	object that contans the parameters for the image preloader
 *	@param loader.path		-	string that contains the preloader image path
 *	@param loader.height	-	integer value that represents the preloader height
 *	@param loader.width		-	integer value that represents the preloader width
 *	@param loader.rows		-	integer value that represents the number of frame rows in the multi-frame preloader image
 *	@param loader.columns	-	integer value that represents the number of frame columns in the multi-frame preloader image
 *	@param fps		-	float value that represents the frames per second rate
 *	@param width	-	integer value that scales the target frame to the wanted player width
 *	@param height	-	integer value that scales the target frame to the wanted player height
 *	@param repeat	-	boolean value enables or disables the auto repeat function
 *	@param playOnLoad		-	boolean value. if set to true the video atomaticly starts to play after the frames are loaded 
 *	@param playBackwards	-	boolean value. if set to true the video plays backwards
 *	@param showPreLoader	-	boolean value. if set to true the preloader will be displayed
 *	@param verbose	-	boolean value. if set to true the player will trigger the verbose event
 *
**/

(function($) {
 
	var settings = {
		images : [],
		folder : "ai/bg1/",
		grid: {height:250,width:250,rows:1,columns:1},
		loader: {path:"img/loader2.png",height:50,width:50,rows:2,columns:4},
		fps: 24,
		width: 250,
		height: 250,
		repeat:true,
		playOnLoad:true,
		playBackwards:false,
		showPreLoader:false,
		verbose:true
	};			
	
	var playingInterval;
	var imageCache = [];
	
	var methods = {
		init : function(options) {
			
			if (options != undefined) { 
				$.extend( settings, options );
			}
		
			return this.each(function(){
				var data = $(this).data("richMovie");
				
				//no initialization has been done
				if(!data){
					$(this).data("richMovie",$(this));
					//scale canvas
					$(this).css({width:settings.width, height:settings.height, overflow:'hidden'});
					//create frames
					$(this).data("currentFrame",$(this));
					var frameNo = 0;
					for(var i = 0;i < settings.images.length;i++){
						for(var row = 0;row < settings.grid.rows;row++){
							for(var col = 0;col < settings.grid.columns;col++){
								$(this).data("frame"+frameNo,$("<div class='richMovieFrame' />"));
								$(this).data("currentFrame").append($(this).data("frame"+frameNo));
								$(this).data("currentFrame",$(this).data("frame"+frameNo));
								$(this).data("frame"+frameNo)
									.css({width:settings.width, 
										  height:settings.height,
										  'background-position':(-settings.grid.width*col)+"px "+(-settings.grid.height*row)+"px",
										  'background-repeat':'no-repeat'
										  })
									.data("frame",frameNo+1);
								frameNo++;
								//hideAllFrames
								$(this).data("currentFrame").hide();
							}
						}
					}
					//movie is stoped by default
					$(this).data("currentStatus","stopped");
					$(this).bind("play",play_movie_event);
					$(this).bind("stop",stop_movie_event);
					$(this).bind("pause",pause_movie_event);
					//show first frame
					$(this).data("frame0").show();
					$(this).data("currentFrame",$(this).data("frame0"));
					$(this).data("currentFrame").css({'background-image':'url("'+settings.folder+settings.images[0]+'")'});
										  
					//preload all images
					preloadImages.apply($(this));
					//show preloader
					animatePrelaoder.apply($(this));
					
				}else{
					methods.throwError(1);
				}

			});
		
		},
		
		option : function (option, value){
			
			if(value == undefined){
				return settings[option];
			}else{
				settings[option] = value;
				return this;
			}
			
		},
		
		play : function(){
			$(this).data("currentStatus","play");
			$(this).trigger("play");
		},
		
		pause : function(){
			$(this).data("currentStatus","paused");
			$(this).trigger("pause");
		},
		
		stop : function(){
			$(this).data("currentStatus","stopped");
			$(this).trigger("stop");
		},
		
		playUntil : function(frame) {
			$(this).data("playUntil",frame);
			if(frame != $(this).data("currentFrame").data('frame')){
				methods.play.apply(this);
			}
		},
		
		goto : function(frame){
			var self = this;
			$(this)
				.find(".richMovieFrame")
				.each(function(index,elem){
					if(frame == $(this).data('frame')){
						$(self).data("currentFrame").css({'background-image':''});
						$(self).find(".richMovieFrame").hide();
						$(self).data("currentFrame",$(this));
						$(self).data("currentFrame").show();
						$(self).data("currentFrame").parentsUntil('div:not(.richMovieFrame)').show();
						var imageframe = Math.floor((frame-1)/(settings.grid.rows*settings.grid.columns));
						$(self).data("currentFrame").css({'background-image':'url('+settings.folder+settings.images[imageframe]+')'});
					}
				});	
		},
		
		destroy : function(){
	
			return this.each(function(){
				$(".richMovieFrame").remove();
			});
	
		},
		
		throwError : function(errno){
			var error = "";
			if(errno != undefined){
				if(errno == 1){
					error = "This Objekt has already been initialized!";
				}else if(true){
					error = "Unknown Error";
				}
			}else{
				error = "Unknown Error";
			}
			
			if(window.console) {
				console.log(error);
			} else {
				alert(error);
			}
		}
		
		
	};
	
	/*Eventhandler*/
	function play_movie_event(e){
		if($(this).data("currentStatus") == 'play'){	
			clearInterval(playingInterval);
			$(this).data("currentStatus","playing");
			var self=this;
			playingInterval = setInterval(function() {
				//remove current background image
				$(self).data("currentFrame").css({'background-image':''});
				if(settings.playBackwards){
					if($(self).data("currentFrame").data('frame') != 1){
						$(self).data("currentFrame").hide();
						$(self).data("currentFrame",$(self).data("currentFrame").parent());
						$(self).trigger('playing');
					}else{
						if(settings.repeat){
							$(self).trigger('playing');
							$(self).find(".richMovieFrame").show();
							$(self).data("currentFrame",$(self)
															.find(".richMovieFrame")
															.filter(function(){
																if(!$(this).children().length){
																	return $(this);
																}
															})
										 );
						}else{
							$(self).trigger('stop');
						}
					}
				}else{
					if($(self).data("currentFrame").children().length){
						$(self).data("currentFrame",$(self).data("currentFrame").children().first());
						$(self).data("currentFrame").show();
						$(self).trigger('playing');						
					}else{
						if(settings.repeat){
							$(self).find(".richMovieFrame").hide();
							$(self).data("currentFrame",$(self).data("frame0"));
							$(self).data("currentFrame").show();
						}else{
							$(self).trigger('stop');
						}
					}
				}
				//show current background
				var imageframe = Math.floor(($(self).data("currentFrame").data('frame')-1)/(settings.grid.rows*settings.grid.columns));
				$(self).data("currentFrame").css({'background-image':'url('+settings.folder+settings.images[imageframe]+')'});
				if($(self).data("playUntil") == $(self).data("currentFrame").data('frame')){
				   $(self).trigger('pause');
				   $(self).data("playUntil",-1);
				}
			}, 1000/settings.fps);
		}
	}
	
	function stop_movie_event(e){
		clearInterval(playingInterval);
		$(this).find(".richMovieFrame").hide();
		$(this).data("currentFrame",$(this).data("frame0"));
		$(this).data("currentFrame").show();
		$(this).data("currentFrame").css({'background-image':'url('+settings.folder+settings.images[0]+')'});
		$(this).data("currentStatus","stop");
		$(this).data("playUntil",-1);		
	}
	
	function pause_movie_event(e){
		clearInterval(playingInterval);
	}
	
	/*helper*/
	function preloadImages(imageToLoad){
		
		if(imageToLoad == undefined){
			imageToLoad = 0;
			this.data("loadStatus","loading");
		}
		
		var curImg = new Image();
		var self = this;
		curImg.onload = function(){
			imageToLoad++;
			if(imageToLoad >= settings.images.length){
				self.data("loadStatus","loaded");
				self.trigger("loaded");
				if(settings.playOnLoad){
					methods.play.apply(self);	
				}
			}else{
				preloadImages.apply(self,[imageToLoad]);
			}
			verboseOut.apply(self,["Image #"+imageToLoad+" has been loaded"]);			
		}
		curImg.src = settings.folder+settings.images[imageToLoad];
		/*FOR THE BROWSERS THAT DON'T JUST PRELOAD ON INSTANCIATION LIKE OPERA,CHROME - THEY ONLY CACHE VISIBLE BACKGROUNDIMAGES*/
		this.after(curImg);
		$(curImg).css({width:"1px",height:"1px",position:'absolute',top:"0px",left:"0px",opacity:0.01});
		/*****************************************************************************/
		imageCache.push(curImg);
		
	}
	
	function animatePrelaoder(){
		if(this.data("loadStatus") != "loaded" && settings.showPreLoader){
			this
				.append("<div class='laoderOverlay' />")
				.children(".laoderOverlay")
				.css({"background-color":"black",
					  opacity:0.8,
					  height:this.height()+"px",
					  width:this.width()+"px",
					  position:'absolute',
					  top:this.offset().top+"px",
					  left:this.offset().left+"px"});
			this
				.append("<div class='laoderAnimation' />")
				.children(".laoderAnimation")
				.css({"background-image":"url("+settings.loader.path+")",
					  height:settings.loader.height+"px",
					  width:settings.loader.width+"px",
					  position:'absolute',
					  top:(this.offset().top+(this.height()/2)-(settings.loader.height/2))+"px",
					  left:(this.offset().left+(this.width()/2)-(settings.loader.width/2))+"px",
					  'background-repeat':'no-repeat'});
			
			this.children(".laoderAnimation").data("currentFrame",0);
			
			var self = this;
			var loadingInterval = setInterval(function() {
				if(self.data("loadStatus") == "loaded"){
					self.children(".laoderOverlay, .laoderAnimation").remove();
					clearInterval(loadingInterval);
				}
				var frame = self.children(".laoderAnimation").data("currentFrame");
				self.children(".laoderAnimation").css({'background-position':(-settings.loader.width*(frame%settings.loader.columns))+"px "+(-settings.loader.height*Math.floor(frame/settings.loader.columns))+"px"});
				self.children(".laoderAnimation").data("currentFrame",(frame+1)%(settings.loader.rows*settings.loader.columns));
			}, 100);
		}
	}
	
	function verboseOut(out){
		this.trigger("verbose",out);
	}
		
	$.fn.richMovie = 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.richMovie' );
		}
		 
   };
   
})(jQuery);
