Source: managers/iqueue-manager.js

/**
 * @module managers/iqueue-manager
 * @description This module manages iQueue calls
 * @requires common/view
 */
define([ 

], 

function ()
{

    // ---------------------------------------------------------------
    //
    // PStyles Manager
    //
    // ---------------------------------------------------------------

    var Queue = function ()
    {
        console.log(" * <iqueue>");

        window.tEvent.eventStr.EVENT_IQUEUE_GOT_LOCATIONS     = "EVENT_IQUEUE_GOT_LOCATIONS";
        window.tEvent.eventStr.EVENT_IQUEUE_GOT_WAIT_LIST     = "EVENT_IQUEUE_GOT_WAIT_LIST";
        window.tEvent.eventStr.EVENT_IQUEUE_GOT_APPOINTMENTS  = "EVENT_IQUEUE_GOT_APPOINTMENTS";
        window.tEvent.eventStr.EVENT_IQUEUE_GOT_NOTIFICATIONS = "EVENT_IQUEUE_GOT_NOTIFICATIONS";
        window.tEvent.eventStr.EVENT_IQUEUE_GOT_NEW_NOTIFICATION = "EVENT_IQUEUE_GOT_NEW_NOTIFICATION";

        this.ui = {

        };

        this.def = {
        };

        // core json
        this.jConfig = -1;

        // customer data
        this.customer = -1;

        this.queue = [];
        this.locationsArray = [];
        this.selectedLocation = 0;
        this.sessionGUID = -1;
        this.notifications = [];

        this.init();
    };

    Queue.prototype = {    
       
        // ______________________________________________________________
        //                                                           init
        /**
            * init
            * @description Initializes class
            * @fires assignListeners()
            * @memberOf module:managers/iqueue-manager
            * @instance
        */
        init: function()  { 
            this.assignListeners();            
        },


        // ______________________________________________________________
        //                                                assignListeners
        /** 
        * assignListeners
        * @description Assigns listeners to events used in this class.
        * @listens  EVENT_MODEL_READY
        * @memberOf module:managers/iqueue-manager
        * @instance
        */
        assignListeners: function() {           
            var self = this;

            if (typeof window.oModel === "undefined" || window.oModel.jConfig === -1){
                window.tEvent.addListener("EVENT_MODEL_READY", function(evt, data)
                {
                    // clean up for new page
                    self.onJsonLoaded(window.oModel.jConfig); 
                });                
            } else {
                self.onJsonLoaded(window.oModel.jConfig); 
            }


        },

        // --------------------------------------------------------------
        // HELPERS
        // --------------------------------------------------------------
        
        // ______________________________________________________________
        //                                                     initIqueue
        /** 
        * initIqueue
        * @description Loads customer and locations the begins polling based on configCode
        * @param {Number} locationIndex - [Optional] Location index
        * @fires  getSessionGuid()
        * @fires  cloudConnector.fetchCustomerConfigByConfigCode()
        * @fires  cloudConnector.fetchCustomerLocationsTable()
        * @fires  EVENT_IQUEUE_GOT_LOCATIONS
        * @memberOf module:managers/iqueue-manager
        * @instance
        */
        initIqueue: function(locationIndex) {
            var self = this;

            var configCode = this.jConfig.iqueue.configCode;

            // get unique session guid
            this.sessionGUID = this.getSessionGuid();

            if (typeof configCode === "undefined" || configCode === ""){
                console.warn(" * <iqueue.initIqueue> jConfig.iqueue.configCode is missing");
            }

            // get the details about this customer based on the configCode
            cloudConnector.fetchCustomerConfigByConfigCode(configCode, function(success, data){
                if (!success) {
                    console.error(" ! <iqueue.initIqueue|fetchCustomerConfigByConfigCode> failed.", data);
                    return;
                }

                //make sure we got a customer back for the config code
                if (!data) {
                    //no customer found for that config code
                    console.warn(" * <iqueue.initIqueue|fetchCustomerConfigByConfigCode> configCode: '" + configCode + "' is invalid");
                    return
                }

                //store the customer so we can use it later
                self.customer = data;
                console.log(" * <iqueue.initIqueue|fetchCustomerConfigByConfigCode> customer", data);

                // fetch the locations for this customer
                cloudConnector.fetchCustomerLocationsTable(self.customer.customerID, function(locSuccess, locData){
                    if (!locSuccess) {
                        console.error(" ! <iqueue.initIqueue|fetchCustomerConfigByConfigCode|fetchCustomerLocationsTable> failed.", locData);
                        return;
                    }

                    //save the returned locations locally
                    self.locationsArray = locData;

                    console.log(" * <iqueue.initIqueue|fetchCustomerConfigByConfigCode|fetchCustomerLocationsTable> locations", self.locationsArray);
                    

                    window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_LOCATIONS, self.locationsArray);

                    //select the first location
                    if (typeof locationIndex !== "undefined"){
                        self.selectLocation(locationIndex);
                    } else {
                        self.selectLocation(0);
                    }

                });
            });
        },

        // ______________________________________________________________
        //                                                 getSessionGuid
        /** 
        * getSessionGuid
        * @description Gets unique session guid
        * @returns sessionGuid
        * @memberOf module:managers/iqueue-manager
        * @instance
        */
        getSessionGuid: function() {

            function _p8(s) {
                var p = (Math.random().toString(16) + "000000000").substr(2, 8);
                return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p;
            }
            return _p8() + _p8(true) + _p8(true) + _p8();
        },

        // ______________________________________________________________
        //                                                selectLocation
        /** 
        * selectLocation
        * @description Gets location object and initiates polling
        * @param {Number} locationIndex - Location index
        * @fires  updateWaitlist()
        * @fires  updateAppointmentlist()
        * @fires  pollNotificationsQueue()
        * @memberOf module:managers/iqueue-manager
        * @instance
        */
        selectLocation: function(locationIndex) {

            this.selectedLocation = this.locationsArray[locationIndex];

            console.log(" * <iqueue.selectLocation>", this.selectedLocation.locationDetails.locationName); 

            //start the polling processes
            this.updateWaitlist();
            this.updateAppointmentlist();
            this.pollNotificationsQueue();
        },

        // ______________________________________________________________
        //                                                updateWaitlist
        /** 
        * updateWaitlist
        * @description Gets updated waiting list
        * @fires  EVENT_IQUEUE_GOT_WAIT_LIST
        * @memberOf module:managers/iqueue-manager
        * @instance
        */
        updateWaitlist: function() {
            var self = this;

            //NOTE: please don't poll too often, we don't want to pay for excessive server requests
            let refreshTimeout = this.jConfig.iqueue.waitListDelay * 1000;

            cloudConnector.fetchWaitTime(self.selectedLocation.locationID, function (success, data) {

                if (!success) {

                    console.error(" ! <iqueue.updateWaitlist|fetchWaitTime> Error", data);

                    window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_WAIT_LIST, []);

                    window.setTimeout(function () {
                        updateWaitlist();
                    }, refreshTimeout);

                    return;
                }

                self.queue = data;

                if (self.queue.length === 0) {
                    window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_WAIT_LIST, self.queue);

                    console.log(" ! <iqueue.updateWaitlist|fetchWaitTime>", self.queue);

                    window.setTimeout(function () {
                        self.updateWaitlist();
                    }, refreshTimeout);
                    return;
                }

                const now = new Date().getTime();
                for (let i = 0; i < self.queue.length; i++) {
                    self.queue[i].createDateTime = new Date(self.queue[i].createTime);
                    self.queue[i].waitTime = (now - self.queue[i].createDateTime) / 1000; // seconds                    
                }

                //sort ascending by the create time
                self.queue.sort(function (a, b) {
                    var createTimeA = a.createTime,
                        createTimeB = b.createTime;
                    if (createTimeA < createTimeB) //sort  ascending
                        return -1;
                    if (createTimeA > createTimeB)
                        return 1;
                    return 0 //default return value (no sorting)
                });

                window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_WAIT_LIST, self.queue);
                console.log(" ! <iqueue.updateWaitlist|fetchWaitTime>", self.queue);

                window.setTimeout(function () {
                    self.updateWaitlist();
                }, refreshTimeout);

            });

        },


        // ______________________________________________________________
        //                                          updateAppointmentlist
        /** 
        * updateAppointmentlist
        * @description Update appointment list
        * @fires  EVENT_IQUEUE_GOT_APPOINTMENTS
        * @memberOf module:managers/iqueue-manager
        * @instance
        */
        updateAppointmentlist: function() {

            var self = this;

            //NOTE: please don't poll too often, we don't want to pay for excessive server requests
            let refreshTimeout = this.jConfig.iqueue.appoinmentListDelay * 1000;

            cloudConnector.fetchOpenAppointments(self.selectedLocation.locationID, function (success, data) {

                if (!success) {

                    console.error(" ! <iqueue.updateAppointmentlist|fetchOpenAppointments> error", data);

                    window.setTimeout(function () {
                        self.updateAppointmentlist()
                    }, refreshTimeout);
                    return;
                }

                self.theAppointments = data;

                const now = new Date();

                //filter to just today's appointments
                self.theAppointments = self.theAppointments.filter(function (appointment) {
                    const apptDate = new Date(appointment.appointmentDetails.start);
                    return apptDate.getDate() === now.getDate() && apptDate.getTime() > (now.getTime() - 1000 * 60 * 15)
                })


                if (self.theAppointments.length === 0) {

                    window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_APPOINTMENTS, self.theAppointments);

                    window.setTimeout(function () {
                        self.updateAppointmentlist()
                    }, refreshTimeout);
                    return;
                }

                self.theAppointments.sort(function (a, b) {
                    return a.appointmentDetails.start - b.appointmentDetails.start
                });

                //and show the list of appointments
                let theHTML = '';

                self.theAppointments.forEach(function (appointment, index) {

                    let startTime = new Date(appointment.appointmentDetails.start)
                    let hours = startTime.getHours();
                    let minutes = startTime.getMinutes();
                    let ampm = hours >= 12 ? 'pm' : 'am';
                    hours = hours % 12;
                    hours = hours ? hours : 12; // the hour '0' should be '12'
                    minutes = minutes < 10 ? '0' + minutes : minutes;
                    let strTime = hours + ':' + minutes + ' ' + ampm;

                    self.theAppointments[index]._startTime = strTime;
                });

                window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_APPOINTMENTS, self.theAppointments);

                window.setTimeout(function () {
                    self.updateAppointmentlist()
                }, refreshTimeout);

            });

        },

        // ______________________________________________________________
        //                                         pollNotificationsQueue
        /** 
        * pollNotificationsQueue
        * @description Polls for notifications
        * @fires EVENT_IQUEUE_GOT_NOTIFICATIONS
        * @fires EVENT_IQUEUE_GOT_NEW_NOTIFICATION
        * @memberOf module:managers/iqueue-manager
        * @instance
        */
        pollNotificationsQueue: function() {  

            var self = this;
            var locationId = self.selectedLocation.locationID;

            // NOTE: please don't poll too often, we don't want to pay for excessive server requests
            let refreshTimeout = 20 * 1000;


            var doNotificationPolling = function() {
                cloudConnector.fetchNotifications(locationId, function (success, data) {

                    if (!success) {

                        console.error(" ! <iqueue.pollNotificationsQueue|fetchNotifications> error", data); 
                        window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_NOTIFICATIONS, []);

                        window.setTimeout(() => {
                            doNotificationPolling();
                        }, refreshTimeout);
                        return;
                    }

                    self.notifications = data

                    if (self.notifications.length === 0) {

                        // new Date().toLocaleString()
                        console.log(" ! <iqueue.pollNotificationsQueue|fetchNotifications>", data); 

                        window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_NOTIFICATIONS, self.notifications);

                        window.setTimeout(() => {
                            doNotificationPolling();
                        }, refreshTimeout);
                        return;
                    }

                    // sort the notifications by create time
                    self.notifications.sort(function (a, b) {
                        var createTimeA = a.notificationObject.createTime,
                            createTimeB = b.notificationObject.createTime
                        if (createTimeA < createTimeB) //sort  ascending
                            return -1
                        if (createTimeA > createTimeB)
                            return 1
                        return 0
                    });

                    // NOTE: this code is responsible for keeping the notifications queue clean
                    // DO NOT skip this step, or the notifications queue will grow forever
                    // delete the first notification if it's older than 5 minutes
                    if (self.notifications.length > 0) {
                        const now = new Date().getTime();
                        var maxAge = now - 1000 * 60 * 5;

                        if (self.notifications[0].notificationObject.createTime < maxAge) {

                            // it's old, so delete it from AWS
                            cloudConnector.deleteNotification(self.notifications[0].locationID, self.notifications[0].notificationID);

                            //poll again in 1 second
                            window.setTimeout(function(){
                                doNotificationPolling();
                            }, 1000);
                            return;
                        }
                    }

                    // filter to just the notifications for the display
                    self.notifications = self.notifications.filter(function (notification) {
                        return notification.notificationObject.destination === 'display';
                    });

                    // filter to just the notifications for type nowserving
                    self.notifications = self.notifications.filter(function (notification) {
                        return notification.notificationObject.type === 'nowserving';
                    });

                    if (self.notifications.length === 0) {

                        //none of the notifications were for the display with type nowserving
                        console.log(" ! <iqueue.pollNotificationsQueue|fetchNotifications>", data); 
                        window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_NOTIFICATIONS, self.notifications);

                        window.setTimeout(function(){
                            doNotificationPolling();
                        }, refreshTimeout);
                        return;
                    }

                    // see if there is a notification that has not yet been presented on this display
                    var theNotification = null;
                    for (let i = 0; i < self.notifications.length; i++) {
                        if (self.notifications[i].notificationObject.presentedArray.indexOf(self.sessionGUID) === -1) {
                            //this notification has never been presented on this display
                            theNotification = self.notifications[i];
                            break;
                        }
                    }

                    if (!theNotification) {
                        // we got through the loop above without identifying an undisplayed notification
                        window.setTimeout(function(){
                            doNotificationPolling();
                        }, refreshTimeout);
                        return;
                    }

                    // we have a notification that has not yet been presented on this display
                    console.log(" ! <iqueue.pollNotificationsQueue|fetchNotifications> New notification", theNotification); 
                    window.tEvent.fire(window.tEvent.eventStr.EVENT_IQUEUE_GOT_NEW_NOTIFICATION, theNotification);

                    // check again after timeout
                    window.setTimeout(function(){
                        doNotificationPolling();
                    }, refreshTimeout);

                    // record that this message has been displayed on this screen
                    if (theNotification.notificationObject.presentedArray.indexOf(self.sessionGUID) === -1) {
                        theNotification.notificationObject.presentedArray.push(self.sessionGUID);
                        cloudConnector.updateNotification(theNotification);
                    }



                });
            };

            doNotificationPolling();

            

        },

        // --------------------------------------------------------------
        // EVENTS
        // --------------------------------------------------------------

        // ______________________________________________________________
        //                                                   onJsonLoaded
        /** 
        * onJsonLoaded
        * @description When project JSON is loaded process styles
        * @param {Object} jData - JSON data 
        * @memberOf module:managers/iqueue-manager
        * @instance
        */
        onJsonLoaded: function(jData) {   
            this.jConfig = jData;            
        }



    };

    window.oQueue = new Queue();
        
    return (oQueue);        
   
});