// -----------------------------------------------------------------------------
// This file is part of [nice] frame
// (c) 2007 Dynamic Media eLearning GmbH
// All rights reserved.
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// $Id: nice.js 2699 2008-05-05 14:12:32Z dynamicmedia\Arnold $
// -----------------------------------------------------------------------------

/**
 * @author  Arnold Konrad
 * @date    2007-02-04
 * @version 0.3.4
 * @fileoverview
 * 
 * The [nice] frame Javascript framework core file.
 */

// -----------------------------------------------------------------------------
// Namespaces
// -----------------------------------------------------------------------------

// We define all namespaces as functions to make JSDoc happy. Otherwise the
// generated documentation just won't look like it should ...
 
/**
 * @class
 * The common namespace for all framework components. The NICE class aditionally
 * offers static methods for object extension and dynamic code loading.
 */  
function NICE() {}

/**
 * @class
 * This namespace contains a set of classes for debugging purposes, such as a
 * debug console.
 */   
NICE.debug = function() {}

/**
 * @class
 * Contains classes for event handling and custom event creation.
 */  
NICE.event = function() {}

/**
 * @class
 * Contains utility classes used throughout the framework. 
 */  
NICE.util = function() {} 

/**
 * @class
 * Contains user-interface related classes.
 */  
NICE.ui = function() {}

// -----------------------------------------------------------------------------
// Static
// -----------------------------------------------------------------------------

/**
 * Loads the specified package.
 * <p>
 * Provides a convenient way to load Javascript packages at runtime.
 * The given package name has to use the following format:
 * <br><br><tt>[namespace].[class]</tt>
 * </p>
 * <p>
 * The class to load must reside in a directory relative to the framework
 * directory that mirrors the namespace hierarchy.
 * </p>
 * <p>
 * <tt>NICE.use("debug.DebugConsole")</tt><br>
 * The path to the class must be "%framework%/debug/DebugConsole.js". 
 * </p>
 * <p>
 * The loaded class should be a member of the specified namespace.
 * </p>
 * 
 * @param {String} pkg   The identifier of the package to load
 * @throws Error An Error object containing information on the error
 * @return <b>true</b> if the package was loaded, else <b>false</b>
 */     
NICE.use = function(pkg) {
	
	// -------------------------------------------------------------------------
	// Inner functions
	// -------------------------------------------------------------------------

	// Base URL of the framework
	var _baseUrl = null;
	
	// Returns the base url of the [nice] framework
	function _myUrl() {
		
		var url = null;
		var scripts = null;
		var match = null;
		var levels = null;
		
		if(!_baseUrl) {
			url = location.href;
			// Strip the filename from the path
			url = url.substr(0, url.lastIndexOf('/'));
			// Find the script block that contains nice.js
			scripts = document.getElementsByTagName("script");
			for(var i = 0; i < scripts.length; i++) {
				match = scripts[i].src.match(/(.*)nice.js/);
				if(match) {
					if(/^(file|http(?:s)?):/.test(match[1])) {
						// Firefox and Opera provide the absolute path
						url = match[1];
					} else {
						// Resolve the relative path
						levels = match[1].split('/');
						for(var j = 0; j < levels.length; j++) {
							switch(levels[j]) {
								case '..':
									url = url.substr(0, url.lastIndexOf('/'));
									break;
								case '.':
								case '':
									break;
								default:
									url += "/" + levels[j];
							}
						}
						url += "/";
					}
					break;
				}
			}
			
			_baseUrl = url;
		}
		
		return _baseUrl;
		
	}
	
	function _makePkgUrl(baseurl, pkg) {
		
		return baseurl + pkg.replace('.', '/') + ".js";
		
	}
	
	// Loads the given url and returns the response-text
	function _request(url) {
		
		var request = false;
    	// branch for native XMLHttpRequest object
    	if(window.XMLHttpRequest && !(window.ActiveXObject)) {
	    	try {
				request = new XMLHttpRequest();
	        } catch(e) {
				request = false;
	        }
    	// branch for IE/Windows ActiveX version
    	} else if(window.ActiveXObject) {
	       	try {
	        	request = new ActiveXObject("Msxml2.XMLHTTP");
	      	} catch(e) {
	        	try {
	          		request = new ActiveXObject("Microsoft.XMLHTTP");
	        	} catch(e) {
	          		request = false;
	        	}
			}
	    }
		if(request) {
			try {
				// Issue a blocking request (we need the result to go on)
				request.open("GET", url, false);
				request.send("");
				// Return the loaded content as plain text
				return request.responseText;
			} catch(e) {
				throw 'Request on "' + url + '" failed';
			}
		} else {
			throw new Error("Failed to create XMLHttpRequest object");
		}
		
	}
	
	// -------------------------------------------------------------------------
	// Loader code
	// -------------------------------------------------------------------------
	
	// Wrap the code in an anonymous function
	return (function() {
		
		var code = null;
		var pkgid = pkg.replace(/\./, "_");
		// Retrieve the framework's base url
		var url = _myUrl();
		// Form the package url
		url = _makePkgUrl(url, pkg);
		// Check if the class is already loaded
		if(typeof(NICE.loaded[pkgid]) != "undefined") return false;
		// Get the javascript code
		try {
			code = _request(url);
			eval(code);
			// Mark the file as loaded
			NICE.loaded[pkgid] = true;
		} catch(e) {
			alert(e.message);
			return false;
		}
		
		return true;
		
	})();
	
}

/**
 * Hashtable for loaded modules.
 * @ignore
 */
NICE.loaded = {}

/**
 * Loads the specified package and imports the class into the global namespace.
 * <p>
 * This method tries to load the given package using <tt>NICE.use</tt>. If this
 * is successful, it tries to import a class named like the package into the
 * global scope. If a symbol with the same name already exists, an exception is
 * thrown.
 * </p>
 * 
 * @param {String} pkg   The identifier of the package to load
 */ 
NICE.include = function(pkg) {
	
	// Load the given package
	if(!NICE.use(pkg)) return;
	
	var ns = pkg.split(".");
	var obj = NICE;
	var i;
	// Try to resolve the package name into the corresponding object
	for(i = 0; i < ns.length; i++) {
		if(obj[ns[i]]) {
			obj = obj[ns[i]];
		} else return;
	}
	--i;
	// Check if importing is allowed
	if(obj.noImport) return;
	// Import the symbol if it doesn't already exist
	if(!window[ns[i]]) {
		window[ns[i]] = obj;
	}
}

/**
 * Extends the functionality of a given object with members of another object.
 * <p>
 * This is done by attaching members of the extension object to the extended 
 * object. You can restrict extension to a set of members defined by
 * the parameter <tt>members</tt>. The parameter <tt>members</tt> can be a
 * single string or array of strings containing the member name(s) that shall
 * be included. If the member parameter is omitted, all members are copied.
 * </p>
 * 
 * @param {Object} cls        The class to extend
 * @param {Object} extension  The extension class to copy members from
 * @param {Array}  members    An array of members that shall be copied 
 */
NICE.extend = function(cls, extension, members) {
	
	// Extension shall be restricted
	if(members) {
		// Members contains an array of member names
		if(members.constructor == Array) {
			for(var i = 0; i < members.length; i++) {
				if(cls[members[i]]) continue;
				cls[members[i]] = extension[members[i]];
			}
		// A single member is given
		} else {
			if(!cls[members]) cls[members] = extension[members];
		}
	// Copy all members
	} else {
		for(var member in extension) {
			if(cls[member]) continue;
			cls[member] = extension[member];
		}
	}
	
}

// -----------------------------------------------------------------------------
// Base class
// -----------------------------------------------------------------------------

/**
 * @class
 * The core class all framework classes are derived from. The Base class
 * encapsulates functionality that is common to all framework objects.
 */   
NICE.Base = function() {}

// -----------------------------------------------------------------------------
// Public
// -----------------------------------------------------------------------------
	
/**
 * Checks if the object is an instance of the given class.
 * <p>
 * This method can be used for strict type-checking. It is syntactic sugar for
 * constructor-comparison:<br>
 * <tt>if(obj.constructor === Class) ...</tt>
 * </p>
 * 
 * @param {Object} cls  The class to check for	 
 * @return <b>true</b> if the object is an instance of <tt>cls</tt>
 * @type Boolean
 *
 * @example
 * NICE.include("ui.Button");
 *
 * // Create a simple button
 * var button = new Button(null, {identifier: "my-button"});
 * // Check if the button is an instance of NICE.ui.Button
 * alert(button.instanceOf(Button));
 */	 	 	 	 	
NICE.Base.prototype.instanceOf = function(cls) {
	
	try {
		// Comparison is done with cls.prototype.constructor because
		// a comparison with cls leads to a comparison with the constructor
		// of NICE.Base if the class is derived from NICE.Base.
		if(this.constructor === cls.prototype.constructor) return true;
	} catch(e) {}
	
	return false;
	
}

// -----------------------------------------------------------------------------
// Conditional compilation
// -----------------------------------------------------------------------------
// Some of the components of the framework use IE's conditional compilation
// feature to provide script code for IE only.
// -----------------------------------------------------------------------------

/*@cc_on @*/

// -----------------------------------------------------------------------------
// Workaround for ActiveX activation issue
// -----------------------------------------------------------------------------
// The following function should be included in util.SWFMovie, but due to the
// ActiveX activation issue in IE (Eolas patent), they have to reside in an
// external script file loaded with a <script> tag. Since util.SWFMovie is
// most likely loaded using NICE.use or NICE.include, this workaround is
// necessary.
// -----------------------------------------------------------------------------

// Use conditional compilation in IE to provide a tailored version for
// Internet Explorer  
/*@if(@_win32)

// For Internet Explorer
function _embed(parent, movie, params, properties) {

	var htm = '<object ' +
		'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
	var p = null;
	if(typeof(properties) == "object") {
		for(p in properties) {
			htm += ' ' + p + '="' + properties[p] + '"';
		}
	}
	htm += '>';
	htm += '<param name="movie" value="' + movie + '" />';
	for(p in params) {
		htm += '<param name="' + p + '" value="' + params[p] + '" />';
	}
	htm += '</object>';
	
	parent.style.visibility = "hidden";
	var container = document.createElement("div");
	parent.appendChild(container);
	container.innerHTML = htm;
	parent.style.visibility = "visible";
	
}

@else @*/

/**
 * For all other browsers
 * @ignore
 */
function _embed(parent, movie, params, properties) {
	
	var object = document.createElement("object");
	object.type = "application/x-shockwave-flash";
	object.data = movie;
	
	var p = null;
	if(typeof(properties) == "object") {
		for(p in properties) {
			object[p] = properties[p];
		}
	}
	var param = null;
	for(p in params) {
		param = document.createElement("param");
		param.name = p;
		param.value = params[p];
		object.appendChild(param);
	}
	parent.appendChild(object);
	
}

/*@end @*/

