/*jslint browser: true*/
/*global $, WebSocket*/
(function () {

    "use strict";

    /**
     * Limits frequency of calling function with no args
     * @param fn
     * @param interval
     * @returns {Function}
     */
    function limitFrequency(fn, interval) {
        var lastCallTime = 0;
        return function () {
            if (new Date() - lastCallTime < interval) {
                return;
            }
            lastCallTime = new Date().getTime();
            fn.call();
        };
    }

    function UserActivity(options) {
        this.options = $.extend({
            noSocketLogData: '',
            host: '',
            sessionId: '',
            activityCallFrequency: 10000,
            watchMouseMove: false
        }, options);

        if (!this.isValid()) {
            this.createSocket();
            this.listenSocket();
        }

        this.flash = this.flash.bind(this);
        this.flash = limitFrequency(this.flash, this.options.activityCallFrequency);
    }

    UserActivity.SESSION_PREFIX = '+';
    UserActivity.FLASH_MESSAGE = '*';
    UserActivity.ALIVE_REQUEST = '?';
    UserActivity.ALIVE_RESPONSE = '!';

    UserActivity.prototype = {
        createSocket: function () {
            if (!window.WebSocket) {
                this.noWebSocket();
                return;
            }

            try {
                this.socket = new WebSocket('ws://' + this.options.host);
            } catch (e) {}
        },
        isValid: function () {
            if (!this.options.sessionId) {
                throw new Error('Session identifier for tracking user activity has not been specified!');
            }
            if (!this.options.host) {
                throw new Error('Host for user activity has not been specified!');
            }
        },
        noWebSocket: function () {
            if (!this.options.noSocketLogData) {
                return;
            }
            window.$logger.log(this.options.noSocketLogData);
        },
        assertSocket: function () {
            if (!this.socket) {
                throw new Error('Socket has not been created yet.');
            }
        },
        connect: function () {
            this.assertSocket();
            this.socket.send(UserActivity.SESSION_PREFIX + this.options.sessionId);

            if (this.options.watchMouseMove) {
                $(document).on('mousemove', this.flash);
            }
        },
        listenSocket: function () {
            this.assertSocket();
            this.socket.onopen = this.connect.bind(this);
            this.socket.onmessage = this.receive.bind(this);
        },
        flash: function () {
            this.assertSocket();
            this.socket.send(UserActivity.FLASH_MESSAGE);
        },
        receive: function (message) {
            if (message.data === UserActivity.ALIVE_REQUEST) {
                this.socket.send(UserActivity.ALIVE_RESPONSE);
            }
        }
    };

    window.UserActivity = UserActivity;
}());
