/**
 * LICENSE
 *
 * This source file is subject to the EWS Software License that is bundled
 * with this package in the file LICENSE.txt.
 * If you did not receive a copy of the license please send us an email
 * so we can send you a copy immediately.
 * Permission to copy and distribute verbatim copies of this source
 * are not granted.
 *
 * @copyright 	Copyright (c) 2008-2009 entrance web studio
 * @license	EWS Software License
 */

/**
 * Global javascript file.
 *
 * Defines some important functions for global access
 */

// include
var _includer = new CInclude;


/**
 * Includes a javascript file. Wrapper for the CInclude object. Optionally a callback can be set which is
 * executed after including task has finished
 *
 * @param Array|String file
 * @param Function callback
 * @return void
 */
function include ( file , callback ) {
	_includer.include ( file , callback );
}


/**
 * Pseudo factory method to create elements.
 *
 * @param String element
 * @param Object properties
 * @return HTMLElement elem
 */
function createElement ( tagName , properties ) {
	var elem = document.createElement ( tagName );
	
	if ( ! elem )
		throw new Error ( "Cannot create DOM node. Invalid tag name supplied" );
	
	if ( properties != undefined ) {
		for ( var key in properties )
			elem.setAttribute ( key , properties [ key ] );
	}
	
	return elem;
}


// REFACTOR
/*
function log ( msg ) { 
	$ ( "console-output" ).innerHTML += msg + "<br>"; 
}
*/


/**
 * Includer class.
 *
 * Simulates a pseudo include function for local or external javascript sources.
 *
 * @author Christoph Lukas Lindtner
 * @copyright entrance web studio
 */
function CInclude () 
{
	/* ------------------------------------------------------------------------------------------------------------ *
	 *							 																				     																										*
	 * Class variables																								     																					*
	 *																											     																										*
	 * ------------------------------------------------------------------------------------------------------------ */
	 
	/**
	 * List with all included files.
	 *
	 * @var Array includedFiles
	 */
	var _includedFiles = new Array ();
	
	
	/**
	 * Files waiting for inclusion.
	 *
	 * @var Object tasksWaiting
	 */
	var _tasksWaiting = new Object ();
	
	
	/* ------------------------------------------------------------------------------------------------------------ *
	 *							 																				     																										*
	 * Class methods																									     																					*
	 *																											     																										*
	 * ------------------------------------------------------------------------------------------------------------ */
	 
	/**
	 * Main function to include files.
	 *
	 * @param String|Array files
	 * @param Function callback
	 */
	this.include = function ( file , callback ) {
		var header = document.getElementsByTagName ( "head" ) [ 0 ];
		var fileArray = [];
		
		// if file is string, give a single index element
   	if ( typeof ( file ) == "string" )
			fileArray.push ( file );
		
		// if file is array just merge
		else if ( file instanceof Array )
			fileArray = file;
			
		else
			return false;
		
		// Create a unique id using the current time
		var taskId = new Date () . getTime () . toString ();
		_tasksWaiting [ taskId ] = { 
			"loading" : fileArray.length , 
			"task" : callback
		};
		
		// if no files need to be loaded execute the callback
		if ( fileArray.length <= 0 ) {
			callback.call ();
			return;
		}
		
		//go through all the files
		for ( var i = 0; i < fileArray.length; i++ ) {
			var fileinfo = getFileInfo ( fileArray [ i ] );
			
			// skip already included files
			if ( _includedFiles.indexOf ( fileinfo.path ) > 0 ) {
				// decrease loading counter in task
				_tasksWaiting [ taskId ].loading--;
				
				// and continue
				continue;
			}
			
			// create tag
			if ( fileinfo.tag != null ) {
				var elem = document.createElement ( fileinfo.tag );
        elem.setAttribute ( "type" , fileinfo.mime );
        
        // special treatment for css
        switch ( fileinfo.ext ) {
        	case "js" : {
        		elem.setAttribute ( "src" , fileinfo.path );
        		break;
        	}
        	case "css" : {
        		// onload doesn't work for css files. 
        		_tasksWaiting [ taskId ].loading--;
        		
        		elem.setAttribute ( "href" , fileinfo.path );
        		elem.setAttribute ( "rel" , "stylesheet" );
        		break;
        	}
        }
        
        // append to head tag
        header.appendChild ( elem );
        
        // push into _includedFiles
        _includedFiles.push ( fileinfo.path );
        
        jQuery ( elem ).bind ( "load" , function ( e ) { fileLoaded ( taskId ) } );
			}
		}
		
		// if no files need to be included trigger callback
		if ( _tasksWaiting [ taskId ].loading <= 0 && callback instanceof Function )
    	callback.call ();
	}                     
                        
                        
	/**
	 * @private
	 */
	
	/**
	 * Pass a file name and return a array with file name and extension.
	 *
	 * @param String file
	 * @return Object info
	 */
	function getFileInfo ( file ) {
		file = file.replace (/^\s|\s$/g, "") ;
		var info;
   
    if (/\.\w+$/.test ( file ) ) {
    	// split up file and get extension and tag info
			info = file.match ( /([^\/\\]+)\.(\w+)$/ );
			
			if ( info ) {
				switch ( info [ 2 ] ) 
				{
					case "js" : {
						return {
							"path" : file ,
							"filename" : info [ 1 ] ,
							"ext" : info [ 2 ] ,
							"tag" : "script" ,
							"mime" : "text/javascript"
						};
					}
					
					case "css" : {
						return {
							"path" : file ,
							"filename" : info [ 1 ] ,
							"ext" : info [ 2 ] ,
							"tag" : "link" ,
							"mime" : "text/css"
						};
					}
					
					default : {
						return {
							"path" : file ,
							"filename" : info [ 1 ] ,
							"ext" : info [ 2 ] ,
							"tag" : null ,
							"mime" : null
						};
					}
				}
			} else {
				info = file.match(/([^\/\\]+)$/);
				if ( info ) {
					return {
						"path" : file ,
						"filename" : info [ 1 ] ,
						"ext" : null ,
						"tag" : null ,
						"mime" : null
					};
				}
				else {
					return {
						"path" : file ,
						"filename" : null ,
						"ext" : null ,
						"tag" : null ,
						"mime" : null
					};
				}
			}
		}
	}
	
	
	/**
	 * Invoke if file has been loaded.
	 *
	 * @param int taskId
	 * @return void
	 */
	function fileLoaded ( taskId ) {
		// check if taskId is waiting
		if ( taskId in _tasksWaiting ) {
			// decrease loading counter
			// if counter is equal 0 execute callback and delete task
			if ( ( _tasksWaiting [ taskId ].loading -= 1 ) <= 0 ) {
				var callback = _tasksWaiting [ taskId ].task;
				
				// delete task
				delete _tasksWaiting [ taskId ];
				
				// call
        if ( callback instanceof Function )
        	callback ();
      }
		}
	}
}
