/*
	flashctrl.js
	
	v0.12, 2007-02-07, Christian Augustin

*/
/*
	JavaScript 1.3+, W3C DOM Level 2
	FlashPlayer 6+
	
	The scope of this module is to provide a standard set of high-level
	functions to control the FlashPlayer plugin in most modern browsers and
	to hide some of its implementation specific differences (plugin vs.
	ActiveX control).
	
	Some brute-force methods to kick the flash player off the page under
	nearly all circumstances and reinstantiate it are also provided ...
	
	For future releases an optional control panel is planned.
	
	With MSIE and the ActiveX control, some parameters are perhaps lost
	with remove() and insert().
	
	Non-functional FlashPlayer methods with file protocoll (in practice!):
	
	- Rewind()
	- Back()
	- Forward()
	- GotoFrame()
	- LoadMovie()
	- GetVariable()
	- SetVariable()
	
	This leaves only Play() and StopPlay() to that could be reliably used!
	
	
	ToDo
	- Simulate more FlashPlayer methods (LoadMovie etc.).
	- Enhanced methods to control FlashPlayer or to simulate it!
	- Implement .resume()!
	- There is a problem with Safari prior to 1.2 -- check version 1.1!
	. try/catch for some critical FlashPlayer accesses. (Not functional!)
	- Check for critical functions if using file protocoll.
	
	History
	2007-02-07 cma: Small bugfix with MSIE stylesheet.
	2007-02-05 cma: Trying to make the global updateLayout() obsolete ...
	2007-01-31 cma: Simplified interface (the wrapper is a "true" replacement).
	2007-01-30 cma: Extending ...
	2006-07-14 cma: Some additional problems with AppleWebKit/125.4 fixed.
	2006-07-13 cma: Init bug fixed; problem with AppleWebKits prior to "130" partly fixed.
	2006-04-10 cma: Improved page layout on load.
	2006-04-05 cma: Added FlashVars detection for MSIE 5.x/Win.
	2006-03-19 cma: Improving ...
	2006-03-12 cma: .displaynone() added; found reason for "Bad NPObject ..."!
	2006-03-04 cma: .updateLayout() -- experimental implementation.
	2006-02-21 cma: Extending.
	2006-02-19 cma: Initial setup.
	
	Special Gecko problem:

	If a plugin object or one of its parents is set to display=none, the
	internal plugin data is destroyed! This gives a "Bad NPObject as private data"
	error (this seems to be an ongoing topic even with Firefox 1.5 and up).

	This can lead to problems with several JavaScript modules that manipulate
	the DOM object tree while loading the page or that use display=none to hide
	some part of the page ... (no problem with visibility=hidden).
	
	There seems to be a special problem with Firefox 1.5, giving the "Bad NPObject ..."
	error after "re-wrapping" the object ... this has to be investigated ...
	
*/


/* ===========================
   Constructor function ...
=========================== */

function FlashCtrl(obj) {
	if (!obj) return void 0;
	if (!obj.type || obj.type != 'application/x-shockwave-flash') return obj;

	//alert(obj.GetVariable("$version"));

	/* Create wrapper div for killing and reviving etc. ... */
	// This should be a SPAN, because object is normally inline --
	// but than we have to look at the currentStyle to get some
	// CSS attributes right ...

	var that = document.createElement('div');
	if (!that) return obj;
	that.className = "flashWrapper";
	that._n = FlashCtrl.flashs.length;
	FlashCtrl.flashs[that._n] = that;
		
	/* Scan attributes and parameters ... */

	that._attrs = new Object();
	for (var a=0; a<obj.attributes.length; a++) {
		var attr = obj.attributes[a];
		if (attr.nodeName && attr.nodeValue)
			that._attrs[attr.nodeName.toLowerCase()] = attr.nodeValue;
	}
	/* This is to get the original values with MSIE 5.x/Win ... */
	if (!window.opera && document.all) {
		that._attrs.width = obj.width;
		that._attrs.height = obj.height;
	}

	/*
		MSIE 5+6/Win always return a style object, even with .getAttribute!
		But there's a little trick with .cssText ...
	*/
	if (!window.opera && document.all && obj.getAttribute('style')
			&& obj.getAttribute('style').cssText)
		that._attrs.style = obj.getAttribute('style').cssText;
	/* And this is for MSIE 5.x/Mac ... it's so silly ... */
	if (document.all && that._attrs.style && that._attrs.style.match('{'))
		that._attrs.style = that._attrs.style.replace(/\{(.*)\}/, '$1');

	//for (var test in that._attrs) alert(test + ': ' + that._attrs[test]);
	
	that._params = new Object();
	if (obj.childNodes && obj.childNodes.length) {
		/* This is for all "real" browsers and MSIE 6/Win ... yeah! */
		var p = obj.firstChild;
		while (p) {
			if (p.nodeType == 1 && p.tagName.toLowerCase() == 'param')
					that._params[p.name.toLowerCase()] = p.value;
			p = p.nextSibling;
		}
	} else if (!window.opera && document.all && obj.Movie) {
		/* This is for the silly rest, named MSIE 5.x/Win ... */
		if (obj.Movie) that._params.movie = obj.Movie;
		if (obj.FlashVars) that._params.flashvars = obj.FlashVars;
		if (typeof obj.Playing != 'undefined') that._params.play = obj.Playing;
		if (typeof obj.Loop != 'undefined') that._params.loop = obj.Loop;
		if (obj.Quality) that._params.quality = obj.Quality2;
		if (obj.BGColor) that._params.bgcolor = '#' + obj.BGColor;
		if (obj.Scale) that._params.scale = obj.Scale;
		if (typeof obj.DeviceFont != 'undefined') that._params.devicefont = obj.DeviceFont;
		if (typeof obj.Menu != 'undefined') that._params.menu = obj.Menu;
		if (obj.WMode) that._params.wmode = obj.WMode;
		if (obj.SAlign) that._params.salign = obj.SAlign;
		if (obj.AllowScriptAccess) that._params.allowscriptaccess = obj.AllowScriptAccess;
	}
	
	//for (var test in this.params) alert(test + ': ' + this.params[test]);
	
	
	/* Attribute and parameter cleanup ... */
	
	if (that._params.movie) that._attrs.data = that._params.movie;
	if (!that._params.movie && that._attrs.data) that._params.movie = that._attrs.data;
	if (that._attrs.classid) delete(that._attrs.classid);
	if (that._attrs.codebase) delete(that._attrs.codebase);
	
	/* Some additional styling ... */
	
	that.style.width = that._attrs.width + 'px';
	that.style.height = that._attrs.height + 'px';
	if (that._attrs.id) {
		obj.id = '';
		that.id = that._attrs.id;
		//delete(this._attrs.id); // This would be a disaster with AppleWebKit/125.4 ...
	}
	if (that._params.bgcolor) that.style.background = that._params.bgcolor;
	
	/* Get object replacement */
	// This is a little bit dirty, but the only way for MSIE including 7 ...
	
	that._replacement = obj.innerHTML;
	if (that._replacement) {
		that._replacement = that._replacement.replace(/<param[^>]*>/ig, '');
		that._replacement = that._replacement.replace(/^\s+/, '');
		that._replacement = that._replacement.replace(/\s+$/, '');
	};

	/* Simulate Flash Player functions on wrapper ... */

	for (var m in FlashCtrl.prototype) that[m] = FlashCtrl.prototype[m];
	
	/* And off we go ... */
	
	obj.parentNode.replaceChild(that, obj);
	obj = null;
	return that;

}



/* =======================
   Instance methods ...
======================= */

FlashCtrl.prototype.isVisible = function() {
	/*
		If we can't get the current style, we don't know if the flash
		is visible or not -- but if we assume "visible" it is less disruptive ...
	*/
	var cs = FlashCtrl.getCurrentStyle(this);
	if (!cs) return true;
	var n = this;
	while (n && n.nodeType == 1) {
		cs = FlashCtrl.getCurrentStyle(n);
		if (cs.visibility == 'hidden' || cs.display == 'none') return false;
		n = n.parentNode;
	}
	return true;
};

FlashCtrl.prototype.displayNone = function() {
	var cs = FlashCtrl.getCurrentStyle(this);
	if (!cs) return false;
	var n = this;
	while (n && n.nodeType == 1) {
		cs = FlashCtrl.getCurrentStyle(n);
		if (cs.display == 'none') return true;
		n = n.parentNode;
	}
	return false;
};

FlashCtrl.prototype.insertFlash = function() {
	if (this.player || this.displayNone()) return;
	var useEmbed = navigator.userAgent.match(/AppleWebKit\/([789]\d\D|1[012]\d\D)/);
	/*
	// The following code is unreliable and non-functional width MSIE 5.x/Win,
	// but it could be useful for future use, so let's remember it!
	// Attention! The following sequence is crucial with MSIE 6/Win!
	var d = document.createElement('object');
	for (var p in this._params) {
		var t = document.createElement('param');
		t.setAttribute('name', p);
		t.setAttribute('value', this._params[p]);
		d.appendChild(t);
	};
	this.player = this.appendChild(d);
	for (var a in this._attrs)
		d.setAttribute(a, this._attrs[a]);
	*/
	if (useEmbed) {
		/* Fix problem with old AppleWebKits ... use embed instead of object (urgh ...) */
		/* No solution to get JS control for Operas prior to 9.00 on Mac OS X ... */
		var o = '<embed';
		for (var a in this._attrs) {
			if (a == 'id') continue;
			o += ' ' + ((a == 'data') ? 'src' : a) + '="' + this._attrs[a] + '"';
		};
		for (var p in this._params) {
			if (p == 'movie') continue;
			o += ' ' + p + '="' + this._params[p] + '"';
		};
		o += ' name="flashctrlEmbed' + this._n + '"';
		o += '><\/embed>\n';
	} else {
		var o = '<object';
		for (var a in this._attrs) {
			if (a == 'id') continue;
			o += ' ' + a + '="' + this._attrs[a] + '"';
		};
		o += '>\n';
		for (var p in this._params)
			o += '<param name="' + p + '" value="' + this._params[p] + '" />\n';
		o += '<\/object>\n';
	};
	this.innerHTML = o;
	this.firstChild.style.visibility = 'inherit';
	//this.player = (useEmbed)
	//	? document.embeds['flashctrlEmbed' + this.n]
	//	: this.firstChild;
	this.player = this.firstChild;
};

FlashCtrl.prototype.removeFlash = function() {
	if (!this.player) return;
	//this.wrapper.removeChild(this.player);
	this.innerHTML = this._replacement;
	this.player = null;
};

FlashCtrl.prototype.resumeFlash = function() {
	this.insertFlash();
};



/* Control functions (redirected to bruce-force methods as needed) ... */

FlashCtrl.prototype.Play = function() {
	if (this.player && typeof this.player.Play != 'undefined')
		this.player.Play();
};

FlashCtrl.prototype.StopPlay = function() {
	if (this.player && typeof this.player.StopPlay != 'undefined')
		this.player.StopPlay();
};

FlashCtrl.prototype.Stop = FlashCtrl.prototype.StopPlay;

FlashCtrl.prototype.Rewind = function() {
	if (this.player && typeof this.player.Rewind != 'undefined') {
		var r = this.player.Rewind();
	}
};

FlashCtrl.prototype.Back = function() {
	if (this.player && typeof this.player.Back != 'undefined')
		this.player.Back();
};

FlashCtrl.prototype.Forward = function() {
	if (this.player && typeof this.player.Forward != 'undefined')
		this.player.Forward();
};

FlashCtrl.prototype.GotoFrame = function(n) {
	if (this.player && typeof this.player.GotoFrame != 'undefined')
		this.player.GotoFrame(n);
};

/* Query functions ... */

FlashCtrl.prototype.PercentLoaded = function() {
	if (this.player && typeof this.player.PercentLoaded != 'undefined')
		return this.player.PercentLoaded()
	else
		return (this.player) ? 100 : 0;
};

FlashCtrl.prototype.IsPlaying = function() {
	if (this.player && typeof this.player.IsPlaying != 'undefined')
		return this.player.IsPlaying()
	else
		return false;
};

FlashCtrl.prototype.TotalFrames = function() {
	if (this.player && typeof this.player.TotalFrames == 'function')
		return this.player.TotalFrames()
	else if (this.player && typeof this.player.TotalFrames != 'undefined')
		return this.player.TotalFrames
	else
		return 0;
};

FlashCtrl.prototype.CurrentFrame = function() {
	if (this.player && typeof this.player.CurrentFrame != 'undefined')
		return this.player.CurrentFrame()
	else
		return 0;
};





/* ==========================
   Class properties ...
========================== */

FlashCtrl.flashs = new Array();
FlashCtrl.fromFile = document.location.href.toLowerCase().indexOf('file:') == 0;

/* Presets ... */

FlashCtrl.minVersion = 6;
FlashCtrl.requiredVersion = 6;
FlashCtrl.stopWhenInvisible = true;
FlashCtrl.checkInterval = 500;
FlashCtrl.forcedStop = true;

/* Initial CSS ... */

FlashCtrl.oldIE = !!(!window.opera && document.all && !(window.XMLHttpRequest && document.compatMode == 'CSS1Compat'));

FlashCtrl.initialCSS = '<style class="text/css">';
FlashCtrl.initialCSS += 'object[type="application/x-shockwave-flash"]/* */ {visibility: hidden;}'
if (FlashCtrl.oldIE) FlashCtrl.initialCSS += 'object {visibility: expression((type == "application/x-shockwave-flash") ? "hidden" : "inherit");}';
FlashCtrl.initialCSS += '<\/style>';


/* ====================
   Class methods ...
==================== */

FlashCtrl.getPresets = function() {
	if ((typeof presets == 'undefined') || !presets.FlashCtrl) return;
	for (var p in presets.FlashCtrl) FlashCtrl[p] = presets.FlashCtrl[p];
};

FlashCtrl.findFlashObjects = function() {
	if (!document.getElementsByTagName) return;
	var objs = document.getElementsByTagName('object');
	var flshs = new Array();
	if (objs) {
		for (var i=0; i<objs.length; i++) {
			var o = objs[i];
			if (o.type && o.type == 'application/x-shockwave-flash') flshs[flshs.length] = o;
		}
	};
	if (flshs.length) {
		for (var j=0; j<flshs.length; j++) new FlashCtrl(flshs[j]);
	};

};

FlashCtrl.getCurrentStyle = function(elm) {
	return (elm.currentStyle)
		? elm.currentStyle
		: ((document.defaultView && document.defaultView.getComputedStyle)
		? document.defaultView.getComputedStyle(elm, null)
		: null);
};

FlashCtrl.updateLayout = function() {
	for (var i=0; i < FlashCtrl.flashs.length; i++) {
		var f = FlashCtrl.flashs[i];
		if (!f.isVisible()) f.removeFlash()
		else f.resumeFlash();
	}
};

FlashCtrl.removeAllFlashs = function() {
	for (var i=0; i<FlashCtrl.flashs.length; i++)
		FlashCtrl.flashs[i].removeFlash();
};

FlashCtrl.insertAllFlashs = function() {
	for (var i=0; i<FlashCtrl.flashs.length; i++)
		FlashCtrl.flashs[i].insertFlash();
};

FlashCtrl.resumeAllFlashs = function() {
	for (var i=0; i<FlashCtrl.flashs.length; i++)
		FlashCtrl.flashs[i].resumeFlash();
};

FlashCtrl.hideAllFlashs = function() {
	for (var i=0; i<FlashCtrl.flashs.length; i++)
		FlashCtrl.flashs[i].style.visibility = 'hidden';
	//FlashCtrl.updateLayout();
};

FlashCtrl.showAllFlashs = function() {
	for (var i=0; i<FlashCtrl.flashs.length; i++)
		FlashCtrl.flashs[i].style.visibility = 'inherit';
	//FlashCtrl.updateLayout();
};

FlashCtrl.flashByIdx = function(idx) {
	if (idx < 0 || idx >= FlashCtrl.flashs.length) return null;
	return FlashCtrl.flashs[idx];
};



/* =================
   Initialize ...
================= */

if (document.getElementsByTagName 
	&& document.createElement
	&& (!window.opera || document.createDocumentFragment)) {
	
	FlashCtrl.getPresets();
	FlashCtrl.initComplete = false;
	
	document.write(FlashCtrl.initialCSS);
	
	FlashCtrl.init = function() {

		if (FlashCtrl.initComplete) return true;
		
		FlashCtrl.findFlashObjects();
		window.setInterval(FlashCtrl.updateLayout, FlashCtrl.checkInterval);
		
		FlashCtrl.initComplete = true;
		return true;
	}
	
	if (window.onDomReady) {
		window.onDomReady(FlashCtrl.init);
	} else if (typeof pageComplete == 'function') {
		FlashCtrl.oldPageComplete = pageComplete || function(){};
		pageComplete = function() {
			FlashCtrl.oldPageComplete();
			FlashCtrl.init();
		};
	} else {
		FlashCtrl.oldOnload = window.onload || function(){};
		window.onload = function() {
			FlashCtrl.oldOnload();
			FlashCtrl.init();
		};
	};

};

/* End of flashctrl.js */
