/* ========================================================================

    Modello, Object-orientied JavaScript Framework

    Author: Ken Xu <ken@ajaxwing.com>

    For more information, see: http://modello.sourceforge.net/

   ------------------------------------------------------------------------

    Copyright 2006 by Ken Xu

                            All Rights Reserved

    Permission to use, copy, modify, and distribute this software and its
    documentation for any purpose and without fee is hereby granted, provided
    that the above copyright notice appear in all copies and that both that
    copyright notice and this permission notice appear in supporting
    documentation, and that the name of Ken Xu not be used in advertising or
    publicity pertaining to distribution of the software without specific,
    written prior permission.

    KEN XU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
    KEN XU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

   ======================================================================== */


var Modello = {
	version: '0.0.4',
	date: '2006-06-30'
}

var Class = new (function () {
	var _class_depository = {__all__:[]};
	this.getClassDepository = function () {return _class_depository;}
	this.create = function () {
		var cls = function () {this.__class__ = arguments.callee; _construct.apply(this, arguments);}
		_extends(cls, arguments);
		cls.register = function (path, override) {return Class.register(this, path, override);}
		cls.create = _createInstance;
		cls.toString = _toStringClass;
		cls.subclassOf = function (cls) {return _subclassOf(this, cls);}
		cls.superclassOf = function (cls) {return _subclassOf(cls, this);}
		_class_depository.__all__.push(cls);
		return cls;
	}
	this.isClass = function (cls) {
		return (typeof cls == 'function' && cls.create == _createInstance) ? true : false
	}
	this.isInstance = function (obj) {
		return (typeof obj == 'object' && this.isClass(obj.__class__)) ? true : false
	}
	this.register = function (cls, path, override) {
		var override = override || false;
		if (typeof cls != 'function') {
			throw new Error('Class register error: The first argument must be a function');
		}
		var pair = [];
		if (!_parse_path(path, pair)) {
			throw new Error('Class register error: Invalid class path');
		}
		var pkg = pair[0];
		var cn = pair[1];
		var old_class = _class_depository[pkg][cn];
		if (old_class) {
			if (override) {
				delete old_class.__package__;
				delete old_class.__classname__;
			} else {
				throw new Error('Class register error: Class "' + path + '" already exists');
			}
		}
		_class_depository[pkg][cn] = cls;
		cls.__package__ = pkg;
		cls.__classname__ = cn;
		return cls;
	}
	this.get = function (path) {
		var pair = [];
		if (!_parse_path(path, pair, true) || !_class_depository[pair[0]][pair[1]]) {
			throw new Error('Class get error: Class "' + path + '" is not found');
		}
		return _class_depository[pair[0]][pair[1]];
	}
	this.abstractMethod = function () {
		throw new Error('Class runtime error: Call an abstract method that has not been implemented');
	}
	this.toString = function () { return '[object Class]'; }
	var _parse_path = function (path, pair, check) {
		if (typeof path != 'string' || path.length == 0) {
			return false;
		}
		var arr = path.split('.');
		if (arr.length > 1) {
			pair[0] = arr.slice(0, arr.length - 1).join('.');
			pair[1] = arr[arr.length - 1];
		} else {
			pair[0] = '';
			pair[1] = path;
		}
		if (typeof _class_depository[pair[0]] != 'object') {
			if (check) {
				return false;
			} else {
				_class_depository[pair[0]] = {};
			}
		}
		return true;
	}
	var _createInstance = function () {
		var args = [];
		for (var i = 0; i < arguments.length; i++) {
			args.push('arguments[' + i + ']');
		}
		return eval('new this(' + args.join(', ') + ');');
	}
	var _extends = function (cls, args) {
		cls.__superclasses__ = [];
		for (var i = 0; i < args.length; i++) {
			var superclass = args[i];
			if (typeof superclass == 'string') {
				superclass = Class.get(superclass);
			}
			if (typeof superclass != 'function') {
				throw new Error('Class create error: Invalid superclass: ' + 'args[' + i + ']');
			}
			cls.__superclasses__.push(superclass);
		}
	}
	var _construct = function () {
		var cls = this.__class__;
		for (var i = cls.__superclasses__.length - 1; i >= 0; i--) {
			var s = cls.__superclasses__[i];
			eval('this.super' + i + ' = new s(Class);');
			eval('_extend(this, this.super' + i + ');');
		}
		this.__class__ = cls;
		this.toString = _toStringInstance;
		if (typeof cls.construct == 'function') {
			cls.construct.apply(this, [this, cls]);
		}
		this.getClass = function () {return this.__class__;}
		this.instanceOf = _instanceOf;
		this.isA = function (cls) {return this.instanceOf(cls) || _subclassOf(this.__class__, cls);}
		if (arguments[0] != Class && typeof this.initialize == 'function') {
			this.initialize.apply(this, arguments);
		}
	}
	var _extend = function (dest, src) {
		for (prop in src) {
			if (prop.substr(0, 5) == 'super' && !isNaN(parseInt(prop.substr(5)))) {
				continue;
			}
			dest[prop] = src[prop];
		}
	}
	var _toStringClass = function () {
		if (this.__classname__) {
			if (this.__package__.length > 0) {
				return '[class ' +  this.__package__ + '.' + this.__classname__ + ']';
			} else {
				return '[class ' +  this.__classname__ + ']';
			}
		} else {
			return '[class Anonymous]';
		}
	}
	var _toStringInstance = function () {
		if (this.__class__.__classname__) {
			if (this.__class__.__package__.length > 0) {
				return '[object ' + this.__class__.__package__ + '.' + this.__class__.__classname__ + ']';
			} else {
				return '[object ' + this.__class__.__classname__ + ']';
			}
		} else {
			if (this.__class__) {
				return '[object Anonymous class]';
			} else {
				return '[object Object]';
			}
		}
	}
	var _instanceOf = function (cls) {
		if (typeof cls == 'string') {
			cls = Class.get(cls);
		}
		if (typeof cls != 'function') {
			return false;
		}
		return this.__class__ == cls;
	}
	var _subclassOf = function (cls1, cls2) {
		if (typeof cls1 == 'string') {
			cls1 = Class.get(cls1);
		}
		if (typeof cls2 == 'string') {
			cls2 = Class.get(cls2);
		}
		if (typeof cls1 != 'function' || typeof cls2 != 'function') {
			return false;
		}
		if (!cls1.__superclasses__ || cls1.__superclasses__.constructor != Array) {
			return false;
		}
		for (var i = 0; i < cls1.__superclasses__.length; i++) {
			if (cls1.__superclasses__[i] == cls2) {
				return true;
			} else {
				if (_subclassOf(cls1.__superclasses__[i], cls2)) {
					return true;
				}
			}
		}
		return false;
	}

});

var Define = (function () {
	var __defined_macros__ = [];
	return (function (name, value) {
		if (arguments.length < 2 || typeof name != 'string') {
			throw new Error('Define error: Usage: Define(\'name\', value);');
		}
		for (var i = 0; i < __defined_macros__.length; i++) {
			if (__defined_macros__[i] == name) {
				return;
			}
		}
		if (typeof value == 'string') {
			eval(name + ' = "' + value + '";');
		} else {
			if (typeof value == 'number' || typeof value == 'boolean') {
				eval(name + ' = ' + value + ';');
			} else {
				eval(name + ' = value ;');
			}
		}
		__defined_macros__.push(name);
	});
})();
