function DeviceEvents() {
    var
        _this = this,
        items = [],
        loadFails = 0,
        loading = false;

    _this.events = function() {
        $(document).on('keyup', '#events_search_field', $.debounce(500, function () {
            _this.list();
        }));

        $('#events_tab .tab-pane-body').scroll(function() {

            if (loading)
                return;

            var
                $container = $(this),
                $next = $('[data-next]', $container);

            if ( ! $next.length)
                return;

            var
                height = $container.height(),
                visTop = $container.scrollTop(),
                visBottom = visTop + height;

            var hT = $next.position().top,
                hH = $next.outerHeight(),
                wH = $container.height(),
                wS = $container.scrollTop();

            if (hT < 0)
                return;

            if ((hT+hH-wH) > 0)
                return;

            $.ajax({
                type: 'GET',
                url: $next.attr('data-next'),
                data: {
                    search: $('#events_search_field').val()
                },
                beforeSend: function() {
                    loading = true;
                    loader.add( $next );
                },
                success: function(response) {
                    $('#ajax-events').append(response);
                    initComponents( $container );
                },
                complete: function() {
                    loading = false;
                    loader.remove( $next );
                    $next.remove();
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    handlerFail(jqXHR, textStatus, errorThrown);
                }
            });
        });
    };

    _this.init = function() {
        _this.events();
    };

    _this.list = function() {
        var dataType = 'html';

        dd('events.list');

        var $container = $('#ajax-events');

        $.ajax({
            type: 'GET',
            dataType: dataType,
            url: app.urls.events,
            data: {
                search: $('#events_search_field').val()
            },
            beforeSend: function() {
                loader.add( $container );
            },
            success: function(response) {
                dd('events.list.success');

                $container.html(response);

                initComponents( $container );

                loadFails = 0;
            },
            complete: function() {
                loader.remove( $container );
            },
            error: function(jqXHR, textStatus, errorThrown) {
                handlerFail(jqXHR, textStatus, errorThrown);

                loadFails++;

                if ( loadFails >= 5 ) {
                    app.notice.error('Failed to recover alerts.');
                }
                else {
                    _this.list();
                }
            }
        });
    };

    _this.get = function( id ) {
        var _item = items[ id ];

        if ( typeof _item === "EventSys" )
            return null;

        return _item;
    };

    _this.parse = function(all) {
        $.each(all , function( index, data ) {
            _this.add(data, true);
        });
    };

    _this.addMulti = function(all) {
        $.each(all , function( index, data ) {
            _this.add(data);
        });
    };

    _this.add = function(data, fresh) {
        data = data || {};

        if ( typeof data === 'string' ) {
            data = JSON.parse(data);
        }

        if ( ! data ) {
            return;
        }

        if (typeof items[ data.id ] === 'undefined' ) {
            items[ data.id ] = new EventSys(data);
        } else {
            items[ data.id ].update(data);
        }

        if ( fresh ) {
            items[ data.id ].notice();

            items[ data.id ].sound();

            $( items[ data.id ].html() ).prependTo( $("#ajax-events") );

            initComponents( $("#ajax-events") );
        }
    };

    _this.select = function(event_id) {
        dd('events.select');

        if ( ! items[event_id] )
            return;

        $('#ajax-events [data-event-id]').removeClass('active');
        $('#ajax-events [data-event-id="'+event_id+'"]').addClass('active');

        items[event_id].popup();
    };
}
