/**
 * com.disney.mpf.Mpf.js
 *  
 * 
 * Copyright (c) 2007 Walt Disney Internet Group, Inc. All Rights Reserved.
 *
 * $Author: dkonopac $
 * $Revision: #3 $
 * $DateTime: 2007/10/30 17:28:04 $
 * 
 */

/************************************************
 * Method <code>Namespace</code> is a way to develop Javascript objects
 * without the problem of name collisions between different methods. This
 * script is adapted from the Figment framework, developed by Philip Jarrell.
 * philip.jarrell@disney.com
 * @param namespace : String - The fully-qualified name of the object;
 * @return Void;
 */
Namespace = function ( namespace ) {
	
		var root = window;
		var namespaceParts = namespace.split( "." );
		var totalParts = namespaceParts.length;
		
		for( var i=0; i < totalParts; i++ ) {
			
			if( !root[ namespaceParts[ i ] ] ) root[ namespaceParts[ i ] ] = {};
			root = root[ namespaceParts[ i ] ];
			
		}
		
		delete namespaceParts;
		delete totalParts;
		delete root;
		
}

Import = function ( strScript, strStartURL, bDotsAreFolders ) {
	var bImport = false;
	var strNamespace = null;
	var listOfNamespaces = null;
	var root = null;
	var iLen = null;
	var i = 0;
	var objHead = null;
	var strJs = null;
	var objScript = null;
	var ajaxRequestor = null;
	
	strNamespace = strScript;
	if( arguments.length === 3 && bDotsAreFolders )
	{
		strScript = strScript.replaceAll( '.','/' );
	}
	strScript += '.js';

	if( arguments.length < 2 )
	{
		strStartURL = '';
	}
	else
	{
		if( strStartURL !== null && strStartURL !== '' && !strStartURL.endsWith( '/' ) )
		{
			strStartURL += '/';
		}
	}

	listOfNamespaces = strNamespace.split( '.' );
	root = window;
	iLen = listOfNamespaces.length;
	for( i=0; i < iLen; i++ )
	{
		if( !root[ listOfNamespaces[i] ] )
		{
			bImport = true;
			break;
		}
		root = root[ listOfNamespaces[i] ];
	}

	// Label the import section
	markImport:
	
	if( bImport )
	{
		objScript = document.createElement( "SCRIPT" );
		objHead = document.getElementsByTagName( "HEAD" );
		
		if( objHead.length > 0 )
		{
			objHead = objHead[0];
		}
		else
		{
			alert( "Script not loaded" );
			break markImport;
		}
		
		objScript.type = "text/javascript";
		objScript.src = Figment.getBase() + strStartURL + strScript;
		objHead.appendChild( objScript );

		delete objScript;
		delete objHead;
	}
	delete listOfNamespaces;
	delete root;
}

/************************************************
 * Object <code>com.disney.mpf.Mpf</code> is the primary
 * Javascript wrapper for the MPF. This contains a number
 * of helper methods and wrappers meant to facilitate the
 * development of Javascript-based players.
 */
Namespace( "com.disney.mpf.Mpf" );
com.disney.mpf.Mpf = {
	
	_flashObject: null,
	
	/************************************************
	 * <code>addEventListener</code> is a wrapper method that provides
	 * enhanced event handling. This allows easier cross-browser
	 * eventing, as well as access to outside event management, such as
	 * the events that are triggered by the QVT player. This method can
	 * also be used to listen for events, and then dispatch those events
	 * to the Flash framework. The <code>args</code> parameter is used to
	 * pass in additional arguments, such as <code>isFlashEvent</code> and
	 * <code>eventListener</code>. Here are the values for <code>args</code>:
	 * <pre>
	 * args {
	 *     isFlashEvent: true|false (Used to determine if event is to be dispatched to Flash or not),
	 *     eventListener: path.to.external.event.listener (Useful if you want to connect to another type of event listener, such as <code>MN.Event.Observe</code> for QVT,
	 *     bubble: Event bubbles
	 * }
	 * </pre>
	 * @param _eventObject : Object - The object that the listener is observing, such as window or QVT player;
	 * @param eventType : String - The event to listen for;
	 * @param eventHandler : Function - The method to execute when the event occurs;
	 * @param args : Object - An object containing additional arguments.
	 * @return Void;
	 */
	addEventListener: function ( _eventObject, eventType, eventHandler, args ) {
		
		var mediaEventListener = null;
		var isFlashEvent = false;
		var bubble = false;
		var eventObject = eval( _eventObject );
		
		if ( args !== undefined && args !== null ) {
			
			isFlashEvent = args.isFlashEvent;
			if ( args.bubble ) bubble = args.bubble;
			
			if ( args.eventListener !== undefined && args.eventListener !== null ) {
				
				mediaEventListener = eval( args.eventListener );
				
				if ( !isFlashEvent ) {
				
					mediaEventListener( eventObject, eventType, function() { eval( eventHandler )( eventType, arguments ) } );
					
				} else {
					
					mediaEventListener( eventObject, eventType, function() { MPF.dispatchFlashEvent( eventType, arguments ) } );
					
				}
				
			}
			
		} else {
			
			if ( eventObject.addEventListener ) {
				
				if ( !isFlashEvent ) {
					
					mediaEventListener =  eventObject.addEventListener( eventType, eventHandler, bubble );
					
				} else {
					
					mediaEventListener =  eventObject.addEventListener( eventType, function( obj ) { MPF.dispatchFlashEvent( eventType, obj ) }, bubble );
					
				}
				
			} else {
				
				if ( !isFlashEvent ) {
					
					mediaEventListener =  eventObject.attachEvent( "on" + eventType, eventHandler );
					
				} else {
					
					mediaEventListener =  eventObject.attachEvent( "on" + eventType, function( obj ) { MPF.dispatchFlashEvent( eventType, obj ) } );
					
				}
				
			}
			
		}
		
	},
	
	/************************************************
	 * <code>dispatchFlashEvent</code> is used to dispatch events back
	 * to Flash. There is a delegate method on the Flash side that will
	 * handle where the event needs to get dispatched to inside of the
	 * application. NOTE: To keep a standard for Javascript event
	 * dispatching back to Flash, "on" is prepended to all events.
	 * @param eventType : String - The type of event that occurred;
	 * @param eventArguments : Object - The event arguments that are dispatched back to Flash;
	 * @return Void;
	 */
	dispatchFlashEvent: function ( eventType, eventArguments ) {
		
		var eventName = ( eventType.indexOf( "on" ) !== 0 && eventType.indexOf( "com" ) !== 0 ) ? "on" + eventType : eventType;
		
		if ( eventArguments !== undefined && eventArguments !== null ) {
			
			this.getFlashContainer().dispatchExternalEvent( eventName, eventArguments );
			
		} else {
			
			this.getFlashContainer().dispatchExternalEvent( eventName );
			
		}
		
	},
	
	/************************************************
	 * <code>getWindow</code> is a simple helper method that returns
	 * either <code>window</code> or <code>document</code>, based upon
	 * which browser the client is.
	 * @param Null;
	 * @return Object;
	 */
	getWindow: function () {
		
		if ( navigator.appName.indexOf("Microsoft") >-1 ) return window;
		return document;
		
	},
	
	/************************************************
	 * <code>getElementById</code> is a helper method that wraps
	 * the differences of browser implementation for this method.
	 * @param elementId : String - The name of the HTML element to get;
	 * @return HTML Element;
	 */
	getElementById: function ( elementId ) {
	
		if ( document.all && !document.getElementById ) return document.all[ elementId ];
		return document.getElementById( elementId );
	
	},
	
	/************************************************
	 * <code>setFlashName</code> sets the Flash DOM object name.
	 * @param flashWindowName : String - The DOM id of the Flash object;
	 * @return Void;
	 */
	setFlashName: function ( flashWindowName ) {
		
		this._flashObject = flashWindowName;
		
	},
	
	/************************************************
	 * <code>getFlashName</code> returns the currently set DOM
	 * name of the MPF Flash object.
	 * @param Null;
	 * @return String;
	 */
	getFlashName: function () {
		
		return this._flashObject;
		
	},
	
	/************************************************
	 * <code>getFlashContainer</code> returns the currently set MPF
	 * Flash object.
	 * @param Null;
	 * @return HTML Flash Object;
	 */
	getFlashContainer: function () {
		
		return this.getWindow()[ this.getFlashName() ];
		
	},
	
	/************************************************
	 * <code>log</code> sends logging information back to Flash. !!This
	 * method is currently not fully functional!!
	 * @param logMessage : String - The log message that is to be sent to Flash;
	 * @return Void;
	 */
	log: function ( logMessage ) {
		
		if ( this.getFlashContainer() ) this.getFlashContainer().log( logMessage );
		
	},
	
	/************************************************
	 * <code>logError</code> is used for logging back to Flash
	 * errors that occur on the Javascript side. !!This
	 * method is currently not fully functional!!
	 * @param errorLevel : String - The level of the error ["Warn"|"Error"|"Fatal"];
	 * @param errorMessage : String - The error message that is to be sent to Flash;
	 * @return Void;
	 */
	logError: function ( errorLevel, errorMessage ) {
		
		if ( this.getFlashContainer() ) this.getFlashContainer().logError( errorLevel, errorMessage );
		
	},
	
	/************************************************
	 * <code>getX</code> returns the <code>x</code> coordinate
	 * value of an HTML element. This will give the value relative
	 * to the browser window.
	 * @param element : HtmlElement - The element for which the <code>x</code> value is required;
	 * @return Number;
	 */
	getX: function( element )
	{
		var curleft = 0;
		if( element.offsetParent )
		{
			while(1)
			{
				curleft += element.offsetLeft;
				if( !element.offsetParent )
				{
					break;
				}
				element = element.offsetParent;
			}
		}
		else if( element.x )
		{
			curleft += element.x;
		}
		return curleft;
	},
	
	/************************************************
	 * <code>getY</code> returns the <code>y</code> coordinate
	 * value of an HTML element. This will give the value relative
	 * to the browser window.
	 * @param element : HtmlElement - The element for which the <code>y</code> value is required;
	 * @return Number;
	 */
	getY: function( element )
	{
		var curtop = 0;
		if( element.offsetParent )
		{
			while(1)
			{
				curtop += element.offsetTop;
				if( !element.offsetParent )
				{
					break;
				}
				element = element.offsetParent;
			}
		}
		else if( element.y )
		{
			curtop += element.y;
		}
		return curtop;
	},
	
	createEmptyLayer: function ( elementId )
	{
		
		var layer = document.createElement( "DIV" );
		layer.setAttribute( 'id', elementId );
		document.body.appendChild( layer );
		
	},
	
	removeLayer: function ( elementId )
	{
		var layer = this.getElementById( elementId );
		layer.parentNode.removeChild( layer );
	},
	
	/************************************************
	 * <code>delegate</code> is used to dispatch method requests
	 * from the Flash application to Javascript. This is a central
	 * point of communication for all incoming Flash requests and
	 * is used to minimize individual method assignment and access.
	 * Since this is a core feature of the MPF, there are three
	 * ways in which this method works:
	 * 
	 * 1) If <code>dispatchObjectName</code>
	 * is an empty string, the method to execute is inside of the
	 * <code>com.disney.mpf.Mpf</code> class, i.e.
	 * <pre>
	 * <code>
	 *    delegate( "", "getFlashName" ); // Will return the name of the Flash object, as called from <code>com.disney.mpf.Mpf</code>.
	 * </code>
	 * </pre>
	 * 
	 * 2) If <code>dispatchObjectName</code> has one or more
	 * dots seperating the class, <code>delegate</code> will
	 * execute that method as a fully-qualified namespace object, i.e.
	 * <pre>
	 * <code>
	 *    delegate( "com.disney.mpf.ui.AdjustColors", "setBlue" ); // Will access the <code>com.disney.mpf.ui.AdjustColors</code> and executes the <code>setBlue</code> method.
	 * <code>
	 * </pre>
	 * 
	 * 3) If <code>dispatchObjectName</code> is a single name
	 * with no dots, delegate will execute the <code>dispatchObjectName</code>
	 * as part of the <code>com.disney.mpf.players</code> package.
	 * <pre>
	 * <code>
	 *     delegate( "Move", "getVolume" ); // Executes the <code>getVolume</code> in the <code>com.disney.mpf.players.Move</code> object.
	 * </code>
	 * </pre>
	 * 
	 * The delegate method can also handle up to five (5)
	 * custom arguments that can be passed to the executed method.
	 * @param dispatchObjectName : String - The name of the object to dispatch to;
	 * @param dispatchArguments : Array - The arguments to be passed in - the method is always the first argument, with up to five (5) additional arguments allowed;
	 * @return Void;
	 */
	delegate: function ( dispatchObjectName, dispatchArguments ) {
		
		var dispatchObject = String( dispatchObjectName );
		var dispatchClass = "";
		var method = dispatchArguments[ 0 ];
		var totalArguments = dispatchArguments.length - 1;
		
		if ( dispatchObject === "" ) {
			
			dispatchClass = com.disney.mpf.Mpf;
			
		} else if ( dispatchObject.indexOf( "." ) > -1 ) {
			
			dispatchClass = eval( dispatchObject );
			
		} else {
			
			dispatchClass = com.disney.mpf.players[ dispatchObject ];
			
		}
		
		switch ( totalArguments ) {
		
		case 1:
			return dispatchClass[ method ]( dispatchArguments[ 1 ] );
			break;
		
		case 2:
			return dispatchClass[ method ]( dispatchArguments[ 1 ], dispatchArguments[ 2 ] );
			break;
		
		case 3:
			return dispatchClass[ method ]( dispatchArguments[ 1 ], dispatchArguments[ 2 ], dispatchArguments[3 ] );
			break;
		
		case 4:
			return dispatchClass[ method ]( dispatchArguments[ 1 ], dispatchArguments[ 2 ], dispatchArguments[3 ], dispatchArguments[ 4 ] );
			break;
		
		case 5:
			return dispatchClass[ method ]( dispatchArguments[ 1 ], dispatchArguments[ 2 ], dispatchArguments[ 3 ], dispatchArguments[ 4 ], dispatchArguments[ 5 ] );
			break;
		
		default:
			return dispatchClass[ method ]();
			break;
		
		}
	
	},
	
	/************************************************
	 * <code>main</code> is the initialization method of the
	 * <code>com.disney.mpf.Mpf</code> object.
	 * @param flashObjectName : String - [Optional] The name of the MPF Flash object;
	 * @return com.disney.mpf.Mpf;
	 */
	main: function () {
		
		if ( arguments[ 0 ] !== undefined && arguments[ 0 ] !== null ) this.setFlashName( arguments[ 0 ] );
		return this;
		
	}
	
};
