/**
 * FlashBack - jquery.flashback.js
 *
 * Cross-browser compatible flash/javascript interaction plugin.
 * Requires cross-browser semantic flash nested object structure, detailed here: http://www.alistapart.com/articles/byebyeembed/
 * div.flashData should contain the HTML returned to flash as XML.
 *
 * Typical Usage:
 *
 * //settings object declared in a scope accessable to flash movie
 * (function($){
 * 		var id = $flashCount, // velocity variable
 * 			config = {
 * 				container: '.widgetType',
 * 				beforeReady: function (flashObj){
 * 					// stuff goes here that happens before flash gets <data>
 * 				},
 * 				afterReady: function (flashObj) {
 * 					// stuff goes here that happens after flash gets <data>
 * 				}
 * 			};
*		jQuery.fn.flashBack.addConfig(id, config, debug);
 * })(jQuery);
 *
 * Dependencies: jQuery, flashObj.setData
 *
 * Ready functions:
 * 		both used for attaching js event handling to html elements within scope of jQuery selected set
 * 		beforeReady also used for attaching js methods to the flash object for txt and dom manipulation
 * 		afterReady used to visually indicate loaded state; attach events for UI elements once they exist and have a flashObject with exposed methods to call
 *
 * @project FlashBack
 * @author James Vivian
 * @version 1.1
 * @param settings.beforeReady	anonymous function executed after flash is passed XML
 * @param settings.afterReady	anonymous function executed after flash is passed XML
 * @param settings.debug		flag for debug mode
 * @param settings.getData		executed on $(el).each, regexs strip container down to div.flashData, returning the contents as an XML <data> node;
 * 								in debug mode, <data> node passed to console.log
 * @param settings.container: 	not used by flashback plugin, jQuery css selector used by flash movie to scope flashback execution, defaults to '.widget'
 *
 * // Depricated: @param settings.flashReady	js function exposed by flash that would be called on flashback execution
 *
 *
 * 0.9 Notes: Limited debug mode to window.console.log only.  Fixed scope for afterReady function.
 *
 * 1.0 Notes:
 * - removed setTimeout polling for .flashReady on flash objects.
 * - flash calls flashback on itself, Using rely on jQuery.ready() stack execution.
 *
 * 1.1 Notes:
 * - config handling via flashBack.addConfig() method
 * - revised checks for existence of flash object and supporting methods
 * - cleaned up extraneous comments
 * - more verbose logging statements
 *
 */
(function () {
	var window = this,
		$ = window.jQuery,
		// remove everything up to and including the data div tag
		stripToData = new RegExp('\\s*?(?:<!--.+?-->(?:.|\\s)*?)?<\\w+(?:.|\\s)*?<div class="flashData">\\s*', 'm'),
		// remove end tags
		stripAfterData = new RegExp('\\s*?</div><!--.+?>-->(?:.|\\s)*$', 'm'),
		// return semantic HTML as XML to flash movie
		getData = function () {
			var data = '<data>' + $(this).html().replace(stripToData, '').replace(stripAfterData, '') + '</data>';
			return data;
		};
	$.fn.extend({
		flashBack: function (settings) {
			var objDomIndex = ($.browser.msie || $.browser.safari) ? 0 : 1,		// find correct flash container to use depending on browser
				isFn = function (fn) {
					return typeof fn === 'function';
				};
			settings = $.extend({
				// enable debug to log results of getData function
				debug: false,
				// function called before flashReady fires
				beforeReady: null,
				// function called after flashReady fires
				afterReady: null,
				// return semantic HTML as XML to flash movie
				encodeData: false,
				getData: function (debug) {
					var data = settings.encodeData ? encodeURIComponent(getData.apply(this)) : getData.apply(this);
					if (debug) {
						console.log('[flashBack] settings.encodeData:', settings.encodeData);
						console.log('[flashBack] getData - scope: ', this, ' returned data: ', data);
					}
					return data;
				}
			}, settings);
			settings.debug = (settings.debug && typeof window.console === "object" && typeof window.console.log === "function");
			return $(this).each(function () {
				var flashObj  = $('object', this)[objDomIndex],
					data = {};
				if (flashObj && isFn(settings.getData) && isFn(flashObj.setData)) {
					if (isFn(settings.beforeReady)) {
						settings.beforeReady.apply(this, [flashObj]);
					}
					data.xmlData = settings.getData.apply(flashObj, [settings.debug]);
					flashObj.setData(data);
					if (isFn(settings.afterReady)) {
						settings.afterReady.apply(this, [flashObj]);
					}
				}
			});
		}
	});
	$.fn.extend($.fn.flashBack, {
		config: {},
		addConfig: function (id, config, debug) {
			debug = ((config && config.debug) || debug) && (typeof window.console === "object" && typeof window.console.log === "function");
			if (debug) {
				console.log('[flashBack] addConfig - id: ', id, ', config: ', config);
				config.debug = debug;
			}
			if (id) {
				$.fn.flashBack.config[id] = config || {};
			}
		},
		getData: getData
	});
}());

/* possible modifications:
 *
 * addition of clean error handling if !flashObj or !isFn(flashObj.getData)
 *
 *
*/