Kernel= {}

Kernel.SCRIPT_NAME= 'Kernel.js';

Kernel.rootPath= '';

Kernel._includedScripts= {};

Kernel._includedStylesheets= {};



Kernel._init= function() {
	var aScripts= document.getElementsByTagName('script');
	var hScript= null;

	for (var i= 0 ; i < aScripts.length ; i++) {
		var uScriptPath= aScripts[i].src;
		if (uScriptPath.indexOf('/'+this.SCRIPT_NAME) >= 0) {
			hScript= aScripts[i];
			hScript.id= 'Kernel:script';
			break;
		}
	}

	if (!hScript) {
		alert('Kernel loading failure:\nUnable to determine kernel path');
		return;
	}

	this.rootPath= hScript.src.substr(0, hScript.src.indexOf('/'+this.SCRIPT_NAME));
	this._includedScripts.last= hScript;

	aCommands= hScript.src.substr(hScript.src.indexOf('#')+1).split('#');
	for (var i= 0; i < aCommands.length; i++) {
		try {
			this.processCommand(aCommands[i]);
		}
		catch (err) {
			alert('Error while processing commands:\n'+err.message);
			return;
		}
	}
}

Kernel.registerOnLoad= function(sCode) {
	if (!this._toRunOnLoad) this._toRunOnLoad= []; //lazy variable init

	iSeparator= sCode.indexOf('(');
	if (iSeparator < 0) {
		sFunctionName= sCode;
		sParams= '()';
	}
	else {
		sFunctionName= sCode.substr(0, iSeparator);
		sParams= sCode.substr(iSeparator);
	}

	this._toRunOnLoad.push({
		'func': sFunctionName,
		'params':sParams
	});

	if (!this._loadMonitor)
		this._loadMonitor= setInterval('if (Kernel.isEverythingLoaded()) {clearInterval(Kernel._loadMonitor); Kernel._loadMonitor= null; Kernel._load();}', 200);
}

/*
Enhancements in order to detect real script loading:
	http://ajaxian.com/archives/a-technique-for-lazy-script-loading
*/
Kernel.isEverythingLoaded= function() {
	for (var i= 0; i < this._toRunOnLoad.length; i++) {
		try {
			eval(this._toRunOnLoad[i].func+' instanceof Function');
		}
		catch (err) {
		/* could be enriched in order to distinguish between 'x is undefined' errors and others */
			return false;
		}
	}
	return true;
}

Kernel._load= function() {
	for (var i= 0; i < this._toRunOnLoad.length; i++) {
		eval(this._toRunOnLoad[i].func+this._toRunOnLoad[i].params);
	}
	this._toRunOnLoad= null;
}



Kernel.processCommand= function(sCommand) {
	iSeparator= sCommand.indexOf('=');
	if (iSeparator <= 0) {
		throw new Error('Wrong command syntax: '+sCommand);
	}
	sCommandName= sCommand.substr(0, iSeparator).toLowerCase();
	sCommandParam= sCommand.substr(iSeparator+1);

	switch (sCommandName) {
	case 'include':
		this.include(sCommandParam);
		break;
	case 'run':
		this.run(sCommandParam);
		break;
	default:
		throw new Error('Unknown command: '+sCommandName);
	}
}



Kernel.include= function(uAsset) {
//Imports a script or a stylesheet.
//The following placeholders are allowed in uAsset :
// %KROOT% : the kernel's root path (URL of the folder where the Kernel is located)
	if (uAsset.indexOf('%KROOT%') >= 0) uAsset= uAsset.replace('%KROOT%', this.rootPath);

	iLastDot= uAsset.lastIndexOf('.');
	if (iLastDot <= 0) return false;
	sExtension= uAsset.substr(iLastDot+1).toLowerCase();
	switch (sExtension) {
	case 'js':
		return this.includeScript(uAsset);
		break;
	case 'css':
		return this.includeStylesheet(uAsset);
		break;
	default:
		return false;
	}
}

Kernel.includeStylesheet= function(uStylesheet) {
//Imports the specified stylesheet
	var hLink= this._includedStylesheets['included_'+uStylesheet];
	if (!hLink) {
		hLink= document.createElement('link');
		hLink.rel= 'stylesheet';
		hLink.type= 'text/css';
		hLink.href= uStylesheet;
		document.getElementsByTagName('head')[0].appendChild(hLink);

		this._includedStylesheets['included_'+uStylesheet]= hLink;
	}
	return hLink;
}

Kernel.includeScript= function(uScript) {
//Imports the specified script (executes it only if it is the first time you import it)
	var hScript= this._includedScripts['included_'+uScript];
	if (!hScript) {
		hScript= document.createElement('script');
		hScript.type= 'text/javascript';
		hScript.src= uScript;
		this._includedScripts.last.parentNode.insertBefore(hScript, this._includedScripts.last.nextSibling); //append the new script after the kernel script element

		this._includedScripts['included_'+uScript]= hScript;
		this._includedScripts.last= hScript;
	}
	return hScript;
}

Kernel.run= function(sScriptAndFunction) {
	iSeparator= sScriptAndFunction.indexOf('::');
	if (iSeparator < 0) {
		//throw new Error('Wrong parameter syntax for [run] command: '+sScriptAndFunction);
		this.registerOnLoad(sScriptAndFunction);
	}
	else {
		uScript= sScriptAndFunction.substr(0, iSeparator);
		sFunctionName= sScriptAndFunction.substr(iSeparator+2);

		this.include(uScript);
		this.registerOnLoad(sFunctionName);
	}
}






/* Initialization */
Kernel._init();
