/**
 * Allows bind to DOM-elements any kind of event with or without timeout
 * Usefull for showing errors, suggests, etc
 * 
 * @param node Parent node, needs to localize event
 * @param callbacks Callbacks in special format
 * @return object
 */
var EventBinder = function(node, callbacks) {
    var that  = this;
    
    that._node        = node;
    that._lastTimeout = 0;
    that._callbacks   = callbacks;
    
    /**
     * Binds all events to the specified elements
     */
    that.bind = function() {
        // Walk by all elements
        $.each(
            that._callbacks,
            function(className, callbacksList) {
                var elementBindTo = that._node.find('.' + className);
                
                // And bind all specified types of events
                $.each(
                    callbacksList,
                    function(eventType, callbackOptions) {
                        if(callbackOptions.timeout) {
                            elementBindTo[eventType](that._bindDelay);
                        } else {
                            elementBindTo[eventType](that._bindImmediately);
                        }
                    }
                );
            }
        );
    }
    
    /**
     * Calls a event callback immediately, without any timeout
     * Its possible to return some value after callback
     */
    that._bindImmediately = function(e) {
        var element = $(e.target);
        var currentClass = element.attr('class').split(' ')[0];
        var callback = that._getCallback(currentClass, e.type);
        return callback.call(element, e);
    }
    
    /**
     * Calls event callback with timeout
     * Calls one ONLY ONE time, if many identical events happens in
     * timeout interval
     */
    that._bindDelay = function(e) {
        that._setHandler.call($(e.target), e.type);
    }
    
    that._setHandler = function(eventType) {
        var currentClass = this.attr('class').split(' ')[0];
        var timeout = that._callbacks[currentClass][eventType].timeout;
        that._timeout.call(
            this,
            that._getCallback(currentClass, eventType), timeout
        );
    }
    
    that._timeout = function(handler, timeout) {
        var timeoutClosure = function(currentTimeout, subject) {
            return function() {
                if(that._lastTimeout == currentTimeout) {
                    handler.call(subject);
                }
            }
        }
        
        that._lastTimeout++;
        setTimeout(
            timeoutClosure(that._lastTimeout, this),
            timeout
        )
    }
    
    that._getCallback = function(className, eventType) {
        if(that._callbacks[className]) {
            return that._callbacks[className][eventType].callback;
        } else {
            alert(
                'Error while calling callback: callback "' + key + 
                '" does not exists'
            );
            
            return function() {};
        }
    }
    
    return {
        'bind': that.bind
    };
}
