// Inspired by base2 and Prototype
(function(){
    var initializing = false, fnTest = /xyz/.test(function(){
        xyz;
    }) ? /\b_super\b/ : /.*/;

    // The base Class implementation (does nothing)
    this.Class = function(){
        
        var self = this;

        this.__clone = function (source) {
            if (source == null || typeof(source) != 'object')
                return source;

            try {
                var destination = new source.constructor();
            } catch (e) {

            }

            for (var property in source)
                destination[property] = this.__clone (source[property]);

            return destination;
        };

        this.clone = function () {
            return this.__clone (this);
        };

        var objectType = function (o) {
            if (typeof o === "undefined")
                return "undefined";

            if (typeof o === "boolean")
                return "boolean";

            if (typeof o === "string")
                return "string";

            if (typeof o === "number")
                return "number";

            if (typeof o === "object" && typeof o.length === "number")
                return "array";

            if (typeof o === "object")
                return "object";

            if (typeof o === "function")
                return "function";
        };

        var equalType = function (o1, o2) {
            return (objectType (o1) === objectType (o2));
        };

        var __equal = function  (o1, o2) {
            if (!equalType (o1, o2)) {
                // typen unterschiedlich
                return false;
            } else if (objectType (o1) === "string" || objectType (o1) === "number" || objectType (o1) === "boolean") {
                // string oder number oder boolean
                return (o1 === o2);
            } else if (objectType (o1) === "object" || objectType (o1) === "array") {
                // alle anderen typen
                for (var i in o1) {
                    if (!__equal (o1[i], o2[i])) {
                        return false;
                    }
                }                
                for (var i in o2) {
                    if (!__equal (o2[i], o1[i])) {
                        return false;
                    }
                }
            }
            return true;
        };

        this.equal = function (o1, o2) {
            return __equal (o1, o2);
        };

        this.equals = function (o2) {
            return __equal (this, o2);
        };

        this.attr = function (prop, value, backup) {
            if (arguments.length < 2) {
                return this[prop];
            } else {

                this[prop] = value;

                if (!this.hasOwnProperty ("__" + prop + "__") || backup) {
                    this["__" + prop + "__"] = this.__clone (value);
                }
                
                return this;
            }
        };

        this.__attr__ = function (prop, value) {
            if (arguments.length < 2) {
                return this["__" + prop + "__"]
            } else {
                this["__" + prop + "__"] = this.__clone (value);
                return this;
            }
        };

        this.__attr__clear = function () {
            var re = /^__.*__$/;
            for (var i in this) {
                if (re.test (i) && typeof this[i] !== "function") {
                    delete this[i];
                }
            }
        };

        this.attrChanged = function (prop) {
            return !this.equal (this[prop], this["__" + prop + "__"]);
        };
        
        this.attrChangedNum = function () {
            var _attrChangedNum = 0;
            var re = /^__.*__$/;
            for (var i in this) {
                if (re.test (i) && !this.equal (this[i], this[i.replace(/^__|__$/g, "")])) {
                    _attrChangedNum++;
                }
            }            
            return _attrChangedNum;
        };

    };

    // Create a new Class that inherits from this class
    Class.extend = function(prop) {
        var _super = this.prototype;

        // Instantiate a base class (but only create the instance,
        // don't run the init constructor)
        initializing = true;
        var prototype = new this();
        initializing = false;

        // Copy the properties over onto the new prototype
        for (var name in prop) {
            // Check if we're overwriting an existing function
            prototype[name] = typeof prop[name] == "function" &&
            typeof _super[name] == "function" && fnTest.test(prop[name]) ?
            (function(name, fn){
                return function() {
                    var tmp = this._super;

                    // Add a new ._super() method that is the same method
                    // but on the super-class
                    this._super = _super[name];

                    // The method only need to be bound temporarily, so we
                    // remove it when we're done executing
                    var ret = fn.apply(this, arguments);
                    this._super = tmp;

                    return ret;
                };
            })(name, prop[name]) :
            prop[name];
        }

        // The dummy class constructor
        function Class() {
            // All construction is actually done in the init method
            if ( !initializing && this.init )
                this.init.apply(this, arguments);
        }

        // Populate our constructed prototype object
        Class.prototype = prototype;

        // Enforce the constructor to be what we expect
        Class.constructor = Class;

        // And make this class extendable
        Class.extend = arguments.callee;

        return Class;
    };
})();

