Source: MobileAnalyticsSessionManager.js

var AMA = global.AMA;
AMA.Storage = require('./StorageClients/LocalStorage.js');
AMA.StorageKeys = require('./StorageClients/StorageKeys.js');
AMA.Session = require('./MobileAnalyticsSession.js');
AMA.Client = require('./MobileAnalyticsClient.js');

/**
 * @typedef AMA.Manager.Options
 * @augments AMA.Client.Options
 * @property {AMA.Session.ExpirationCallback} [expirationCallback=] - Callback function to call when sessions expire
 */

/**
 * @name AMA.Manager
 * @namespace AMA.Manager
 * @constructor
 * @param {AMA.Client.Options|AMA.Client} options - A configuration map for the AMA.Client or an instantiated AMA.Client
 * @see AMA.Client
 */
AMA.Manager = (function () {
    'use strict';
    /**
     * @lends AMA.Manager
     */
    var Manager = function (options) {
        if (options instanceof AMA.Client) {
            this.client = options;
        } else {
            options._autoSubmitEvents = options.autoSubmitEvents;
            options.autoSubmitEvents = false;
            this.client = new AMA.Client(options);
            options.autoSubmitEvents = options._autoSubmitEvents !== false;
            delete options._autoSubmitEvents;
        }
        this.options = this.client.options;
        this.outputs = this.client.outputs;

        this.options.expirationCallback = this.options.expirationCallback || AMA.Util.NOP;
        function checkForStoredSessions(context) {
            context.client.storage.each(function (key) {
                if (key.indexOf(AMA.StorageKeys.SESSION_ID) === 0) {
                    context.outputs.session = new AMA.Session({
                        storage           : context.client.storage,
                        sessionId         : context.client.storage.get(key),
                        sessionLength     : context.options.sessionLength,
                        expirationCallback: function (session) {
                            var shouldExtend = context.options.expirationCallback(session);
                            if (shouldExtend === true || typeof shouldExtend === 'number') {
                                return shouldExtend;
                            }
                            context.stopSession();
                        }
                    });
                    if (new Date().getTime() > context.outputs.session.expirationDate) {
                        context.outputs.session.expireSession();
                        delete context.outputs.session;
                    }
                }
            });
        }

        checkForStoredSessions(this);
        if (!this.outputs.session) {
            this.startSession();
        }
        if (this.options.autoSubmitEvents) {
            this.client.submitEvents();
        }
    };

    /**
     * submitEvents
     * @param {Object} [options=] - options for submitting events
     * @param {Object} [options.clientContext=this.options.clientContext] - clientContext to submit with defaults to
     *                                                                      options.clientContext
     * @returns {Array} Array of batch indices that were submitted
     */
    Manager.prototype.submitEvents = function (options) {
        return this.client.submitEvents(options);
    };

    /**
     * Function to start a session
     * @returns {AMA.Client.Event} The start session event recorded
     */
    Manager.prototype.startSession = function () {
        this.client.logger.log('[Function:(AMA.Manager).startSession]');
        if (this.outputs.session) {
            //Clear Session
            this.outputs.session.clearSession();
        }
        this.outputs.session = new AMA.Session({
            storage: this.client.storage,
            logger: this.client.options.logger,
            sessionLength: this.options.sessionLength,
            expirationCallback: function (session) {
                var shouldExtend = this.options.expirationCallback(session);
                if (shouldExtend === true || typeof shouldExtend === 'number') {
                    return shouldExtend;
                }
                this.stopSession();
            }.bind(this)
        });
        return this.recordEvent('_session.start');
    };

    /**
     * Function to extend the current session.
     * @param {int} [milliseconds=options.sessionLength] - Milliseconds to extend the session by, will default
     *                                                     to another session length
     * @returns {int} The Session expiration (in Milliseconds)
     */
    Manager.prototype.extendSession = function (milliseconds) {
        return this.outputs.session.extendSession(milliseconds || this.options.sessionLength);
    };

    /**
     * Function to stop the current session
     * @returns {AMA.Client.Event} The stop session event recorded
     */
    Manager.prototype.stopSession = function () {
        this.client.logger.log('[Function:(AMA.Manager).stopSession]');
        this.outputs.session.stopSession();
        this.outputs.session.expireSession(AMA.Util.NOP);
        return this.recordEvent('_session.stop');
    };

    /**
     * Function to stop the current session and start a new one
     * @returns {AMA.Session} The new Session Object for the SessionManager
     */
    Manager.prototype.renewSession = function () {
        this.stopSession();
        this.startSession();
        return this.outputs.session;
    };

    /**
     * Function that constructs a Mobile Analytics Event
     * @param {string} eventType - Custom Event Type to be displayed in Console
     * @param {AMA.Client.Attributes} [attributes=] - Map of String attributes
     * @param {AMA.Client.Metrics} [metrics=] - Map of numeric values
     * @returns {AMA.Client.Event}
     */
    Manager.prototype.createEvent = function (eventType, attributes, metrics) {
        return this.client.createEvent(eventType, this.outputs.session, attributes, metrics);
    };

    /**
     * Function to record a custom event
     * @param eventType - Custom event type name
     * @param {AMA.Client.Attributes} [attributes=] - Custom attributes
     * @param {AMA.Client.Metrics} [metrics=] - Custom metrics
     * @returns {AMA.Client.Event} The event that was recorded
     */
    Manager.prototype.recordEvent = function (eventType, attributes, metrics) {
        return this.client.recordEvent(eventType, this.outputs.session, attributes, metrics);
    };

    /**
     * Function to record a monetization event
     * @param {Object} monetizationDetails - Details about Monetization Event
     * @param {string} monetizationDetails.currency - ISO Currency of event
     * @param {string} monetizationDetails.productId - Product Id of monetization event
     * @param {number} monetizationDetails.quantity - Quantity of product in transaction
     * @param {string|number} monetizationDetails.price - Price of product either ISO formatted string, or number
     *                                                    with associated ISO Currency
     * @param {AMA.Client.Attributes} [attributes=] - Custom attributes
     * @param {AMA.Client.Metrics} [metrics=] - Custom metrics
     * @returns {AMA.Client.Event} The event that was recorded
     */
    Manager.prototype.recordMonetizationEvent = function (monetizationDetails, attributes, metrics) {
        return this.client.recordMonetizationEvent(this.outputs.session, monetizationDetails, attributes, metrics);
    };
    return Manager;
}());

module.exports = AMA.Manager;