// Prototype.box.js (Base Object Extension)
// Author: SLimonov, ARevinsky
// Reguires: prototype.js
if (!('Prototype' in window)) throw "Requires prototype.js";

window.G = {};

var namespace = function (nsName) {
	var nsContainer = window;
	nsName.split('.').each(function (ns) {
		if (!(ns in nsContainer)) nsContainer[ns] = {};
		nsContainer = nsContainer[ns];
	});
	return nsContainer;
};

var using = function (nsName) {
	var nsContainer = window;
	nsName.split('.').each(function (ns) {
		if (!(ns in nsContainer)) throw("Namespace " + nsName + " is not defined.");
		nsContainer = nsContainer[ns];
	});
	Object.extend(window, nsContainer);
};

Class.inherit = function() {
	switch (arguments.length) {
		case 1: // (source)
			destination = Class.create();
			base = null;
			source = arguments[0];
			break;
		case 2: // (base, source)
			destination = Class.create();
			base = arguments[0];
			source = arguments[1];
			break;
		case 3: // (destination, base, source)
			destination = arguments[0];
			base = arguments[1];
			source = arguments[2];
			break;
		default:
			return null;
	}
	destination.__base = base;
	if (base) {
		Object.extend(destination.prototype, base.prototype);
	}
	for (property in source) {
		var val = source[property];
		if (typeof val == 'function') {
			var _base = destination.prototype[property];
			if (_base) val.__base = _base;
		}
		destination.prototype[property] = val;
	}
	return destination;
};


var Multicast = {
	_methodsGC: [],
	_unload: false,
	add: function(contextObj, invokingObj, invokingMethod, workerFunc, runOnce) {
		invokingObj = (invokingObj ? invokingObj : window);
		var mountPt = invokingObj[invokingMethod];
		var methods = (typeof(mountPt) == 'function' && !mountPt.callables) ? [mountPt] : []; // safekeeping pre-existed handler if it wasn't our multicast wrapper
		if ((typeof(mountPt) != 'function') || !mountPt.callables) {
			mountPt = invokingObj[invokingMethod] = this._makeFunc(contextObj);
			if (invokingObj["nodeType"]) this._tagForGC(invokingObj, invokingMethod);
		}
		if (typeof(workerFunc) == 'function') {
			methods.push(workerFunc);
		} else if ((contextObj ? contextObj : window)[workerFunc] instanceof Function) {
			methods.push((contextObj ? contextObj : window)[workerFunc]);
		}
		for (var i = 0, j = methods.length; i < j; methods[i++] = null) { // killing extra references
			this._append(contextObj, methods[i], mountPt, runOnce);
		}
		delete methods;
		delete mountPt;
	},
	_isUnderDevelopment: /^http\:\/\/localhost(?:\:\d*)?\/(?!.*?[?&]EmulateRuntime)/i,
	_makeFunc: function(contextObj) {
		contextObj = contextObj || null;
		try {
			var _this = this;
			var func = function(){
				var results, result, __method = arguments.callee;
				for (var i = 0, j = __method.callables.length; i < j; i++) {
					if (__method.callables[i]) {
						var dev = false; try { dev = !!(window.location.href); } catch (e) {}
						if (dev && (_this._isUnderDevelopment).test(window.location.href)) {
							// set watch for __method.callables[i].toString()
							results = results || __method.callables[i].apply(contextObj, arguments);
						} else
						// clause for local debugging - end
						try {
							result = __method.callables[i].apply(contextObj, arguments);
							results = results || result;
						} catch (e) {
							__method.callables[i].reuse = false;
						}
					}
					if (_this._tidyUp(__method.callables, __method.hashes, i)) {
						i--; j--;
					}
				}
				return results;
			};
			func.callables = [];
			func.hashes = {};
			return func;
		} finally {
			delete func;
			delete _this;
		}
	},
	_append: function(contextObj, method, mountPt, runOnce) {
		if (!method) return;
		var key = (method.hash) ? method.hash : Math.random().toString().substr(2,10);
		if (mountPt.hashes[key]) return;
		mountPt.hashes[key] = {};
		var wrapper = function() { return method.apply(contextObj, arguments); };
		wrapper.hash = method.hash = key;
		wrapper.reuse = !runOnce;
		mountPt.callables.push(wrapper);
	},
	_tidyUp: function(callables, hashes, i) {
		if (callables.length == 0) return false;
		var callable = callables[i];
		if (callable.reuse) return false;
		delete hashes[callable.hash];
		callables.splice(i, 1);
		return true;
	},
	_tagForGC: function(object, method) {
		if (!this._unload) {
			this._unload = true;
			this.add(this, null, "onunload", this._runGC, true);
			this._tagForGC(window, "onunload");
		}
		this._methodsGC.push( { "object": object, "method": method } );
	},
	_runGC: function() {
		for (var i = 0, entry; (entry = this._methodsGC[i]); i++ ){
			entry.object[entry.method] = null;
			delete entry.object;
			delete this._methodsGC[i];
		}
		delete this._methodsGC;
	},
	addWindowOnLoad: function(func, object) {
		this.add(object, window, "onload", func, true);
	},
	addWindowOnUnload: function(func, object) {
		this.add(object, window, "onunload", func, true);
	},
	addDocumentReadyStateChange: function(func, doc) {
		if (!document.all) 
			doc.addEventListener("DOMContentLoaded", func, false);
		else 
			this.add(doc, doc, "onreadystatechange", function(){ func();}, true);
	}
};

function SetEvent() {
	throw("SetEvent: Obsolete");
	Multicast.add.apply(Multicast, arguments);
}
function addLoadEvent() {
	Multicast.addWindowOnLoad.apply(Multicast, arguments);
}

function addLoadDOMEvent(func, targetDocument) {
	targetDocument = targetDocument || window.document;
	Multicast.addDocumentReadyStateChange(func, targetDocument);
}

function addUnLoadEvent() {
	Multicast.addWindowOnUnload.apply(Multicast, arguments);
}

var BaseObject = Class.create();
Object.extend(BaseObject, {
	base: function(object) {
		var _base = arguments.callee.caller.__base;
		if (typeof _base != 'function') throw ("Base method isn't defined. Use Class.inherit function for class definition.");
		return _base.apply(object, $A(arguments).shift());
	},
	observe: function(hostObj, name, handler, runOnce) {
		name = 'on' + name;
		if (hostObj[name] && !('_observed' in hostObj[name])) return hostObj;
		Multicast.add(hostObj, hostObj, name, handler, runOnce);
		hostObj[name]['_observed'] = true;
		return hostObj;
	},
	stopObserving: function(hostObj, name, handler) {
		throw "Not implemented";	
	}
});

Class.inherit(BaseObject, null, {
	initialize:	function () {
	},
	base: function() {
		var _base = arguments.callee.caller.__base;
		if (typeof _base != 'function') throw ("Base method isn't defined.");
		return _base.apply(this, arguments);
	},
	observe: function(name, handler, runOnce) {
		return BaseObject.observe(this, name, handler, runOnce);
	},
	stopObserving: function(name, handler) {
		return BaseObject.stopObserving(this, name, handler);
	}
});

// [AtlasScript]

if(typeof(Sys)!="undefined")
	Sys.Application.notifyScriptLoaded();

// [/AtlasScript]
			