/**
 * @namespace This contains methods to control and write Flash objects.
 * @author Tom McCourt / Oliver Bishop
 * @version 0.0.2
 * @changeLog Changed the namespace from UKISA.util.Flash to UKISA.Flash.
 */
var UKISA = UKISA || {};
UKISA.util = UKISA.util || {};

/**
 * @namespace Flash SWF, FLV writing methods.
 * @memberOf UKISA.util
 */
UKISA.Flash = {
	config: {
		styleUrl: "/files/styles/",			// This is the location of the styles - for the swfobject.js file.
		scriptUrl: "/files/scripts/",			// This is the location of the scripts - for the swfobject.js file.
		yuiUrl: "/files/yui/build/",			// This is the location of YUI scripts that may be required.
		url: "/files/flash/",			// This must be the URL of the flash folder (set to be relative to the site root).
		movieUrl: "/files/movies/",		// This must be the URL of the movie folder (set to be relative to the site root).
		supports: "8.0.0",					// Default Flash version that is supported.
		width: 512,							// Default width.
		height: 288,						// Default height.
		params: {
			"quality": "high",
			"scale": "noscale",
			"pluginspage": "http://www.macromedia.com/go/getflashplayer",
			"wmode": "transparent"
		},
		vars: {
			"MM_ComponentVersion": "1",
			"skinName": "/files/flash/Halo_Skin_3",
			"autoPlay": "false",
			"autoRewind": true
		}
	},
	/**
	 * This stores a copy of the config with updates settinfgs from the embed function.
	 */
	context: {},
	/**
	 * This stores any skin that have padding therefore adding to an FLV size.
	 */
	skins: {
		"Halo_Skin_3": {
			top: 11,
			right: 11,
			bottom: 40,
			left: 11
		}
	},
	/**
	 * This will try and load the swfobject if it is not explicitly set on the page.
	 */
	checkSWFObject: function(success) {
		var instance, failure, getter;

		instance = this;

		failure = function() {
			alert("Sorry, there has been a problem trying to play the video.");
		};

		if (typeof swfobject === "undefined") {
			if (typeof YAHOO !== "undefined" && typeof YAHOO.util.Get !== "undefined") {

				this.log("swfobject cannot be found.");

				getter = YAHOO.util.Get.script(this.context.scriptUrl + "swfobject.js", { 
					onSuccess: function() { 
						success.call(instance);
					},
					onFailure: function() {
						failure.call(instance);
					}
				});
				
			} else {
				this.log("YAHOO or YAHOO.util.Get and swfobject cannot be found.");
				failure.call(instance);
			}
		} else {
			this.log("SWFObject found.");
			success.call(instance);
		}
	},
	/**
	 * Embed a FLV video.
	 */
	embedVideo: function(movie, el, width, height, vars, params, options) {
		this.context.vars.streamName = this.context.movieUrl + movie.substring(0, movie.indexOf("."));

		this.checkSWFObject(function() {
			this.log("Flash successful");

			swfobject.embedSWF(
				this.context.url + "flv_player.swf",
				el, 
				width, 
				height, 
				this.context.supports, 
				null, 
				this.context.vars, 
				this.context.params
			);
		});	
		
		this.log("Embedding a FLV movie");
		this.log("FLV path: " + this.context.vars.streamName);
		this.log("Movie path: " + this.context.url + movie);
	},
	/**
	 * Embed a Flash movie.
	 */
	embedFlash: function(movie, el, width, height, vars, params, options) {

		this.log("Movie path: " + this.context.url + movie);
		this.log("Movie width: " + this.context.width);
		this.log("Movie height: " + this.context.height);

		this.checkSWFObject(function() {
			this.log("Flash successful");

			swfobject.embedSWF(
				this.context.url + movie, 
				el, 
				width, 
				height, 
				this.context.supports, 
				null, 
				this.context.vars, 
				this.context.params
			);
		});
	},
	/**
	 * Embed a either a Flash movie of FLV by specifying the file extension e.g. video.flv.
	 */
	embed: function(movie, el, width, height, vars, params, options) {
		var i;

		// Create a new copy of the config for default values.
		this.reset(vars, params);

		var size = this.size(movie, width, height, options);
		width = size.width;
		height = size.height;

		// Detect if this is trying to get a Flash FLV.
		if (movie.toLowerCase().indexOf(".flv") !== -1) {
			return this.embedVideo.call(this, movie, el, width, height, vars, params, options);
		} else {
			return this.embedFlash.call(this, movie, el, width, height, vars, params, options);
		}
	},
	/**
	 * Opens a modal window to play the Flash in.
	 */
	modal: function(movie, title, width, height, vars, params, options) {
		var cloneConfigi, panel, instance, create, instance, getterCSS, getterScript;

		// Kill any old YUI Panel
		if (this.context && this.context.modal) {
			this.context.modal.destroy();
		}

		// Create a new copy of the config for default values.
		this.reset(vars, params);

		create = function() {

			// This creates the custom shadow around the Panel box.
			panel = document.createElement("div");

			hd = panel.cloneNode(false);
			bd = panel.cloneNode(false);
			ft = panel.cloneNode(false);

			panel.id = "ukisa-flash-modal";
			panel.className = "yui-panel-container yui-dialog shadow";
			hd.className = "hd";
			bd.className = "bd";
			ft.className = "ft";

			panel.appendChild(hd);
			panel.appendChild(bd);
			panel.appendChild(ft);

			document.body.appendChild(panel);

			instance = this;

			this.context.modal = new YAHOO.widget.Panel("ukisa-flash-modal", { 
				fixedcenter: true,
				modal: true,
				visible : false, 
				close: true,
				underlay: "shadow",
				constraintoviewport: true,
				zIndex: 1100,
				autofillheight: "body"
			});

			if (title && title.length) {
				this.context.modal.setHeader(title);
			}

			title = title || "this";

			this.context.modal.renderEvent.subscribe(function() {
				var el, region, movieWidth, movieHeight, regionWidth, regionHeight;

				instance.log("renderEvent");
				instance.log("context.width: " + instance.context.width);
				instance.log("context.height: " + instance.context.height);

				var size = instance.size(movie, width, height, options);
				movieWidth = size.width;
				movieHeight = size.height;

				el = document.getElementById("ukisa-flash-modal-flash");
				el.style.width = movieWidth + "px";
				el.style.height = movieHeight + "px";

				region = YAHOO.util.Dom.getRegion("ukisa-flash-modal");
				regionWidth = region.right - region.left;
				regionHeight = region.bottom - region.top;

				instance.embed(movie, "ukisa-flash-modal-flash", width, height, vars, params, options);

				instance.log("regionWidth: " + regionWidth);
				instance.log("regionHeight: " + regionHeight);

				// Remove the border width :(
				regionWidth -= 2;
				regionHeight -= 2;

				this.cfg.setProperty("width", regionWidth + "px");
				this.cfg.setProperty("height", regionHeight + "px");
			});	

			this.context.modal.setBody("<div id=\"ukisa-flash-modal-flash\">Flash plugin is required to view \"" + title + "\".</div>");
			this.context.modal.hideEvent.subscribe(function() {
				// This is to remove the Flash movie
				UKISA.Flash.remove("ukisa-flash-modal-flash");
			});	
				
			this.context.modal.render();
			this.context.modal.show();
		};

		instance = this;

		if (typeof YAHOO !== "undefined" && typeof YAHOO.widget.Panel != "undefined") {
			create.call(instance);
		} else {
			getterCSS = YAHOO.util.Get.css(this.context.styleUrl + "container.css");

			getterScript = YAHOO.util.Get.script(this.context.yuiUrl + "container/container-min.js", { 
				onSuccess: function() { 
					create.call(instance);
				},
				onFailure: function() {
					alert("Sorry, there has been a problem trying to play the video.");
				}
			});
		}

		return false;
	},
	/**
	 * This is weird but useful. When passing in the FLV dimension, only the actual movie size is required.
	 * If a skin with a border (like the Halo skin) is used then there is additional padding around the FLV
	 * that needs to be taken into account when creating the Flash object. This looks up the skin name that is
	 * stored and adds the additional dimensions to the width and height.
	 *
	 * @param {String} movie				Name of the movie with file extension.
	 * @param {Int} width					Width of the Flash movie.
	 * @param {Int} height					Height of the Flash movie.
	 * @param {ObjectLiteral} options		The options - not sure why or how anymore... :(
	 */
	size: function(movie, width, height, options) {
		var skin, totalWidth, totalHeight;

		totalWidth = width || this.context.width;
		totalHeight = height || this.context.height;

		if (movie.toLowerCase().indexOf(".flv") !== -1) {
			skin = this.context.vars.skinName;

			if (options && options.vars && options.vars.skinName) {
				skin = options.vars.skinName;
			}

			skin = skin.split("/").pop();

			if (typeof this.skins[skin] !== "undefined") {
				this.log("Skin: " + skin);

				skin = this.skins[skin];
				totalWidth += skin.left + skin.right;
				totalHeight += skin.top + skin.bottom;
			}
		}
	
		this.log("Movie width: " + totalWidth);
		this.log("Movie height: " + totalHeight);

		return {"width": totalWidth, "height": totalHeight};
	},
	/**
	 * Safely removes a Flash movie from the page.
	 * @param {String} el Flash placeholder.
	 */
	remove: function(el) {
		if (typeof swfobject !== "undefined") {
			swfobject.removeSWF(el);
		}
	},
	/**
	 * For each time the Flash embed method is called, the default configuration parameters must be cloned
	 * and a normal assignment from the config to the context property will be passed by reference not value, so 
	 * the config must be cloned. This gets called twice for the Flash.modal as the width/height is required to
	 * calculate the size of the modal window when it has finished being written out. It's more strung out but it should mean that 
	 * the modal will size itself to the Flash movie dimensions making it easier to develop.
	 *
	 * @param {ObjectLiteral} vars			The Flash vars.
	 * @param {ObjectLiteral} params		The Flash params.
	 */
	reset: function(vars, params) {
		var clone, modal;

		// Sad but true for now - save the modal if there is one
		modal = (this.context && this.context.modal) ? this.context.modal : null; 

		this.context = null;

		clone = function(o) {
			if(typeof(o) != "object") return o;
			if(o == null) return o;

			var newO = new Object();

			for(var i in o) {
				newO[i] = clone(o[i]);
			}
			return newO;
		};

		this.context = new clone(this.config);

		if (modal) {
			this.context.modal = modal;
		}
		
		// Update the Flash vars.
		for (var i in vars) {
			if (typeof this.context.vars[i] !== "undefined") {
				this.context.vars[i] = vars[i];
			}
		}

		// Update the Flash params.
		for (var i in params) {
			if (typeof this.context.params[i] !== "undefined") {
				this.context.params[i] = params[i];
			}
		}
	},
	/**
	 * Log for Firebug debugging.
	 *
	 * @param {String} s Message log.
	 */
	log: function(s) {
		if (window.console) {
			console.log(s);
		}
	}
};

