/***************************************************************
*
*  @Application: Flash Thermometer v 1.0.1
*  @Author: Mark Tesla & James Rain
*  @Date: October 12, 2010
*
*  A configurable animated thermometer using Flash 9 (CS3).  
*  The object can be tweaked in color, display text, and size.
* 
****************************************************************/



/*
(((((( Reference ))))))


* The following is a list of all the paramters for the thermometer with default values
* This also serves as the "settings" property layout for the returned "myNewTherm" object instance.
* Create a new instance of FlashThermometer with the following parameters.


*** The only requirements are "containerID", start (or current_marker:{value_html:"0"}), goal (or goal_marker:{value_html:"0"})
*** The following examples are equivalent:
***
*** FlashThermometer("myDivID", {start:10, goal:55});
*** FlashThermometer("myDivID", {current_marker:{value_html:10}, goal_marker:{value_html:55}});
***
*** "start", "goal", and "markers" are simply convenience parameters for the much more extensive "current_marker", "goal_marker", and "gauge_markers"


@@ See "FlashThermometer_Demo.html" for live examples @@


var myNewTherm = FlashThermometer
(
  "containerID",            // The HTML container ID (eg. <DIV id='myID'>) which the Flash Thermometer will be inserted into (Type: String | REQUIRED)
  "swfPath",		   // OPTIONAL: The full path to the FlashThermometer.swf file  eg. "/swf/FlashThermometer.swf".  Defaults to the path of who called the FlashThermometer.js file (the HTML file).
  {
    start:"0",              // A value which MUST contain a number indicating the start/curent position of the thermometer fluid. You may use HTML. This is a convenience property for the "current_marker" property.  (Type: String | REQUIRED)
    goal:"0",               // A value which MUST contain a number indicating the end/goal of the thermometer fluid.  You may use HTML.  This is a convenience property for the "goal_marker" property.  (Type: String | REQUIRED)
    markers:[],             // An  array of #s indicating the display markers next to the thermometer.  You can use HTML.  This is a convenience property for the "gauge_markers" array property.  This only accepts an array of #s or strings and NOT objects like gauge_markers.  (Type: Array of Strings or Numbers)
    align:"top_center",     // The alignment of the flash object display within the container. (Type: String | Values: "top_left", "top_center", "top_right", "bottom_left","bottom_center","bottom_right","center_left","center_right")
    x_pos:0,		    // Adjust the therm object x position within the scene
    y_pos:0,		    // Adjust the therm object y position within the scene
    current_marker:         // The current position of the thermometer level.  * REQUIRED *
    {
        value_html:"0",     // The value the thermometer will display.  Some HTML tags may be used to format the value -- <A>, <B>, <FONT>, <I>, <U>.  The value is extracted from this by removing alls tags and non-number characters.  (Type: String | REQUIRED)
        alt_html:"",        // An alternative html to display that will show in place of value_html however value_html will still be used for the progress. Some HTML tags may be used to format the value -- <A>, <B>, <FONT>, <I>, <U>.  (Type: String)
        use_commas:true,    // Whether to digit group value_html using a comma (eg. 1234 will display as 1,234) (Type: Boolean]
        x_offset:0,         // The text display for the marker can be adjusted with an x offset. (Type:Number)
        y_offset:0,         // The text display for the marker can be adjusted with a y offset. (Type:Number)
        visible:true,       // Make the entire marker visible or not. (Type: Boolean)
        dash:               // The adjacent visual arrow pointing to the marker position on the thermometer
        {
            visible:true,   // Is the dash visible or not. (Type: Boolean)
            color:          // The color of the visible dash
            {
                bkg:"#ec2024", // The dash background color. Use the html color format of #RRGGBB (eg. "#FFFFFF"). (Type: String)
                ref:"#f1585b"  // The dash reflection color. Use the html color format of #RRGGBB (eg. "#FFFFFF"). (Type: String)
            },
            url:"",            // An altenate display for the dash based on a URL image or Flash SWF file (eg. "http://mysite.com/test.png"  or "/test.png").  (Type: String)
            x_offset:0,        // The x offset for the dash. (Type: Number)
            y_offset:0         // The y offset for the dash/ (Type: Number)
        }
    },        
    goal_marker:        // The goal value the thermometer will grow to.  * REQUIRED *
    {
        value_html:"0", // The value the thermometer will display.  Some HTML tags may be used to format the value -- <A>, <B>, <FONT>, <I>, <U>.  The value is extracted from this by removing alls tags and non-number characters.  (Type: String | REQUIRED)
        alt_html:"",    // An alternative html to display that will show in place of value_html however value_html will still be used for the progress. Some HTML tags may be used to format the value -- <A>, <B>, <FONT>, <I>, <U>. (Type: String)
        x_offset:0,     // The text display for the marker can be adjusted with an x offset. (Type:Number)
        y_offset:0,     // The text display for the marker can be adjusted with a y offset. (Type:Number)
        visible:true,   // Make the entire marker visible or not. (Type: Boolean)
        dash:           // The adjacent visual arrow pointing to the marker position on the thermometer
        {
            visible:true, // Is the dash visible or not. (Type: Boolean)
            color:        // The color of the visible dash
            {
                bkg:"#ec2024", // The dash background color. Use the html color format of #RRGGBB (eg. "#FFFFFF"). (Type: String)
                ref:"#f1585b"  // The dash reflection color. Use the html color format of #RRGGBB (eg. "#FFFFFF"). (Type: String)
            },
            url:"",            // An altenate display for the dash based on a URL image or Flash SWF file (eg. "http://mysite.com/test.png"  or "/test.png").  (Type: String)
            x_offset:0,        // The x offset for the dash. (Type: Number)
            y_offset:0         // The y offset for the dash/ (Type: Number)
        }
    },
    gauge_markers:[],          // Along the side of the thermometer are gauge values indicating the progress or benchmarks for the current marker.  Provide an array list of objects for these visual items.  The object parameters are similar to "goal_marker".  (Type: Array)
    color:    // The color of the thermometer.
    {
        outline:"#6b8e9e",     // Outline around thermometer. Use the html color format of #RRGGBB. (Type: String)
        glass:"#c5dfed",       // The inner glass. Use the html color format of #RRGGBB. (Type: String)
        glass_ref:"#e0ebf0",   // The inner glass reflection. Use the html color format of #RRGGBB. (Type: String)
        fluid:"#ec2024",       // The mercury fluid. Use the html color format of #RRGGBB. (Type: String)
        fluid_ref:"#ffffff",   // The reflection on the mercury fluid. Use the html color format of #RRGGBB. (Type: String)
        fluid_top:"#ef5760"    // The top of the fluid which indicates the current marker progress. Use the html color format of #RRGGBB. (Type: String)
    },
    animate:true,              // Whether to animate the current marker to the new position. (Type: Boolean)
    onUpdate:null,             // The callback function to call while the flash thermometer animation is visually updating (Type: Function)
    onComplete:null,           // The callback function to call once the flash thermometer animation completes (Type: Function)
    onUpdateStepInterval:0       // How often the onUpdate callback should be called.  Eg. 5 means make callback every 5th round during the updates        
  }
);



// The returned "myNewTherm" object above can be used to communicate with the newly displayed Flash Thermometer
//  instance using the following Properties and Methods



----[Properties]----


containerID                 // The container ID you specified earlier when creating the new Flash Thermometer object
flashObjID                  // The ID of the newly created embedded flash object
flashObj                    // The DOM element of the embedded flash obj
settings                    // Your current flash thermometer settings.  Modify this within your instance object to tweak the display.
                            // Calls to methods "updateCurrentMarker" and "updateAll" can accept changes to settings


Ex.
    myNewTherm.containerID;
    myNewTherm.settings.current_marker.value_html;



----[Methods]----


updateCurrentMarker(settings) // Call this to update the current marker position on the thermometer.  Basically animate the fluid to the new position as specified in "myNewTherm.settings.current_marker.value_html".  The "settings" parameter is optional.
updateAll(settings)           // Call this to update every item in the display.  Basically a full refresh.  With updateCurrentMarker only the current marker position is updated and not any other settings changes.  Use this to update everything.  Pass in any changes with "settings" to apply to the display.  The "settings" parameter is optional.


Ex.

    myNewTherm.updateCurrentMarker();            // Refresh the current marker / start position
    myNewTherm.updateAll();                      // Refresh the thermometer display. 
    myNewTherm.updateCurrentMarker({start:20});  // Modify the currrent starting position with the new value of 20.  The thermometer will animate to position 20.
    myNewTherm.updateCurrentMarker({current_marker:{alt_html:"2011 Honda Civic", value_html:"<font color='#ff0000'>2000 People</font>"}); // Update the current / start marker to display 2011 Honda Civic but it will animate to position 2000.



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


[[[ Note ]]]


* The following HTML tags are valid within "value_html" and "alt_html":
    + <A>
    + <B>
    + <I>
    + <U>
    + <FONT>
        [Attributes]
            - Color (eg. <font color="#ff0000">Test</font>) = Color must be in #RRGGBB format
            - Face (eg. <font face="Arial,Times">Test</font>)
            - Size (eg. <font size="16">Test</font>) = Size is in pixels using only numbers to represent the size



*/

var domReady = {};

// Class constructor for the Flash Thermometer.  This will initiate everything
function FlashThermometer(cID, swfPath, params)
{
    // Check the container ID
    if (!FlashThermometer_NS.isString(cID, true))
        return;

   // Check the swfPath exists and is a string
   if (typeof swfPath != "string")
   {
   	params = (typeof params != "undefined") ? params : swfPath;
   	swfPath = null;
   }	
   
   if (swfPath == null)
   	swfPath = "FlashThermometer.swf";

    // Get the next id and setup the global
    var nextFTID = FlashThermometer_NS.getNextID();
    FlashThermometer_NS.Instance_List[nextFTID] = 
    {
        containerID:cID, 
        flashObjID:nextFTID,
        init_params:params,
        flashObj:null,
        settings:null
    };

    // Once the DOM is ready embed the new flash object into the container    
    FlashThermometer_NS.onDOMReady(function()
    {
	var so = new SWFObject (
	// name of the fCMSPro enabled swf
	swfPath,
	// object/embed id
	nextFTID,
	// width
	'100%',
	// height
	'100%',
	// required flash player version
	'9',
	// background color
	'#EEEEEE',
	// express install
	true
	);
	so.addParam('wmode','transparent');
	so.addParam ('allowFullScreen', 'true');
	so.write (cID);        
 
        // Once the Flash Thermometer is ready to be used it will call OnReady
    });
    
    // Update the instance with additional properties
    var ftInstance = FlashThermometer_NS.Instance_List[nextFTID];
    
    ftInstance.updateCurrentMarker = FlashThermometer_NS.updateCurrentMarker;
    ftInstance.updateAll = FlashThermometer_NS.updateAll;
    ftInstance.updateSettingsAndShow = FlashThermometer_NS.updateSettingsAndShow;
    ftInstance.resetDisplay = FlashThermometer_NS.resetDisplay;
    ftInstance.onProgressUpdateCallback = null
    ftInstance.onProgressUpdateCompleteCallback = null;
    
    return ftInstance;
}

// Our Namespace

var FlashThermometer_NS = 
{
    Instance_List:{},
    Instance_Count:0,
    Default_Gauge_Marker:null,
    flashReadyTimer:null,
    flashUpdatePendingList:[],
    
    // Once the flash object has completed its setup it calls this function to inform JS it is ready to go
    OnReady:function(flashObjectID, defaultValues)
    {
        var myInfo = FlashThermometer_NS.Instance_List[flashObjectID];
        
        // If the default gauge marker isnt set do so now
        if (FlashThermometer_NS.Default_Gauge_Marker == null)
            FlashThermometer_NS.Default_Gauge_Marker = FlashThermometer_NS.cloneObject(defaultValues.goal_marker);
            
        // Clone defaultValues for the user's default settings
        myInfo.settings = FlashThermometer_NS.cloneObject(defaultValues);
        
        // Get the flash object DOM
        myInfo.flashObj = document.getElementById(flashObjectID);

        // Call Flash Thermometer to display
        myInfo.updateSettingsAndShow(2, myInfo.init_params);
        
        // Remove init_params since useless now
        delete myInfo.init_params;    
    },

    // While the thermometer is animating it calls here indicating its current position.  The user can set up a call back and this function will handle the calling of that callback.
    OnProgressUpdating:function(flashObjectID, current_val)
    {
        var myInfo = FlashThermometer_NS.Instance_List[flashObjectID];
        
        if (typeof myInfo.onProgressUpdateCallback == "function")
            myInfo.onProgressUpdateCallback(current_val);
    },

    // When the thermometer completes its progress animation it calls here indicating it is complete.  The user can set up a call back to let it know and this function will perform that call back.
    OnProgressUpdateComplete:function(flashObjectID, current_val)
    {
        var myInfo = FlashThermometer_NS.Instance_List[flashObjectID];
        
        if (typeof myInfo.onProgressUpdateCompleteCallback != 'undefined' && myInfo.onProgressUpdateCompleteCallback != null)
            myInfo.onProgressUpdateCompleteCallback(current_val);
    },

    // The next id available within the Flash Thermometer global instance list
    getNextID:function()
    {
        return "ft_" + (FlashThermometer_NS.Instance_Count++);
    },
    
    updateCurrentMarker:function(usettings)
        {
            // Update the user settings with any changes
        this.updateSettingsAndShow(1, usettings);
    },
    
    updateAll:function(usettings)
    {
            // Update the user settings with any changes
        this.updateSettingsAndShow(2, usettings);
    },
    
    resetDisplay:function(usettings)
    {
	// Update the user settings with any changes
        this.updateSettingsAndShow(3, usettings);        
    },

    updateSettingsAndShow:function(type, usettings)
    {
        // Update the current settings
        if (typeof usettings != 'undefined')
            FlashThermometer_NS.setObject(this.settings, usettings, this);
    
        // Queue up the request to call FH to update all
        FlashThermometer_NS.onFlashThermometerReady(this.flashObjID, type);
    },
    

    //////////////////////// UTILS /////////////////////////////////////
    
    // Update settings with changes info
    setObject:function(settings, changes, obj)
    {
        // Make sure the changes are valid
        if (!(typeof changes == "object" && changes != null)) return;
        
        // Iterate the changes object
        for (var key in changes)
        {        
            switch(key)
            {
                case 'start':    settings.current_marker.value_html = String(changes.start);
                                 break;
                        
                case 'goal':     settings.goal_marker.value_html = String(changes.goal);
                                 break;
                        
                case 'markers':  if (FlashThermometer_NS.isArray(changes.markers))
                                 {
                                    settings.gauge_markers = [];
                                    for (var i in changes.markers)
                                    {
                                        var newGauge = FlashThermometer_NS.cloneObject(FlashThermometer_NS.Default_Gauge_Marker);
                                        newGauge.value_html = String(changes.markers[i]); 
                                        settings.gauge_markers.push(newGauge);
                                    }
                                 }    
                                 break;        
                        
                case 'onUpdate': 
                                if (typeof changes[key] == "function")
                                {
                                    obj.onProgressUpdateCallback = changes[key];
                                    obj.settings.doProgressUpdateCallBack = true;
                                }    
                                else
                                {
                                    obj.onProgressUpdateCallback = null;
                                    obj.settings.doProgressUpdateCallBack = false;
                                }    
                                    
                                break;
            
                case 'onComplete':  
                                if (typeof changes[key] == "function")
                                {
                                    obj.onProgressUpdateCompleteCallback = changes[key];
                                    obj.settings.doProgressUpdateCompleteCallBack = true;
                                }    
                                else
                                {
                                    obj.onProgressUpdateCompleteCallback = null;
                                    obj.settings.doProgressUpdateCompleteCallBack = false;
                                }    
                            
                                break;
            
                case 'gauge_markers':  
                                if (FlashThermometer_NS.isArray(changes.gauge_markers))
                                {
                                    settings.gauge_markers = [];
                                    for (var i in changes.gauge_markers)
                                    {
                                        var newGauge = FlashThermometer_NS.cloneObject(FlashThermometer_NS.Default_Gauge_Marker);
                                        FlashThermometer_NS.setObject(newGauge, changes.gauge_markers[i], obj);
                                        settings.gauge_markers.push(newGauge);
                                    }
                                }    
                                
                                break;
                        
                default:        if (typeof settings[key] != 'undefined')
                                {
                                    if (typeof changes[key] == 'object')
                                        FlashThermometer_NS.setObject(settings[key], changes[key], obj);
                                    else
                                    {
                                        var stype = typeof settings[key];
                                        
                                        switch(stype)
                                        {
                                            case "string":
                                                    settings[key] = String(changes[key]);
                                                    break;
                                            case "number":        
                                                    settings[key] = Number(changes[key]);
                                                    break;
                                            case "boolean":        
                                                    settings[key] = Boolean(changes[key]);
                                                    break;
                                            default:
                                                break;
                                        }
                                    }    
                                }        
                                break;
            }
        }
    },
    
    isString:function(val, isNotEmpty)
    {
        if (isNotEmpty)
            return (typeof val == "string" && val.replace(/^\s+|\s+$/g,"") != "");
        else    
            return (typeof val == "string");
    },

    isNumber:function(val)
    {
        return (typeof val == "number");
    },

    isBoolean:function(val)
    {
        return (typeof val == "boolean");
    },
    
    isObjectEmpty:function(ob)
    {
          for(var i in ob)
          { 
              if(ob.hasOwnProperty(i))
                  return false;
          }
          return true;
    },

    isArray:function(obj) 
    {
           if (obj.constructor.toString().indexOf("Array") == -1)
                  return false;
           else
              return true;
    },

    // Waits for the DOM to be ready to locate IDs and insert the flash object
    onDOMReady:function(f)
    {
        // If the DOM is already loaded, execute the function right away
        if (domReady.done) return f();

        // If we’ve already added a function
        if (domReady.timer)
        {
          // Add it to the list of functions to execute
          domReady.ready.push(f);
        }
        else
        {

          // Initialize the array of functions to execute
          domReady.ready = [f];

          // Check to see if the DOM is ready as quickly as possible
          domReady.timer = setInterval(function()
          {
            // If we already figured out that the page is ready, ignore
            if (domReady.done) return false;

            // Check to see if a number of functions and elements are
            // able to be accessed
            if (document && document.getElementsByTagName && document.getElementById && document.body)
            {
              // If they’re ready, we can stop checking
              clearInterval(domReady.timer);

              domReady.timer = null;

              // Execute all the functions that were waiting
              for (var i = 0; i < domReady.ready.length; i++)
                  domReady.ready[i]();

              // Remember that we’re now done
              domReady.ready = null;

              domReady.done = true;
            } 
          }, 13);

        }
    },
    
    // Waits for the Flash Object and internal method to be ready before calling any function within it
    // ftID: the flashObjectID, type: which method is calling (1: updateCurrentMarker, 2: updateAll)
    onFlashThermometerReady:function(ftID, type)
    {
        var ftInstance = FlashThermometer_NS.Instance_List[ftID];    
        
        // First see if the flash object is available.  If so call it now
        if (ftInstance.flashObj != null && typeof ftInstance.flashObj.updateAll != 'undefined')
        {
            // Remove the item from the pending list if it exists
            if (typeof FlashThermometer_NS.flashUpdatePendingList[ftID] != 'undefined')
            {
                type = FlashThermometer_NS.flashUpdatePendingList[ftID];
                delete FlashThermometer_NS.flashUpdatePendingList[ftID];
            }    
            
            // Do the update
            if (type == 1)
                ftInstance.flashObj.updateCurrentMarker(ftInstance.settings);
            else if (type == 2)
                ftInstance.flashObj.updateAll(ftInstance.settings);
            else
                ftInstance.flashObj.resetDisplay(ftInstance.settings);
        }
        else // The flash object method is not available yet so let's wait
        {
            // No existing pending updates exist so add it now
            if (typeof FlashThermometer_NS.flashUpdatePendingList[ftID] == 'undefined')
            {
                // Is the timer currently running?  If so just add the item to the pending list
                if (FlashThermometer_NS.flashReadyTimer != null)
                    FlashThermometer_NS.flashUpdatePendingList.push(ftID);
                else
                {
                    // No timer running so create it now
                    
                    FlashThermometer_NS.flashReadyTimer = setInterval(function()
                    {
                        // Iterate the FlashThermometer_NS.flashUpdatePendingList and verify the flashObj
                        for (var ftID in FlashThermometer_NS.flashUpdatePendingList)
                        {
                            var ftInstance = FlashThermometer_NS.Instance_List[ftID];

                            // Does the flashObj and its internal method exist now?
                            if (ftInstance.flashObj != null && typeof ftInstance.flashObj.updateAll != 'undefined')
                            {
                                // Do the update
                                if (FlashThermometer_NS.flashUpdatePendingList[ftID] == 1)
                                    ftInstance.flashObj.updateCurrentMarker(ftInstance.settings);
                                else if (FlashThermometer_NS.flashUpdatePendingList[ftID] == 2)
                                    ftInstance.flashObj.updateAll(ftInstance.settings);
                                else    
                                    ftInstance.flashObj.resetDisplay(ftInstance.settings);

                                // Remove the pending item
                                delete FlashThermometer_NS.flashUpdatePendingList[ftID];                            
                            }
                        }

                        // Check the pending list for any more items.  If any then leave the timer to try again for the rest
                        // Otherwise kill the timer now
                        if (FlashThermometer_NS.isObjectEmpty(FlashThermometer_NS.flashUpdatePendingList))
                        {
                            clearInterval(FlashThermometer_NS.flashReadyTimer);
                            FlashThermometer_NS.flashReadyTimer = null;
                        }    

                    },200);
                }            
            }
            else if (FlashThermometer_NS.flashUpdatePendingList[ftID] == 1 && type == 2)  // If an UpdateAll request comes in keep it as priority update
                FlashThermometer_NS.flashUpdatePendingList[ftID] = 2;
        }    
    },
    
    // cloneObject 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
    cloneObject:function(from, to)
    {
        if (from == null || typeof from != "object") return from;
        if (from.constructor != Object && from.constructor != Array) return from;
        if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
        from.constructor == String || from.constructor == Number || from.constructor == Boolean)
        return new from.constructor(from);

        to = to || new from.constructor();

        for (var name in from)
        {
        to[name] = typeof to[name] == "undefined" ? FlashThermometer_NS.cloneObject(from[name], null) : to[name];
        }

        return to;
    }    
};


/* CMH UPGRADED THIS FROM 1.4 to 1.5.      2.0 did not work. */
/**
 * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
 *
 * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
if(typeof deconcept == "undefined") var deconcept = new Object();
if(typeof deconcept.util == "undefined") deconcept.util = new Object();
if(typeof deconcept.SWFObjectUtil == "undefined") deconcept.SWFObjectUtil = new Object();
deconcept.SWFObject = function(swf, id, w, h, ver, c, quality, xiRedirectUrl, redirectUrl, detectKey) {
	if (!document.getElementById) { return; }
	this.DETECT_KEY = detectKey ? detectKey : 'detectflash';
	this.skipDetect = deconcept.util.getRequestParameter(this.DETECT_KEY);
	this.params = new Object();
	this.variables = new Object();
	this.attributes = new Array();
	if(swf) { this.setAttribute('swf', swf); }
	if(id) { this.setAttribute('id', id); }
	if(w) { this.setAttribute('width', w); }
	if(h) { this.setAttribute('height', h); }
	if(ver) { this.setAttribute('version', new deconcept.PlayerVersion(ver.toString().split("."))); }
	this.installedVer = deconcept.SWFObjectUtil.getPlayerVersion();
	if (!window.opera && document.all && this.installedVer.major > 7) {
		// only add the onunload cleanup if the Flash Player version supports External Interface and we are in IE
		deconcept.SWFObject.doPrepUnload = true;
	}
	if(c) { this.addParam('bgcolor', c); }
	var q = quality ? quality : 'high';
	this.addParam('quality', q);
	this.setAttribute('useExpressInstall', false);
	this.setAttribute('doExpressInstall', false);
	var xir = (xiRedirectUrl) ? xiRedirectUrl : window.location;
	this.setAttribute('xiRedirectUrl', xir);
	this.setAttribute('redirectUrl', '');
	if(redirectUrl) { this.setAttribute('redirectUrl', redirectUrl); }
}
deconcept.SWFObject.prototype = {
	useExpressInstall: function(path) {
		this.xiSWFPath = !path ? "expressinstall.swf" : path;
		this.setAttribute('useExpressInstall', true);
	},
	setAttribute: function(name, value){
		this.attributes[name] = value;
	},
	getAttribute: function(name){
		return this.attributes[name];
	},
	addParam: function(name, value){
		this.params[name] = value;
	},
	getParams: function(){
		return this.params;
	},
	addVariable: function(name, value){
		this.variables[name] = value;
	},
	getVariable: function(name){
		return this.variables[name];
	},
	getVariables: function(){
		return this.variables;
	},
	getVariablePairs: function(){
		var variablePairs = new Array();
		var key;
		var variables = this.getVariables();
		for(key in variables){
			variablePairs[variablePairs.length] = key +"="+ variables[key];
		}
		return variablePairs;
	},
	getSWFHTML: function() {
		var swfNode = "";
		if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture
			if (this.getAttribute("doExpressInstall")) {
				this.addVariable("MMplayerType", "PlugIn");
				this.setAttribute('swf', this.xiSWFPath);
			}
			swfNode = '<embed type="application/x-shockwave-flash" src="'+ this.getAttribute('swf') +'" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'" style="'+ this.getAttribute('style') +'"';
			swfNode += ' id="'+ this.getAttribute('id') +'" name="'+ this.getAttribute('id') +'" ';
			var params = this.getParams();
			 for(var key in params){ swfNode += [key] +'="'+ params[key] +'" '; }
			var pairs = this.getVariablePairs().join("&");
			 if (pairs.length > 0){ swfNode += 'flashvars="'+ pairs +'"'; }
			swfNode += '/>';
		} else { // PC IE
			if (this.getAttribute("doExpressInstall")) {
				this.addVariable("MMplayerType", "ActiveX");
				this.setAttribute('swf', this.xiSWFPath);
			}
			swfNode = '<object id="'+ this.getAttribute('id') +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'" style="'+ this.getAttribute('style') +'">';
			swfNode += '<param name="movie" value="'+ this.getAttribute('swf') +'" />';
			var params = this.getParams();
			for(var key in params) {
			 swfNode += '<param name="'+ key +'" value="'+ params[key] +'" />';
			}
			var pairs = this.getVariablePairs().join("&");
			if(pairs.length > 0) {swfNode += '<param name="flashvars" value="'+ pairs +'" />';}
			swfNode += "</object>";
		}
		return swfNode;
	},
	write: function(elementId){
		if(this.getAttribute('useExpressInstall')) {
			// check to see if we need to do an express install
			var expressInstallReqVer = new deconcept.PlayerVersion([6,0,65]);
			if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) {
				this.setAttribute('doExpressInstall', true);
				this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl')));
				document.title = document.title.slice(0, 47) + " - Flash Player Installation";
				this.addVariable("MMdoctitle", document.title);
			}
		}
		if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){
			var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId;
			n.innerHTML = this.getSWFHTML();
			return true;
		}else{
			if(this.getAttribute('redirectUrl') != "") {
				document.location.replace(this.getAttribute('redirectUrl'));
			}
		}
		return false;
	}
}

/* ---- detection functions ---- */
deconcept.SWFObjectUtil.getPlayerVersion = function(){
	var PlayerVersion = new deconcept.PlayerVersion([0,0,0]);
	if(navigator.plugins && navigator.mimeTypes.length){
		var x = navigator.plugins["Shockwave Flash"];
		if(x && x.description) {
			PlayerVersion = new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split("."));
		}
	}else if (navigator.userAgent && navigator.userAgent.indexOf("Windows CE") >= 0){ // if Windows CE
		var axo = 1;
		var counter = 3;
		while(axo) {
			try {
				counter++;
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+ counter);
//				document.write("player v: "+ counter);
				PlayerVersion = new deconcept.PlayerVersion([counter,0,0]);
			} catch (e) {
				axo = null;
			}
		}
	} else { // Win IE (non mobile)
		// do minor version lookup in IE, but avoid fp6 crashing issues
		// see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
		try{
			var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
		}catch(e){
			try {
				var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
				PlayerVersion = new deconcept.PlayerVersion([6,0,21]);
				axo.AllowScriptAccess = "always"; // error if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code)
			} catch(e) {
				if (PlayerVersion.major == 6) {
					return PlayerVersion;
				}
			}
			try {
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
			} catch(e) {}
		}
		if (axo != null) {
			PlayerVersion = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));
		}
	}
	return PlayerVersion;
}
deconcept.PlayerVersion = function(arrVersion){
	this.major = arrVersion[0] != null ? parseInt(arrVersion[0]) : 0;
	this.minor = arrVersion[1] != null ? parseInt(arrVersion[1]) : 0;
	this.rev = arrVersion[2] != null ? parseInt(arrVersion[2]) : 0;
}
deconcept.PlayerVersion.prototype.versionIsValid = function(fv){
	if(this.major < fv.major) return false;
	if(this.major > fv.major) return true;
	if(this.minor < fv.minor) return false;
	if(this.minor > fv.minor) return true;
	if(this.rev < fv.rev) return false;
	return true;
}
/* ---- get value of query string param ---- */
deconcept.util = {
	getRequestParameter: function(param) {
		var q = document.location.search || document.location.hash;
		if (param == null) { return q; }
		if(q) {
			var pairs = q.substring(1).split("&");
			for (var i=0; i < pairs.length; i++) {
				if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
					return pairs[i].substring((pairs[i].indexOf("=")+1));
				}
			}
		}
		return "";
	}
}
/* fix for video streaming bug */
deconcept.SWFObjectUtil.cleanupSWFs = function() {
	var objects = document.getElementsByTagName("OBJECT");
	for (var i = objects.length - 1; i >= 0; i--) {
		objects[i].style.display = 'none';
		for (var x in objects[i]) {
			if (typeof objects[i][x] == 'function') {
				objects[i][x] = function(){};
			}
		}
	}
}
// fixes bug in some fp9 versions see http://blog.deconcept.com/2006/07/28/swfobject-143-released/
if (deconcept.SWFObject.doPrepUnload) {
	if (!deconcept.unloadSet) {
		deconcept.SWFObjectUtil.prepUnload = function() {
			__flash_unloadHandler = function(){};
			__flash_savedUnloadHandler = function(){};
			window.attachEvent("onunload", deconcept.SWFObjectUtil.cleanupSWFs);
		}
		window.attachEvent("onbeforeunload", deconcept.SWFObjectUtil.prepUnload);
		deconcept.unloadSet = true;
	}
}
/* add document.getElementById if needed (mobile IE < 5) */
if (!document.getElementById && document.all) { document.getElementById = function(id) { return document.all[id]; }}

/* add some aliases for ease of use/backwards compatibility */
var getQueryParamValue = deconcept.util.getRequestParameter;
var FlashObject = deconcept.SWFObject; // for legacy support
var SWFObject = deconcept.SWFObject;

