/**
 * Copyright (c) 2007, Carl S. Yestrau
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Feature Blend nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Carl S. Yestrau ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Carl S. Yestrau BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
function FlashTML(minVersion, source, width, height, options){
	var self = this;
	var baseElement = document.createElement("div");
	var options = options || {};
	var winIE = ((navigator.appVersion.toLowerCase().indexOf("win")!=-1) && (navigator.appName=="Microsoft Internet Explorer"));
	var idCount = FlashTML.idCount++;
	var namespaceAdded = false;
	var namespaceName = "flashtml";
	var namespaceURN = "http://www.featureblend.com/2007/flashtml/";
	self.domTemplate = "";
	self.innerHTML = "";
	self.xhtml = "";
	self.inDocumentElement = "";
	var getCabVersion = function(minVersion){
		return minVersion + ",0,0,0";//B+
	}
	var getNameValueAttrFromOptions = function(name){
		return (typeof options[name] != "undefined")?getNameValueAttributes(name, options[name].toString()):"";
	}
	var getNameValueAttributes = function(name, value){
		return {
			"@name":name,
			"@value":value
		}
	}
	var createElementFromRule = function(name, target){
		var newElement = safeCreateElement(name.replace("#",""));
		return target.appendChild(newElement);
	}
	var getID = function(){
		return options.id || FlashTML.idPattern + idCount;
	}
	var setAttributeFromRule = function(name, value, target){
		target.setAttribute(name.replace("@",""), value);
	}
	var safeCreateElement = function(name){
		if((name=="object" || name=="param") && document.namespaces){
			if(!namespaceAdded){
				document.namespaces.add(namespaceName, namespaceURN);
				namespaceAdded = true;	
			}
			return document.createElement(namespaceName + ":" + name);
		}else{
			return document.createElement(name);
		}
	}
	var removeNameSpace = function(str){
		str = str.replace(/<\?xml([^>]*)>/, "");
		str = str.replace(eval("/"+namespaceName+":/g"),"");
		str = str.replace(/><\/param>/g,">");
		str = str.replace(/(<param )(.*?)(>)/g, "<param $2 \/>");
		return str;
	}
	var parseRules = function(position, target){
		for(var i in position){
			if(i.charAt(0)=="#"){
				if(typeof position[i] == "object" && position[i].length){
					for(var j=0; j<position[i].length; j++){
						if(position[i][j]()!=""){
							var appendedElement = createElementFromRule(i, target)
							parseRules(position[i][j](), appendedElement);
						}
					}
				}else if(typeof position[i] == "function" && position[i]()!=""){
					var appendedElement = createElementFromRule(i, target)
					parseRules(position[i](), appendedElement);
				}
			}else if(i.charAt(0)=="@"){
				if(typeof position[i] == "function" && position[i]()!=""){
					setAttributeFromRule(i, position[i](), target);
				}else if(typeof position[i] == "string"){
					setAttributeFromRule(i, position[i], target);
				}
			}
		}
	}
	var structuralRules = {
	    "#object":function(){
	    	return {
	    		"@type":function(){
	    			return (!winIE)?"application/x-shockwave-flash":"";
	    		},
		    	"@codebase":function(){
		    		return (winIE)?"http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab#version="+getCabVersion(minVersion):"";
		    	},
		    	"@classid":function(){
		    		return (winIE)?"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000":"";
		    	},
		    	"@data":function(){
		    		return (!winIE)?source:"";
		    	},
		    	"@width":function(){
		    		return width.toString();
		    	},
		    	"@height":function(){
		    		return height.toString();
		    	},
		    	"@id":function(){
		    		return getID();
		    	},
		    	"#param":[
		    		function(){
		    			return (winIE)?getNameValueAttributes("movie", source):"";
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("swliveconnect");
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("play");
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("loop"); 
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("menu"); 
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("quality"); 
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("scale"); 
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("align"); 
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("salign"); 
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("wmode"); 
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("bgcolor");
		    		},
		    		function(){
		    			return getNameValueAttrFromOptions("base");
		    		},
		    		function(){
		    			//TODO: Add length check to 64KB (65535 bytes) in length.
		    			var result = "";
		    			if(options.flashvars){
		    				var flashVarsStr = (typeof options.flashvars == "object")?FlashTML.getQueryStrFromObj(options.flashvars):encodeURI(options.flashvars);
		    				result = getNameValueAttributes("flashvars", flashVarsStr);
		    			}
		    			return result;
		    		}
		    	]
	    	}
	    
	    }
	}
	self.append = function(target){
		return addToElement(target, false);
	}
	self.replace = function(target){
		return addToElement(target, true);
	}
	var addToElement = function(target, replace){
		var result = false;
		var targetObj = (typeof target=="object")?target:document.getElementById(target);
		if(!self.inDocumentElement){
			if(winIE){
				if(replace){
					targetObj.innerHTML = self.xhtml;
				}else{
					targetObj.innerHTML += self.xhtml;
				}
				self.inDocumentElement = document.getElementById(getID());
				window.attachEvent("onunload", self.garbageCollection);
			}else{
				if(replace){
					while (targetObj.firstChild) {
					  targetObj.removeChild(targetObj.firstChild);
					}					
				}
				self.inDocumentElement = targetObj.appendChild(baseElement.childNodes[0]);
			}
			result = self.inDocumentElement;
		}
		return result;
	}
	self.garbageCollection = function(){
		if(winIE && self.inDocumentElement){
			self.inDocumentElement = null;
		}
	}
	self.FlashTML = function(){
		parseRules(structuralRules, baseElement);
		self.domTemplate = baseElement.childNodes[0];
		self.innerHTML = baseElement.innerHTML;
		self.xhtml = removeNameSpace(self.innerHTML);
	}();
}
FlashTML.getQueryStrFromObj = function(nameValue){
	var str = "";
	for(var i in nameValue){
		str += (i + "=" + nameValue[i] + "&");
	}
	return encodeURI(str.substring(0, str.length-1));
}
FlashTML.idCount = 0;
FlashTML.idPattern = "__flash-tml-";
