/**
 *	AudioControl.js, initially written by Rob Cole @2007.
 *  -----------------------------------------------------
 *
 *  Purpose:
 *  	- Provides javascript/DHTML controls for SWF audio player (which has no controls of its own).
 *  	- Defines extendable object for controlling an AudioPlayerNoControl swf.
 *      - Ideal for case when there are multiple audio sources on a page to be played by a single player,
 *        each with its own play/stop button. One audio-control object encapsulates the set of audio-sources/play-buttons,
 *        and is tied to a single flash audio player instance. Theoretically you could have multiple audio-control
 *        objects tied to a single player, but this case has not been tested.
 *		- Does not support multiple audio streams playing simultaneously - this is a feature. 
 *
 *  Details:
 *  	- Motivation: Browser gets unhappy when including multiple SWF players (with their own built in controls) on a page.
 *    	  Not only that but these players would have to talk to each other anyway to get
 *    	  one to stop when the other starts... This solves both problems.
 *
 *  Dependencies:
 *    	- AC_RunActiveContent.js
 *
 *  Instructions:
 *		- Include this file in the head.
 *	  	- Extend audio-control object as desired to adapt to your environment.
 *    	- Initialize control objects - can be done before body is loaded.
 *    	- In body, from script, call embed-audio-player to put the flash player somewhere
 *		  on the page - doesn't matter where.
 *    	- On page have unique div id for each control.
 *    	- Populate divs using script call to write-control-link.
 *	  	- if singleton OK, or for the first control only, call audio-control-init.
 *	  	- otherwise, or for additional controls call constructors directly.
 *
 *	Error handling:
 *		- when a play is initiated, the player is polled periodically until it has an error or has started playing.
 *        alert is called if an error occurs before it reaches the play state. 
 *
 *	Limitations:
 *		- There are no call-backs from player to javascript. This is sort of good news and bad news both.
 *		  Good because you can do whatever you want in javascript without breaking the player, and bad
 *		  because the player is only loosely coupled to the controller.
 *			- Some ideas for future:
 *		  		- Define two more control states:
 *					- Busy: entered upon play-start, or other operations.
 *					- Error: entered upon unsuccessful operation conclusion.
 *          	- Then if player errors out, it calls back into javascript
 *			  	  which enters the error state.
 *				- Likewise, if player starts successfully, that could generate a call-back
 *			      as well.
 *		- Also, there is no call-back when the player concludes a clip. I must say, the up side of this
 *        is that its easy to see what just played even after it stops.
 *      - A really fancy interface could even use a progress call-back, but at that point,
 *        it may be better to consider another technique(?)
 *
 *	********* AUDIO FILENAMES MUST NOT CONTAIN ANY OF THE FOLLOWING CHARACTERS: ' & # +
**/



//	B O O T S T R A P P I N G  /  I N I T


//
// 	Default audio control object, instantiated by default init function.
// 	if additional controllers are desired, instantiate in calling context
// 	into variables declared there.
//
var audioControl;

//
// 	Default audio control init function.
// 	Good for one audio control.
//
function audioControlInit() {
	//alert("audioControlInit - In");
	audioControl = new AudioControl("audioControl", "AudioPlayerNoControl");
		// Default movie name same as swf name.
	audioControl.init(); // include image preloading.
	//alert("audioControlInit - Out");
}



//  A U D I O   C O N T R O L   O B J E C T


//
//	Constructor.
//  ------------
//  Arguments:
//		- varName: name of the variable the new audio-control is being assigned to.
//			       Used for creating self-referential method calls in script code.
// 
function AudioControl(varName, movieName) {
	this.varName = varName;							// this must be exactly correct or it won't work.
	this.movieName = movieName;						// name/id of embedded swf movie.
	this.playingId = "";							// div id of control that is playing
	this.playingFile = "";							// file (path) of control that is playing.
	this.imageDir = "/_common/images/";             // re-assign after creation or created sub-class.
	this.stopImage = "PauseButton.gif";				// ditto.
	this.playImage = "play_button.gif";				// ditto.
	this.requiredMajorVersion = 9;					// ditto. No lesser version will do.
	// Minor version of Flash required
	this.requiredMinorVersion = 0;					// ditto.
	// Minor version of Flash required
	this.requiredRevision = 45;						// may work with lesser revisions, but not tested.
	this.timerID = 0;
	this.tickCount = 0;
}

//
// 	Override to provide custom initialization.
// 	This function assumes the default state is "ready to play" and thus its the stop-image that needs to be
// 	pre-loaded. Override if the default stat is "playing" and preload the play-image instead.
//
AudioControl.prototype.init = function() {
   	var preload = new Image();	// dummy image variable
	preload.src = this.imageDir + this.stopImage; // load image into dummy variable so its in browser cache.
}

//
//	Called by timer function to clear timer and display message.
//
AudioControl.prototype.conclude = function(message) {
	if (this.timerID) {
		clearInterval(this.timerID);
		this.timerID = 0;
	}
	if (message) {
		alert(message);
	}
}

//
//  Timer function for polling player status.
//
AudioControl.prototype.handleTimeout = function(dir, swfName) {
	//if (this.tickCount < 3) {
	//	alert("timeout being called");
	//	this.tickCount = this.tickCount + 1;
	//}
	var fm = this.getAudioPlayerMovie();
	if (fm) { 
		if (fm.getStatusInfo) { 
			var sts = fm.getStatusInfo(); // returns a string.
			var pattern = /error/i;       // regular expression.
			if (pattern.test(sts)) {
				this.conclude("Flash audio player is not happy, status: " + sts);
			} else {
				var pattern = /playing/i;
				if (pattern.test(sts)) {
					this.conclude();
				}
			}
		} else {
			this.conclude("***** ERROR: Javascript can not find flash audio status function.");
		}
	} else {
		this.conclude("***** ERROR: Javascript can not find flash audio player, name: " + this.movieName);
	}
}

//
//	Call from script tag in body of html doc at desired insertion point.
//
//  Arguments:
//		- dir: path where swf file is located - required. Example: /asdf/qwerty/
//      - swfName: BASE of filename - OMIT SWF EXTENSION. optional: if not passed,
//			    default swf will be used.
//
AudioControl.prototype.embedAudioPlayer = function(dir, swfName) {
	if (!swfName) {
		swfName = "AudioPlayerNoControl";
	}
	if (AC_FL_RunContent == 0 || DetectFlashVer == 0) {
		alert("****** ERROR: Audio control requires AC_RunActiveContent.js.");
	} else {
		var hasRightVersion = DetectFlashVer(this.requiredMajorVersion, this.requiredMinorVersion, this.requiredRevision);
		if(hasRightVersion) {  // if we've detected an acceptable version
			// embed the flash movie
			AC_FL_RunContent(
				'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,45,0',
				'width', '123',
				'height', '23',
				'src', dir + swfName,
				'quality', 'high',
				'pluginspage', 'http://www.macromedia.com/go/getflashplayer',
				'align', 'middle',
				'play', 'true',
				'loop', 'true',
				'scale', 'showall',
				'wmode', 'window',
				'devicefont', 'false',
				'id', this.movieName,
				'bgcolor', '#ffffff',
				'name', this.movieName,
				'menu', 'true',
				'allowScriptAccess','sameDomain',
				'allowFullScreen','false',
				'movie', dir + swfName,
				'salign', ''
				); //end AC code
		} else {  // flash is too old or we can't detect the plugin
			var alternateContent = 'Flash Audio requires the Adobe Flash Player. '
				+ '<a href=http://www.macromedia.com/go/getflash/>Get Flash</a>';
			document.write(alternateContent);  // insert non-flash content
		}
	}
}

//
//	Gets reference to flash movie by name.
//
AudioControl.prototype.getAudioPlayerMovie = function() {
	//alert("getAudioPlayerMovie - In");
	var fm;
	var isIE = navigator.appName.indexOf("Microsoft") != -1;
	fm = (isIE) ? window[this.movieName] : document[this.movieName];
	//alert("getAudioPlayerMovie - Out: " + fm);
	return fm;
}

//
//	Play file associated with specified div control.
//
//	Arguments:
//		_id: 	control div id.
//		_file: 	path to audio file, I usually make this site-relative, e.g. /myWebApp/myAudio/goodsound.mp3
//				Can also be document-relative, or URL to a script, but MUST be on the same server that delivered 
//				the web page or it won't work.
//
AudioControl.prototype.playIt = function(_id, _fil) {
	//alert("playIt - In, id: " + _id + ", file: " + _fil);
    if (this.playingId) {
		this.stopIt(this.playingId, this.playingFile);
	}
	var fm = this.getAudioPlayerMovie();
	if (fm) { 
		if (fm.playAudioFile) { 
			//alert("Attempting to play file: " + _fil);
			fm.playAudioFile(_fil);
			this.tickCount = 0;
			this.timerID = setInterval(this.varName + ".handleTimeout()", 3000);
			//var sts = fm.getStatusInfo();
			//alert("status after initiating play: " + sts);
		} else {
			alert("***** ERROR: Javascript can not find flash audio play function.");
			return;
		}
	} else {
		alert("***** ERROR: Javascript can not find flash audio player, name: " + this.movieName);
		return;
	}
	this.writeControlLink("stopIt", this.stopImage, _id, _fil);
	this.playingId = _id;	
	this.playingFile = _fil;	
	//alert("playIt - Out");
}

//
//	Initializes or updates the contents of a control div.
//
//	Arguments:
//		- _jfcn: name of method to call, either playIt or stopIt.
//		- _img: filename of associated control image.
//		- _id: id of div whose contents will be set.
//		- _fil: name of audio file to play, or to remember.
//
//	Override to provide text based control links.
//
AudioControl.prototype.writeControlLink = function(_jfcn, _img, _id, _fil) {
	var snippet = "<a href=\"javascript:" + this.varName + "." + _jfcn + "(\'" + _id + "\', \'" + _fil + "\')\"><img src=\"" + this.imageDir + _img + "\" border=\"0\"></a>";
	//if (_jfcn == "stopIt") {
	//	alert("Writing control link: " + snippet);
	//}
	document.getElementById(_id).innerHTML = snippet;
}

//
//	Stop playing the file associated with the specified div control.
//  Called in response to a control link activation.
//
AudioControl.prototype.stopIt = function(_id, _fil) {
	//alert("stopIt - In, id: " + _id + ", file: " + _fil);
	if (this.timerID) {
		clearInterval(this.timerID);
		this.timerID = 0;
	}
	var fm = this.getAudioPlayerMovie();
	if (fm) { 
		if (fm.stopPlayingAudioFile) { 
			//var sts = fm.getStatusInfo();
			//alert("status before stopping: " + sts);
			fm.stopPlayingAudioFile();
			//sts = fm.getStatusInfo();
			//alert("status after stopping: " + sts);
		} else {
			alert("***** ERROR: Javascript can not find flash audio stop function.");
			return;
		}
	} else {
		alert("***** ERROR: Javascript can not find flash audio player, name: " + this.movieName);
		return;
	}
	this.writeControlLink("playIt", this.playImage, _id, _fil);
	this.playingId = "";
	this.playingFile = "";
	//alert("stopIt - Out");
}

//
//	Check player for errors.
//
//  Checks status string for "error" substring (case-insensitive).
//  So make sure any error statuses returned by audio-player include that substring.
//  Likewise, make sure any non-error statuses do not include that substring.
//
//	Note: if player has error loading a file (the most common error), the status will be
//  IOError. Other statuses are "playing", "stopped", ...
//
AudioControl.prototype.isPlayerHappy = function() {
	var fm = this.getAudioPlayerMovie();
	if (fm) { 
		if (fm.getStatusInfo) { 
			var sts = fm.getStatusInfo(); // returns a string.
			var pattern = /error/i;       // regular expression.
			if (pattern.test(sts)) {
				return false;
			} else {
				return true;
			}
		} else {
			alert("***** ERROR: Javascript can not find flash audio status function.");
			return;
		}
	} else {
		alert("***** ERROR: Javascript can not find flash audio player, name: " + this.movieName);
		return;
	}
}

