define('jls/lang/Class', null, function() {
    /*
     * Based on Alex Arnell's inheritance implementation.
     * From: Prototype JavaScript framework, version 1.7 (c) 2005-2010 Sam Stephenson
     * For details, see the Prototype web site: http://www.prototypejs.org/
     */

    // Late binding
    var Exception;
    require([ 'jls/lang/Exception' ], function(e) {
        Exception = e;
    });

    var IS_DONTENUM_BUGGY = (function() {
        for ( var p in {
            toString : 1
        }) {
            if (p === 'toString')
                return false;
        }
        return true;
    })();

    function subclass() {
    }
    /**
     * @class Provides Class management.
     * @name jls.lang.Class
     */
    var Class = { /** @lends jls.lang.CharBuffer */
        /**
         * Returns the created class.
         * @param {Object} desc The class description.
         * @returns {Object} The created class.
         */
        create : function() {
            var parent = null, properties = Array.from(arguments);
            if (Object.isFunction(properties[0]))
                parent = properties.shift();

            function klass() {
                this.initialize.apply(this, arguments);
            }

            Object.extend(klass, Class.Methods);
            klass.superclass = parent;
            klass.subclasses = [];

            if (parent) {
                subclass.prototype = parent.prototype;
                klass.prototype = new subclass;
                parent.subclasses.push(klass);
            }

            for ( var i = 0, length = properties.length; i < length; i++)
                klass.addMethods(properties[i]);

            if (!klass.prototype.initialize)
                klass.prototype.initialize = Class.emptyFunction;

            klass.prototype.constructor = klass;
            return klass;
        },
        Methods : {
            addMethods : function(source) {
                var ancestor = this.superclass && this.superclass.prototype, properties = Object.keys(source);

                if (IS_DONTENUM_BUGGY) {
                    if (source.toString != Object.prototype.toString)
                        properties.push("toString");
                    if (source.valueOf != Object.prototype.valueOf)
                        properties.push("valueOf");
                }

                for ( var i = 0, length = properties.length; i < length; i++) {
                    var property = properties[i], value = source[property];
                    if (ancestor && Object.isFunction(value) && value.argumentNames()[0] == "$super") {
                        var method = value;
                        value = (function(m) {
                            return function() {
                                return ancestor[m].apply(this, arguments);
                            };
                        })(property).wrap(method);

                        value.valueOf = method.valueOf.bind(method);
                        value.toString = method.toString.bind(method);
                    }
                    this.prototype[property] = value;
                }

                return this;
            }
        },
        // jls specific
        emptyFunction : function() {
        },
        notAvailableFunction : function() {
            throw new Exception('Function not available');
        },
        abstractMethod : function() {
            throw new Exception('Abstract method');
        }
    };

    return Class;
});