dojo.provide("dojox.av.FLVideo");
dojo.experimental("dojox.av.FLVideo");
dojo.require("dijit._Widget");
dojo.require("dojox.embed.Flash");
dojo.require("dojox.av._Media");

dojo.declare("dojox.av.FLVideo", [dijit._Widget, dojox.av._Media], {
			 
	// summary:
	//		Inserts a Flash FLV video into the HTML page and provides methods
	//		and events for controlling the video. Also plays the H264/M4V codec 
	//		with a little trickery: change the '.M4V' extension to '.flv'.
	//
	// example:
	//
	//		markup:
	//		|	<div id="vid" initialVolume=".7", 
	//		|		mediaUrl="../resources/Grog.flv" 
	//		|		dojoType="dojox.av.FLVideo"></div>
	//		programmatic:
	//		|	new dojox.av.FLVideo({
	//		|		initialVolume:.7, 
	//		|		mediaUrl:"../resources/Grog.flv"
	//		|	}, "vid");
	//
	//  mediaUrl: String
	// 		REQUIRED: The Url of the video file that will be played. 
	//		NOTE: Must be either an absolute URL or relative to the HTML file. 
	//		Relative paths will be converted to abslute paths
	//
	// _swfPath: Uri
	//		The path to the video player SWF resource
	_swfPath: dojo.moduleUrl("dojox.av", "resources/video.swf"),
	//
	//
	postCreate: function(){
		// summary:
		// Initialize the media.
		//
		//
		this._subs = [];
		this._cons = [];
		this.mediaUrl = this._normalizeUrl(this.mediaUrl);
		this.initialVolume = this._normalizeVolume(this.initialVolume);	
		
		var args = {
			path:this._swfPath.uri,
			width:"100%",
			height:"100%",
			minimumVersion:9,
			expressInstall:true,
			params:{
				allowFullScreen:true,
				wmode:"transparent"
			},
			// only pass in simple variables - no deep objects
			vars:{
				videoUrl:this.mediaUrl, 
				id:this.id,
				autoPlay:this.autoPlay,
				volume:this.initialVolume,
				isDebug:this.isDebug
			}
		};
		
		// Setting up dojo.subscribes that listens to events
		//	from the player
		this._sub("stageClick",  "onClick");
		this._sub("stageSized",  "onSwfSized");
		this._sub("mediaStatus", "onPlayerStatus");
		this._sub("mediaMeta",   "onMetaData");
		this._sub("mediaError",  "onError");
		this._sub("mediaStart",  "onStart");
		this._sub("mediaEnd",    "onEnd");
	
		this._flashObject = new dojox.embed.Flash(args, this.domNode);
		this._flashObject.onError = function(err){
			console.warn("Flash Error:", err);
			alert(err);
		};
		this._flashObject.onLoad = dojo.hitch(this, function(mov){
			this.flashMedia = mov;
			this.isPlaying = this.autoPlay;
			this.isStopped = !this.autoPlay;
			this.onLoad(this.flashMedia);
			this._initStatus();
			this._update();			 
		});
		
	},
	
	//  =============================  //
	//  Methods to control the player  //
	//  =============================  //
	
	play: function(/* String? */newUrl){
		// summary:
		//		Plays the video. If an url is passed in, plays the new link.
		this.isPlaying = true;
		this.isStopped = false;
		this.flashMedia.doPlay(this._normalizeUrl(newUrl));
	},
	
	pause: function(){
		// summary:
		// 		Pauses the video
		this.isPlaying = false;
		this.isStopped = false;
		//this.onPause();
		this.flashMedia.pause();
	},
	
	seek: function(/* Float */ time ){
		// summary:
		// 		Goes to the time passed in the argument
		this.flashMedia.seek(time);
	},
	
	
	//  =====================  //
	//  Player Getter/Setters  //
	//  =====================  //
	
	volume: function(/* Float */ vol){
		// summary:
		//		Sets the volume of the video to the time in the
		// argument - between 0 - 1.
		//
		if(vol){
			if(!this.flashMedia) {
				this.initialVolume = vol;	
			}
			this.flashMedia.setVolume(this._normalizeVolume(vol));
		}
		if(!this.flashMedia || !this.flashMedia.doGetVolume) {
			return this.initialVolume;
		}
		return this.flashMedia.getVolume(); // Float	
	},
	
	//  =============  //
	//  Player Events  //
	//  =============  //
	
	/*=====
	onLoad: function(mov){
		// summary:
		// 		Fired when the SWF player has loaded
		// 		NOT when the video has loaded
	},
	
	onDownloaded: function(percent){
		// summary:
		//		Fires the amount of that the media has been 
		//		downloaded. Number, 0-100
	},
	
	onClick: function(evt){ 
		// summary:
		// 		Fires when the player is clicked
		// 		Could be used to toggle play/pause, or 
		// 		do an external activity, like opening a new
		//		window.
	},
	
	onSwfSized: function(data){
		// summary:
		// 		Fired on SWF resize, or when its
		// 		toggled between fullscreen.
	},
	
	onMetaData: function(data, evt){
		// summary:
		// 		The video properties. Width, height, duration, etc.
		// 		NOTE: 	if data is empty, this is an older FLV with no meta data.
		// 				Duration cannot be determined. In original FLVs, duration 
		//				could only be obtained with Flash Media Server.
		// 		NOTE: 	Older FLVs can still return width and height
		//				and will do so on a second event call
	},
	
	onPosition: function( time){
		// summary:
		//		The position of the playhead in seconds 
	},
	
	onStart: function( data){
		// summary:
		// 		Fires when video starts
		// 		Good for setting the play button to pause
		// 		during an autoPlay for example
	},
	
	onPlay: function(data){
		// summary:
		// 		Fires when video starts and resumes
	},
	
	onPause: function(data){
		// summary:
		// 		Fires when the pause button is clicked
	},
	
	onEnd: function(data){
		// summary:
		// 		Fires when video ends
		// 		Could be used to change pause button to play
		// 		or show a post video graphic, like YouTube
	},
	
	onStop: function(){
		// summary:
		// Fire when the Stop button is clicked
		// TODO: 	This is not hooked up yet and shouldn't
		//			fire.
	},
	
	onBuffer: function(isBuffering){
		// summary:
		//		Fires a boolean to tell if media
		//		is paused for buffering or if buffering
		//		has finished
		this.isBuffering = isBuffering;
	},
	
	onError: function(data, url){
		// summary:
		// 		Fired when the player encounters an error
		// example:
		//		| console.warn("ERROR-"+data.type.toUpperCase()+":", 
		//		|		data.info.code, " - URL:", url);
	},
	
	onStatus: function(data){
		// summary:
		// 		Simple status
	},
	
	onPlayerStatus: function(data){
		// summary:
		// 		The status of the video from the SWF
		// 		playing, stopped, bufering, etc.
	},
	
	onResize: function(){
		// summary:
		//		Fired on page resize
	},
	=====*/
	
	//  ===============  //
	//  Private Methods  //
	//  ===============  //
	
	_checkBuffer: function(/* Float */time, /* Float */bufferLength){
		// summary:
		//		Checks that there is a proper buffer time between
		//		current playhead time and the amount of data loaded.
		//		Works only on FLVs with a duration (not older). Pauses
		//		the video while continuing download.
		//
		if(this.percentDownloaded == 100){
			if(this.isBuffering){
				this.onBuffer(false);
				this.flashMedia.doPlay();
			}
			return;
		}
		
		if(!this.isBuffering && bufferLength<.1){
			this.onBuffer(true);
			this.flashMedia.pause();
			return;
		}
		
		var timePercentLoad = this.percentDownloaded*.01*this.duration;
		
		// check if start buffer needed
		if(!this.isBuffering && time+this.minBufferTime*.001>timePercentLoad){
			this.onBuffer(true);
			this.flashMedia.pause();
		
		// check if end buffer needed
		}else if(this.isBuffering && time+this.bufferTime*.001<=timePercentLoad){
			this.onBuffer(false);
			this.flashMedia.doPlay();
		}
		
	},
	_update: function(){
		// summary:
		//		Helper function to fire onPosition, check download progress,
		//		and check buffer.
		var time = Math.min(this.getTime() || 0, this.duration);
		var dObj = this.flashMedia.getLoaded();
		this.percentDownloaded = Math.ceil(dObj.bytesLoaded/dObj.bytesTotal*100);
		this.onDownloaded(this.percentDownloaded);
		this.onPosition(time);
		if(this.duration){
			this._checkBuffer(time, dObj.buffer);	
		}
		// FIXME: need to remove this on destroy
		setTimeout(dojo.hitch(this, "_update"), this.updateTime);
	}
	
});
