/*
Script: Class.js
        Contains the Class Function, aims to ease the creation of reusable Classes.

License:
        MIT-style license.
*/

/*
Class: Class
        The base class object of the <http://mootools.net> framework.
        Creates a new class, its initialize method will fire upon class instantiation.
        Initialize wont fire on instantiation when you pass *null*.

Arguments:
        properties - the collection of properties that apply to the class.

Example:
        (start code)
        var Cat = new Class({
                initialize: function(name){
                        this.name = name;
                }
        });
        var myCat = new Cat('Micia');
        alert(myCat.name); //alerts 'Micia'
        (end)
*/

var Class = function(properties){
        var klass = function(){
                return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;
        };
        $extend(klass, this);
        klass.prototype = properties;
        klass.constructor = Class;
        return klass;
};

/*
Property: empty
        Returns an empty function
*/

Class.empty = function(){};

Class.prototype = {

        /*
        Property: extend
                Returns the copy of the Class extended with the passed in properties.

        Arguments:
                properties - the properties to add to the base class in this new Class.

        Example:
                (start code)
                var Animal = new Class({
                        initialize: function(age){
                                this.age = age;
                        }
                });
                var Cat = Animal.extend({
                        initialize: function(name, age){
                                this.parent(age); //will call the previous initialize;
                                this.name = name;
                        }
                });
                var myCat = new Cat('Micia', 20);
                alert(myCat.name); //alerts 'Micia'
                alert(myCat.age); //alerts 20
                (end)
        */

        extend: function(properties){
                var proto = new this(null);
                for (var property in properties){
                        var pp = proto[property];
                        proto[property] = Class.Merge(pp, properties[property]);
                }
                return new Class(proto);
        },

        /*
        Property: implement
                Implements the passed in properties to the base Class prototypes, altering the base class, unlike <Class.extend>.

        Arguments:
                properties - the properties to add to the base class.

        Example:
                (start code)
                var Animal = new Class({
                        initialize: function(age){
                                this.age = age;
                        }
                });
                Animal.implement({
                        setName: function(name){
                                this.name = name
                        }
                });
                var myAnimal = new Animal(20);
                myAnimal.setName('Micia');
                alert(myAnimal.name); //alerts 'Micia'
                (end)
        */

        implement: function(){
                for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]);
        }

};

//internal

Class.Merge = function(previous, current){
        if (previous && previous != current){
                var type = $type(current);
                if (type != $type(previous)) return current;
                switch(type){
                        case 'function':
                                var merged = function(){
                                        this.parent = arguments.callee.parent;
                                        return current.apply(this, arguments);
                                };
                                merged.parent = previous;
                                return merged;
                        case 'object': return $merge(previous, current);
                }
        }
        return current;
};
