define('jls/lang/Exception', ['jls/lang/Class', '_AMD'], function (Class, _AMD) {

var Exception;

Exception = Class.create(/** @lends jls.lang.Exception.prototype */
{
    /**
     * @param {String} [message] The detail message.
     * @param {Object} [cause] The cause.
     * @constructs
     * @class Provide the base Exception.
     */
    initialize : function(message, cause, name) {
        /**
         * The detail message
         * 
         * @private
         * @type String
         */
        this._message = message || null;
        /**
         * The cause
         * 
         * @private
         * @type Object
         */
        this._cause = null;
        if (cause) {
            this._cause = Exception.wrap(cause);
        }
        this._name = name || null;
    },
    /**
     * Returns the cause of this exception or null if the cause is nonexistent or unknown. The cause is the exception that caused this
     * exception to get thrown.
     * 
     * @returns {Object} The cause.
     */
    getCause : function() {
        return this._cause;
    },
    /**
     * Returns the detail message string of this exception.
     * 
     * @returns {String} The detail message.
     */
    getMessage : function() {
        return this._message;
    },
    getName : function() {
        return this._name || _AMD.getModuleId(this) || 'Exception';
    },
    /**
     * Returns the stack trace of this exception.
     * 
     * @returns {Array} The stack trace.
     */
    getStackTrace : function() {
        return [];
    },
    /**
     * Prints this exception and its stacktrace.
     * 
     * @param {jls.io.PrintStream} [ps] The print stream to use.
     */
    printStackTrace : function(ps) {
        if (! ps) {
            return;
        }
        var last = null;
        for (var e = this; e != null; e = e.getCause()) {
            if (e == this) {
                ps.println(e.toString());
            } else {
                ps.println('Caused by: ' + e.toString());
            }
            var st = e.getStackTrace();
            var steStr = null;
            for (var i = 0; i < st.length; i++) {
                var ste = st[i]
                steStr = '\tat ' + ste.fileName + ':' + ste.lineNumber;
                if (ste.arguments && (ste.arguments.length > 2)) {
                    steStr += ' called with ' + ste.arguments;
                }
                if (steStr == last) {
                    ps.println('\t... ' + (st.length - i) + ' more');
                    break;
                }
                ps.println(steStr);
            }
            last = steStr;
        }
    },
    /**
     * Returns a short description of this exception.
     * 
     * @returns {String} The detail message.
     */
    toString : function() {
        var msg = this.getMessage();
        if (msg == null) {
            return this.getName();
        } else {
            return this.getName() + ': ' + msg;
        }
    }
});

Object.extend(Exception, /** @lends jls.lang.Exception */
{
    wrap : function(e) {
        if (e instanceof Exception) {
            return e;
        } else {
            return new Exception(e == null ? undefined : e.toString());
        }
    }
});

return Exception;
});
