var Class = (function (global) {"use strict";
    
    // Andrea Giammarchi basic JS Class Proposal - Mit Style
    // 295 bytes gzipped via Closure Compiler (simple minification)
    // http://www.3site.eu/ft/js/Class.js
    // http://www.3site.eu/ft/test/
    
    var
        constructor = "constructor",
        prototype = "prototype",
        statics = "statics",
        typeFunction = "function",
        Object = global.Object,
        create = Object.create,
        keys = Object.keys,
        hasOwnProperty = Object[prototype].hasOwnProperty
    ;
    
    function extend(self, other) {
        for (var key = keys(other), i = key.length; i--; self[key[i]] = other[key[i]]);
    }
    
    function Class(parent, definition) {
        var
            dontExtend = !definition,
            Constructor
        ;
        if (dontExtend) {
            definition = typeof parent === typeFunction ? parent() : parent;
        } else if (typeof definition === typeFunction) {
            definition = definition(parent[prototype]);
        }
        Constructor = hasOwnProperty.call(definition, constructor) ? definition[constructor] : function Class() {};
        if (dontExtend) {
            Constructor[prototype] = create(definition);
        } else {
            extend(Constructor, parent);
            extend(Constructor[prototype] = create(parent[prototype]), definition);
        }
        Constructor[prototype][constructor] = Constructor;
        if (hasOwnProperty.call(definition, statics)) {
            extend(Constructor, definition[statics]);
        }
        return Constructor;
    }
    
    // not mandatory, just in case we want have
    // new Class instanceof Class
    Class[prototype] = global.Function[prototype];
    
    return Class;
    
}(this));

/** EXAMPLES **

// basic usage
var Person = new Class({
    getName: function () {
        return this._name;
    },
    setName: function (_name) {
        this._name = _name;
    }
});

var me = new Person;
me.setName("Andrea");
alert(me.getName());
// --------------------------- //

// basic usage + constructor
var Person = new Class({
    constructor: function (_name) {
        this.setName(_name);
    },
    getName: function () {
        return this._name;
    },
    setName: function (_name) {
        this._name = _name;
    }
});

var me = new Person("Andrea");
alert(me.getName());
// --------------------------- //

// basic inheritance
var Employee = new Class(Person, {
    getCompany: function () {
        return this._company;
    },
    setCompany: function (_company) {
        this._company = _company;
    }
});

var me = new Employee;
me.setName("Andrea");
me.setCompany("NOKIA");
alert(me.getName() + " works at " + me.getCompany());
// --------------------------- //

// simplified parent/super access
var Employee = new Class(Person, function (parent) {
    return {
        constructor: function (_name, _company) {
            parent.constructor.call(this, _name);
            this.setCompany(_company);
        },
        getCompany: function () {
            return this._company;
        },
        setCompany: function (_company) {
            this._company = _company;
        }
    };
});

var me = new Employee("Andrea", "NOKIA");
alert(me.getName() + " works at " + me.getCompany());
// --------------------------- //

// simplified private scope
var Hello = new Class(function () {
    function greetings() {
        alert("Hello " + where + "!");
    }
    var
        myProto = {greetings: function () {
            greetings.call(this);
        }},
        where = "there"
    ;
    return myProto;
});

(new Hello).greetings();
// --------------------------- //

// mixins/overwrites
var Whatever = new Class(function () {
    var
        $Person = Person.prototype,
        $Employee = Employee.prototype
    ;
    return {
        constructor: function Whatever() {
            $Employee.constructor.apply(this, arguments);
        },
        getName: $Person.getName,
        setName: function (_name) {
            var oldName = this.getName();
            $Person.setName.call(this, _name);
            return oldName;
        },
        getCompany: $Employee.getCompany,
        setCompany: $Employee.setCompany
    };
});
// --------------------------- //

// statics
var WithStatics = new Class({
    statics: {a:"a", b:"b"}
});
var WithMoreStatics = new Class(WithStatics, {
    statics: {b:"b", c:"c"}
});
// --------------------------- //

// simplified ES5 compatibility
var Cool = new Class(Object.create(null, {
    name: {
        get: function () {
            return this._name;
        },
        set: function (_name) {
            this._name = _name;
            alert("name changed");
        }
    }
}));

var Cool = new Class(function () {
    var parent = Person.prototype;
    return Object.create(parent, {
        name: {
            get: function () {
                // return this.getName();
                return parent.getName.call(this);
            },
            set: function (_name) {
                // this.setName(_name);
		parent.setName.call(this, _name);
                alert("name changed");
            }
        }
    });
});

var me = new Cool;
me.name = "Andrea";
alert(me.name);
// --------------------------- //

**/
