function Observable(){

    this.observers = [];

}

Observable.prototype = {

    attach_observer: function(observer){

        if (!(observer instanceof Object)) {
            return;
        }
        var attached = false;
        for (var i = 0; i < this.observers.length; i ++) {
            if (this.observers[i] == observer) {
                attached = true;
                break;
            }
        }
        if (!attached) this.observers.push(observer);

    },

    detach_observer: function(observer){

        for (var i = 0; i < this.observers.length; i ++) {
                if (this.observers[i] === observer) {
                    this.observers.splice(i, 1);
                }
            }
    },

    notify: function(event_type){

        for (var i = 0; i < this.observers.length; i ++) {

            if (this.observers[i] instanceof Function) {
                this.observers[i](event_type, this);
            }
            else
                if (this.observers[i].listen instanceof Function) {
                    this.observers[i].listen(event_type, this);
                }
        }

    }

};

var Dispatcher = function(){
    this.objects = [];
    this.requests = [];

    this.register = function(obj){
        this.objects.push(obj);
        //Проверяем, нет ли для этого объекта запросов от уже загруженных объектов
        for (var i = 0; i < this.requests.length; i ++) {
            var required_name = this.requests[i][0];
            var waiting_object = this.requests[i][1];
            if (required_name == obj.name) {
                obj.attach_observer(waiting_object);
                waiting_object.listen('ready', obj);
                this.requests.splice(i, 1);
            }
        }
        //
        if (obj.depends) {
            for (var i = 0; i < obj.depends.length; i ++) {
                var required_name = obj.depends[i];
                var object_is_set = false;
                for (var j = 0; j < this.objects.length; j ++) {
                    if (this.objects[j].name == required_name) {
                        this.objects[j].attach_observer(obj);
                        obj.listen('ready', this.objects[j]);
                        object_is_set = true;
                    }
                }
                if (!object_is_set) {
                    this.requests.push([obj.depends[i], obj]);
                }
            }
        }
    }

}

var Widget = function(data){
    this.data = data || [];
    this.each = function(func){
        if (this.data) {
            for (var i = 0; i < this.data.length; i++) {
                func(this.data[i]);
            }
        }
    }
    this.find = function(attr, value){
        if (this.data) {
            for (var i = 0; i < this.data.length; i++) {
                if (this.data[i][attr] == value) {
                    return this.data[i];
                }
            }
        }
    }
}

Widget.prototype = new Observable();

var dispatcher = new Dispatcher();
