/**
 * C3DObject embed
 *
 * Based on
 * Geoff Stearns (geoff@deconcept.com, http://www.deconcept.com/)
 * http://blog.deconcept.com/2005/01/26/web-standards-compliant-javascript-quicktime-detect-and-embed/
 * Licensed under MIT license. http://www.opensource.org/licenses/mit-license.php
 *
 * Embeds a Cult3D object to the HTML page
 *
 * Usage:
 *
 *  myC3DObject = new C3DObject("path/to/cult3d.co", "objectID", "width", "height");
 *  myC3DObject.addParam("antaliasing", "2"); // optional, convenience methods exists for Cult3D embedd parameters
 *  myC3DObject.write();
 *
 *
 */

/**
 * Jonatan Andersson, 2006-04-25
 * Last edited: 2006-05-08
 * version 0.95
 */

/**
 * Constructor to create a new  Cult3D embedd string
 * myC3DObject = new C3DObject("path/to/cult3d.co", "CultObject", "400", "400");
 */
C3DObject = function(object, id, width, height)
{
    this.object = object;
    this.id = id;
    this.width = width;
    this.height = height;
    this.params = new Object();
}

// Event variables for Cult3D
C3DObject.prototype.OnLoadFinishedEvent = "OnLoadFinished";
C3DObject.prototype.OnSendMessageEvent = "OnSendMessage";
C3DObject.prototype.OnSceneLoadedEvent = "OnSceneLoaded";
C3DObject.prototype.OnLoadAbortedEvent = "OnLoadAborted";



// !!!! TODO: Update this when a newer Cult3D version is released
C3DObject.prototype.IE_C3DPLUGIN_VERSION = "5,3,0,228";
C3DObject.prototype.EXPLORER_PLUGIN_DOWNLOAD = "http://www.cult3d.com/download/cult.cab";
C3DObject.prototype.NETSCAPE_PLUGIN_DOWNLOAD = "http://www.cult3d.com/newuser/index.html";

/**
 * Write the Cult3D embedding tag in the website
 *
 * @elementID - The name of a layer elementID which embedd tag will replace,
 *              if the value is null it writes at the location of the execution.
 */
C3DObject.prototype.write = function(elementId)
{
    if (elementId)
    {
        document.getElementById(elementId).innerHTML = this.getHTML();
    }
    else
    {
        document.write(this.getHTML());
    }
}


///////////////////////////////////
// Cult3D convenience functions //
///////////////////////////////////

/**
 * This parameter controls only the software antialiasing. It can be set to three different values:
 * AA_AUTOMATIC – automatic antialiasing, if antialiasing is turned on when nothing has happened in the scene after the time period set by “ANTIALIASINGDELAY”. When anything moves, antialiasing is turned off to improve speed. This is the default value.
 * AA_OFF       – disable antialiasing
 * AA_FORCED    – enable antialiasing
 */
C3DObject.prototype.AA_AUTOMATIC = 0; // Let antialiasing kick in after a delay. Default
C3DObject.prototype.AA_OFF = 1; // Turn off antialiasing
C3DObject.prototype.AA_FORCED = 2; // Force antialiasing to be always on
C3DObject.prototype.AA_AUTO= this.AA_AUTOMATIC; // An alias for automatic antialiasing

/**
 * Adds antialising parameter to the embedded object
 * Use the defined AA_OFF, AA_AUTOMATIC, AA_FORCED to set the degree of antialiasing you want
 */
C3DObject.prototype.setAntialiasing = function(aaState)
{
	if ((aaState < 0) || (aaState > 2))
	{
		alert("[includeCult3.js setAntialiasing] - Unknown antialiasing state " + aaState);
		return;
	}

	this.addParam("Antialiasing", aaState);
}

/**
 * How long should the scene stand still before the antialiasing kicks in.
 * The delay is in milliseconds. Default value is 1000 milliseconds (1 second).
 * Its only usable if antialising is in automatic mode.
 */
C3DObject.prototype.addAntialiasingDelay = function(aaDelay)
{
	if (aaDelay < 0)
	{
		alert("[includeCult3D.js addAntialiasingDelay] - Antialiasing delay needs to be positive");
		return;
	}

	this.addParam("AntialiasingDelay", aaDelay);
}

/**
 * Cult3D will trigger this event whenever it receives a
 * “Send Message to Host” call activated by the Cul3D
 * Designer or by a Cult3D Java method.
 *
 * Retrieve the message by calling the method “getLastMessage()”, see Cult3D.js for that function.
 */
C3DObject.prototype.onSendMessage = function(functionName)
{
	if ((functionName == null) || (functionName == ""))
	{
		alert("[includeCult3D.js onSendMessage] - The parameter functionName is empty");
		return;
	}

	functionName = this.validateFunctionName(functionName);
	this.addParam(this.OnSendMessageEvent, functionName);
}


/**
 * Cult3D will trigger this event when enough information has been loaded to
 * start the scene. Textures and cursors might not have been loaded yet
 */
C3DObject.prototype.onSceneLoaded = function(functionName)
{
	if ((functionName == null) || (functionName == ""))
	{
		alert("[includeCult3D.js onSceneLoaded] - The parameter functionName is empty");
		return;
	}

	functionName = this.validateFunctionName(functionName);
	this.addParam(this.OnSceneLoadedEvent, functionName);
}

/**
 * Cult3D will trigger this event when the full Cult3D file has been loaded and decompressed.
 */
C3DObject.prototype.onLoadFinished = function(functionName)
{
	if ((functionName == null) || (functionName == ""))
	{
		alert("[includeCult3D.js onLoadFinished()] - The parameter functionName is empty");
		return;
	}

	if (this.isIE())
	{
		functionName = this.validateFunctionName(functionName, "this");
	}
	else
	{
		functionName = this.validateFunctionName(functionName, "'" + this.id + "'");
	}

	this.addParam(this.OnLoadFinishedEvent, functionName);
}

/**
 * Cult3D will trigger this event when the Cult3D file is either invalid or
 * can't be found on the path specified in the includeCult3D.js constructor.
 */
C3DObject.prototype.onLoadAborted = function(functionName)
{
	if ((functionName == null) || (functionName == ""))
	{
		alert("[includeCult3D.js onLoadAborted] - The parameter functionName is empty");
		return;
	}

	functionName = this.validateFunctionName(functionName);
	this.addParam(this.OnLoadAbortedEvent, functionName);
}

/**
 * This parameter controls hardware acceleration.
 * Default value is HW_ENABLED which enables hardware acceleration if available.
 * Set the value to HW_DISABLED to disables all hardware acceleration.
 */
C3DObject.prototype.HW_ENABLED  = 0; // Enable hardware support. Default if not eplicitly disabled
C3DObject.prototype.HW_DISABLED = 1; // Disable hardware support.

/**
 * Set param hardwareSupport to HW_DISABLED to disable hardware support for the Cult3D Scene.
 */
C3DObject.prototype.disableHW = function(hardwareSupport)
{
	if ((hardwareSupport != this.HW_DISABLED) || (hardwareSupport != this.HW_ENABLED))
	{
		alert("[includeCult3D.js disableHW] - The parameter hardwareSupport is invalid " + hardwareSupport);
		return;
	}

	this.addParam("DisableHW", hardwareSupport);
}


C3DObject.prototype.FRAME_SKIP_DISABLE = 0; // May skip frames on slower computers. Default
C3DObject.prototype.FRAME_SKIP_ENABLE  = 1; // Plays all the frames.

/**
 * This parameter controls automatic frame skipping to compensate for slower computers.
 * Default value is FRAME_SKIP_ENABLE which enables frame skipping. Set the value to
 * FRAME_SKIP_ENABLE to disable frame skipping.
*/
C3DObject.prototype.frameSkip = function(frameState)
{
	if ((frameState != FRAME_SKIP_DISABLE) || (frameState != FRAME_SKIP_ENABLE))
	{
		alert("[includeCult3D.js frameSkip] - The parameter frameState is invalid " + frameState);
		return;
	}

	this.addParam("FrameSkip", frameState);
}

C3DObject.prototype.VIEW_FINISHED_RENDER = 0;
C3DObject.prototype.VIEW_FINISHED_HOLD   = 1;

/**
 * This parameter controls the rendering of the Cult3D object while the
 * object is loading.
 *
 * Default value is "VIEW_FINISHED_RENDER" which allows Cult3D to render
 * the object while it is loading the object.
 * set to VIEW_FINISHED_HOLD to force Cult3D to not render anything until
 * the object is completely loaded.
 */
C3DObject.prototype.viewFinished = function(renderState)
{
	if ((renderState != VIEW_FINISHED_RENDER) || (renderState != VIEW_FINISHED_HOLD))
	{
		alert("[includeCult3D.js viewFinished] - The parameter renderState is invalid " + renderState);
		return;
	}

	this.addParam("ViewFinished", frameState);
}

/**
 * This sets the color of the Cult3D progress bar while the Cult3D object is loading.
 * If no value is given or the value is invalid, it will automatically
 * be set to white. The color must be a hex value.
 */
C3DObject.prototype.progressBarColor = function(hexColor)
{
	// !!! Todo: validate that hexColor really is a hex color
	this.addParam("PBColor", hexColor);
}

/**
 * This disables the Cult3D progress bar when loading the Cult3D object.
 */
C3DObject.prototype.disableProgressbar = function()
{
	this.addParam("DisablePB", "1");
}


////////////////////////////
// Embedd methods         //
////////////////////////////


C3DObject.prototype.addParam = function(name, value)
{
    this.params[name] = value;
}

C3DObject.prototype.getParams = function()
{
    return this.params;
}

C3DObject.prototype.getParam = function(name)
{
    return this.params[name];
}

C3DObject.prototype.getHTML = function()
{
    var c3dHTML = "";
    var eventHTML = ""; // For Explorer

    // not ie
	if (! this.isIE())
    {
        c3dHTML += '<embed type=\"application/x-cult3d-object\"\n';
        c3dHTML += '   id="' + this.id + '"\n';
        c3dHTML += '   pluginspage="' + this.NETSCAPE_PLUGIN_DOWNLOAD + '"\n';
        c3dHTML += '   src="' + this.object + '"\n';
        c3dHTML += '   width="' + this.width + '" height="' + this.height + '"\n';

        for (var param in this.getParams()) {
            c3dHTML += '   ' + param + '="' + this.getParam(param) + '"\n';
        }
        c3dHTML += "></embed>\n";
    }
    else // pc ie
    {
	    c3dHTML += '<object classid="clsid:31B7EB4E-8B4B-11D1-A789-00A0CC6651A8"\n';
   	    c3dHTML += '   id="' + this.id + '"\n';
  	    c3dHTML += '   codebase="' +  this.EXPLORER_PLUGIN_DOWNLOAD + '#version=' + this.IE_C3DPLUGIN_VERSION + '"\n';
	    c3dHTML += '   width="' + this.width + '" height="' + this.height + '"\n';
		c3dHTML += '>\n';
		c3dHTML += '   <param name="src" value="' + this.object + '">\n';
	    for (var param in this.getParams())
    	{
			// Disregard these events from param list and add them as separate javascript event blocks.
			if(param.search(this.OnSendMessageEvent) > -1)
			{
				var callback = this.getParam(this.OnSendMessageEvent);
				eventHTML += this.getExplorerEvents(this.OnSendMessageEvent, callback) + "\n";
				continue;
			}
			else if(param.indexOf(this.OnLoadFinishedEvent) > -1)
			{
				var callback = this.getParam(this.OnLoadFinishedEvent);
				eventHTML += this.getExplorerEvents(this.OnLoadFinishedEvent, callback) + "\n";
				continue;
			}
			else if	(param.search(this.OnSceneLoadedEvent) > -1)
			{
				var callback = this.getParam(this.OnSceneLoadedEvent);
				eventHTML += this.getExplorerEvents(this.OnSceneLoadedEvent, callback) + "\n";
				continue;
			}
			else if (param.search(this.OnLoadAbortedEvent) > -1)
			{
				var callback = this.getParam(this.OnLoadAbortedEvent);
				eventHTML += this.getExplorerEvents(this.OnLoadAbortedEvent, callback) + "\n";
				continue;
			}

			c3dHTML += '   <param name="' + param + '" value="' + this.getParam(param) + '">\n';
		}
        c3dHTML += '</object>';
    }

//    alert(eventHTML + "\n\n" + c3dHTML);
    return eventHTML + "\n\n" + c3dHTML;
}


C3DObject.prototype.getVariablePairs = function()
{
    var variablePairs = new Array();
    for (var name in this.getVariables())
    {
        variablePairs.push(name + "=" + escape(this.getVariable(name)));
    }

    if (variablePairs.length > 0)
    {
        return variablePairs.join("&");
    }
    else
    {
        return null;
    }
}

////////////////////////////
// Private util methods  //
//////////////////////////

/**
 * Special method for defining Internet Explorer Cult3D event callbacks
 *
 * @event - One of Cult3D events
 * @functionName - The method which will be called when 'event' is triggered
 */
C3DObject.prototype.getExplorerEvents = function(event, functionName)
{
	var c3dHTML = "";
	c3dHTML += '<SCRIPT LANGUAGE="javascript" FOR=' + this.id + ' EVENT=' + event + '>\n';
	c3dHTML += '<!--\n';
	c3dHTML += 'if (isActiveX())\n';
	c3dHTML += '{\n';
	c3dHTML += '  ' + functionName + '\n';
	c3dHTML += '}\n';
	c3dHTML += '// -->\n';
	c3dHTML += '</SCRIPT>\n';

	return c3dHTML;
}

// Adds paranthesis around the function name if none exists
// Inserts the parameters inside the function name
C3DObject.prototype.validateFunctionName = function(functionName, params)
{
	if (params == null)
	{
		params = "";
	}

	if ((functionName.indexOf("(") == -1) && (functionName.indexOf(")") == -1))
	{
		functionName += "(" + params + ")";
	}
	functionName += ";";
	return functionName;
}


C3DObject.prototype.isIE = function()
{
    if (navigator.plugins && navigator.plugins.length)
    {
    	return false;
    }

    return true;
}
