var CallbackHolder = Class.create({
	initialize: function () {
		window.callbacks = {};
	},
	storeCallback: function (name, func, owner) {
		window.callbacks[name] = {'callback':func,'owner':owner};
	},
	invokeCallback: function (name,param) {
		var callback = window.callbacks[name].callback;
		var owner = window.callbacks[name].owner;
		callback(param,owner);
	}
});

var Classloader = Class.create({
	contextPath: application.contextPath,
	prefix: application.jsPrefix,
	elements: {},
	initialize: function (classMapping) {
		this.lastId = 0;
		this.jsResources = classMapping;
		this.scriptState = {};
	},
	createId: function () {
		this.lastId++;
		return this.lastId;
	},
	forName: function (name) {
		return window[name];
	},
	instanceOf: function (name,element,id) {
		var createStr = 'new ' + name + '(element,id);';
		try {
			var instance = eval(createStr);
			log.debug("new instance for: " + name);
		} catch (exception) {
			log.debug(exception);
			document.observe('dom:loaded', function() {
				this.instanceOf(name, element, id);
			}.bind(this));
		}
	},
	isScriptLoading: function (name) {
		return typeof this.scriptState[name] != 'undefined' && this.scriptState[name] > 0;
	},
	isScriptLoaded: function (name,dep) {
		return typeof this.scriptState[name] != 'undefined' && this.scriptState[name] > 1;
	},
	createScript: function (name,dep) {
		if ((dep == null || !this.isScriptLoading(name)) && !this.isScriptLoading(dep)) {
			var head = document.getElementsByTagName('head')[0];
			var script = document.createElement('script');
			script.type = 'text/javascript';
			if (dep != null) {
				this.scriptState[dep] = 1;
				script.src = this.contextPath + dep + '?' + application.stamp;
				script.id = 'dep-' + name;
				script.setAttribute('js:dep', dep);
			} else {
				this.scriptState[name] = 1;
				script.src = this.contextPath + this.prefix + name + '.js?' + application.stamp;
				script.id = name;
			}
	
			var cb = this.onScriptLoaded;
			script.onreadystatechange= function () {
				if (this.readyState == 'complete' ||
					this.readyState == 'loaded') {
					cb(script);
				}
			}
			script.onload = cb;
		
			head.appendChild(script);
		} else if (dep == null && this.isScriptLoaded(name)) {
			this.instantiate(name);
		}
	},
	onScriptLoaded: function (e) {
		var id = '';
		var element;
		if (wkutils.isUndefined(e.id)) {
			id = Event.element(e).id;
			element = Event.element(e);
		} else {
			id = e.id;
			element = e;
		}
		if (id.startsWith('dep-')) {
			id = id.substring(4);
			classloader.scriptState[element.getAttribute('js:dep')] = 2;
		} else {
			classloader.scriptState[id] = 2;
		}
		classloader.instantiate(id);
	},
	instantiate: function (name) {
		setTimeout(function () {
			if (typeof this.elements[name] != 'undefined' && this.depSatisfied(name)) {
				for (var j=0; j<this.elements[name].length; j++) {
					if (this.elements[name][j] != null) {
						var element = this.elements[name][j];
						var id = this.createId();
						this.instanceOf(name, element, id);
						this.elements[name][j] = null;
					}
				}
			}
		}.bind(this), 0);
	},
	register: function (element, className) {
		log.debug("Register " + className);
		
		if (typeof this.elements[className] == 'undefined') {
			this.elements[className] = [];
		}
		
		this.elements[className].push(element);
		
		if (application.deferredLoading) {
			this.jsResources[className].each(function (dep) {
				if (dep.endsWith('.js')) {
					this.createScript(className,dep);
				} else {
					this.createScript(dep,null);
				}
			}.bind(this));
			this.createScript(className,null);
		} else {
			this.instanceOf(className, element, this.createId());
		}
	},
	depSatisfied: function (name) {
		if (typeof this.jsResources[name] != 'undefined') {
			this.jsResources[name].each(function (res) {
				if (!this.isScriptLoaded(res)) {
					return false
				}
			}.bind(this));
		} else {
			return false;
		}
		return true;
	}
});

window.callbackHolder = new CallbackHolder();

window.classloader = new Classloader(
		{
		 ImageGallery: [],
		 AjaxForm: [],
		 HtmlForm: [],
		 CommentForm: [],
		 ShoppingCart: []
		});