/**
* Framework
* this javascript file of the framework holds multiple classes:
* - Avr
* - Avr.events
* - Avr.status
* - preLoader
* - Core
*
* TODO:
* - Resolve scope issues for the script package preloader
* - dispatchEvents can now only launch one event callback, not multiple
* @version 0.0.2 - 15 dec 2009
* @author Arno van Rossum
* @contact: www.van-rossum.com
*/

/**
* @param Options {
	basePath: String // Optional: if you want to relocate the avr framework, default avr/
	packagePath: String // Optional: default packages/
	packages: Array // Optional: if you want other packages to be loaded, not advised to use
}
*/
Avr.prototype = new Core();
function Avr(pOptions) {
	/**
	* All modules to load
	* @var array
	*/
	this.packages = {
		'progressBar': new Array('progressbar.status.js', 'progressbar.events.js', 'progressbar.js'),
		'events': new Array('events.js'),
		'ajax': new Array('ajax.js'),
		'slider': new Array('slider.direction.js',  'slider.js'),
		'google': new Array('googlemarker.js', 'googlewrapper.js'),
		'clock': new Array('clock.js'),
		'cookies': new Array('cookie.js'),
		'tabs': new Array('tabs.js')
	};

	/**
	* Package Location
	*/
	this.basePath = 'avr/';
	this.packagePath = 'packages/';

	this.preloader = new Preloader();
	this.packageLoaded = new Array();

	this.constructor = function(pOptions) {
		if ( pOptions != undefined ) {
			if ( pOptions.packages != undefined ) this.packages = pOptions.packages;
			if ( pOptions.basePath != undefined ) this.basePath = pOptions.basePath;
			if ( pOptions.packagePath != undefined ) this.packagePath = pOptions.packagePath;
		}
		this.preloader.addListener(Avr.events.loadScript, new Array(this, 'scriptLoaded'));

		this.dispatchEvent(Avr.events.onload, Avr.status.succes);
	}

	/**
	* @param String, package name to load
	*/
	this.loadPackage = function(package) {
		if ( this.packageIsLoaded(package) == false ) {
			for(key in this.packages) {
				if ( key == package ) {
					for(fileindex in this.packages[key]) {
						this.preloader.loadScript(this.basePath + this.packagePath + package + "/" + this.packages[key][fileindex]);
					}
				}
			}
		}
		else this.dispatchEvent(Avr.events.loadPackage, Avr.status.packageLoaded);
	}
	this.scriptLoaded = function(eventType, status) {
		for( package in this.packages ) { // Door package
			if ( this.packageIsLoaded(package) == false ) { // Package is niet loaded
				bPackageLoaded = true;
				// Loop door alle package scripts welke niet loaded zijn
				for(scriptindex in this.packages[package]) {
					// Dit script moet geladen zijn voor succesvol package

					script = package + '/' + this.packages[package][scriptindex];
					
					inPreloader = false;
					for( key in this.preloader.scripts ) {
						loadedScript = this.preloader.scripts[key];
						loadedScript = loadedScript.substr((loadedScript.length - script.length));
						if ( script == loadedScript ) {
							inPreloader = true;
						}
					}

					if ( inPreloader != true ) {
						bPackageLoaded = false;
					}
				}
				if ( bPackageLoaded == true ) { // Add package when loaded and dispatch event
					this.packageLoaded.push(package);
					this.dispatchEvent(Avr.events.loadPackage, Avr.status.succes, {'packageLoaded': package});
				}
			}
		}
	}
	
	this.scriptIsLoaded = function(script) {
		var bLoaded = false;
		// Check if package is loaded
		for(p in this.preloader.scripts) {
			if ( script == this.preloader.scripts[p] ) {
				bLoaded = true;
			}
		}
		return bLoaded;
	}
	
	/**
	* @param String, is the package loaded
	* @return Boolean
	*/
	this.packageIsLoaded = function(package) {
		var bLoaded = false;
		// Check if package is loaded
		for(p in this.packageLoaded) {
			if ( package == this.packageLoaded[p] ) {
				bLoaded = true;
			}
		}
		return bLoaded;
	}
	
	this.constructor(pOptions);
}
Avr.events = {
	'onload': 1,
	'loadPackage': 2,
	'loadScript': 3
}
Avr.status = {
	'succes': 1,
	'failed': 2,
	'packageLoaded': 3
}

/**
* This object makes it possible to perload javascript / css
*/
Preloader.prototype = new Core();
var tempPreLoader;
function Preloader() {
	this.scripts = new Array();

	this.constructor = function() {
	
	}
	
	
	this.onLoad = function(script) {
		this.scripts.push(script);
		this.dispatchEvent(Avr.events.loadScript, Avr.status.succes);
	}
	/**
	* Load a script
	* @param String, Script file name
	*/
	this.loadScript = function(pScript) {
		var script = document.createElement('script');
		script.setAttribute('src', pScript);
		script.setAttribute('type','text/javascript');

		// Scoping issues
		tempPreLoader = this;
		script.onload = fctonload;
		script.onreadystatechange = fctreadystatechange;
		var head = document.getElementsByTagName('head')[0];
		head.appendChild(script);
	}
}
function fctonload() {
	if ( tempPreLoader != undefined ) {
		tempPreLoader.onLoad(this.src);
	}
}
function fctreadystatechange() {
	if(this.readyState == 'loaded' && tempPreLoader != undefined ) {
		tempPreLoader.onLoad(this.src);
	}
}
/*******************/

/**
* This class holds basic features, error handling, and event triggering
*/
function Core() {
	this.events = new Array();
	/**
	* Add listener to this class instance
	* @param eventType
	* @param Function
	*/
	this.addListener = function(eventType, fct) {
		this.events[eventType] = fct;
	}

	/**
	* Remove listener of this instance
	* @param eventType
	*/
	this.removeListener = function(eventType) {
		this.events[eventType] = undefined;
	}

	/**
	* Dispatch the event
	* @param eventType
	* @param statusType
	* @param Optional data
	*/
	this.dispatchEvent = function(eventType, statusType, extra) {
		if ( extra == undefined ) extra = '';
		
		if ( this.events[eventType] != undefined && this.events[eventType] != "" ) {
			// Send to an object through reference
			if ( this.events[eventType][0] != undefined && typeof(this.events[eventType][0]) == 'object' && typeof(this.events[eventType][1]) == "string") {
				this.events[eventType][0][this.events[eventType][1]](this, eventType, statusType, extra);
			}
			else {
				this.events[eventType](this, eventType, statusType, extra);
			}
		}
	}
	
	

	/**
	* Internal error handler
	* @param String
	* @param Integer
	*/
	this.error = function(pMessage, pCode) {
		throw {message: pMessage, code: pCode}
	}
}
