Source: connection/connection.js

/** @namespace Connection
    @desc      Manages connectivity, holds connection and user criteria, and handles packets.
*/
var Connection = Connection ||
{
    /* properties */
    
        // states & configuration
            
            /** @member  {object} Connection~readyFramework
                @private
                @desc    Synchronizer promise representing Framework readiness.
            */
            'readyFramework': new $.Deferred(),
            
            /** @member  {object} Connection~readyDom
                @private
                @desc    Synchronizer promise representing DOM readiness.
            */
            'readyDom': new $.Deferred(),
            
            /** @member  {object} Connection~readyData
                @private
                @desc    Synchronizer promise representing data readiness.
            */
            'readyData': new $.Deferred(),
            
            /** @member {boolean} Connection.splash
                @desc   Whether WebView "framework_splash_screen" is open.
            */
            'splash': true,
            
            /** @member {object} Connection.starlets
                @desc   Hashlike object of starlet objects.
            */
            'starlets': {},
            
            /** @member {array} Connection.features
                @desc   Array of feature objects from API.
            */
            'features': [],
            
            /** @member {object} Connection.subscriptions
                @desc   Hashlike object of packet subscriptions.
            */
            'subscriptions': {},
            
            /** @member {object} Connection.shortcuts
                @desc   Hashlike object of shortcut mappings.
            */
            'shortcuts': {},
            
            /** @member {object} Connection.cache
                @desc   Hashlike object of cached data.
            */
            'cache': {},
            
            /** @member {boolean} Connection.internet
                @desc   Whether Framework is able to access the internet. Assumed true until proven otherwise.
            */
            'internet': true,
            
            /** @member {boolean} Connection.connected
                @desc   Whether Framework is connected to user server via XMPP.
            */
            'connected': false,
            
            /** @member {boolean} Connection.connectedOnce
                @desc   Whether Framework has connected to user server once since starting.
            */
            'connectedOnce': false,
            
            /** @member {boolean} Connection.unloading
                @desc   Whether Connection's WebView is about to unload.
            */
            'unloading': false,
            
            /** @member {boolean} Connection.reloading
                @desc   Whether Connection's WebView is going to load again after unloading.
            */
            'reloading': false,
            
            /** @member {boolean} Connection.sleeping
                @desc   Whether framework will be or has been in system sleep state.
            */
            'sleeping': false,
            
            /** @member {number} Connection.pingLast
                @desc   Time of last ping packet from XMPP user server (ms timestamp).
            */
            'pingLast': 0,
            
            /** @member {number} Connection.pingInterval
                @desc   Expected interval between incoming user server pings (ms).
            */
            'pingInterval': T_SECOND * 10,
            
            /** @member {number} Connection.pingTolerance
                @desc   Length of time before an incoming user server ping is considered missed (ms).
            */
            'pingTolerance': T_SECOND * 2,
            
            /** @member {number} Connection.pingMisses
                @desc   Number of missed pings before XMPP connection is presumed lost.
            */
            'pingMisses': 10,
            
            /** @member {number} Connection.pingCheck
                @desc   Interval to check time since last user server ping (ms).
            */
            'pingCheck': T_SECOND,
            
            /** @member {number} Connection.pongCheck
                @desc   Interval to wait before checking for a pong from server (ms).
            */
            'pongCheck': T_SECOND * 3,
            
            /** @member {number} Connection.ajaxCheckTimeout
                @desc   Length of time before AJAX internet connectivity check times out (ms).
            */
            'ajaxCheckTimeout': T_SECOND * 5,
            
            /** @member {string} Connection.ajaxCheckUrl
                @desc   URL for AJAX internet connectivity check.
            */
            'ajaxCheckUrl': 'http://getip.star2star.com',
            
                        
            /** @member {boolean} Connection.isOnLinkCallbackSet
                @desc   Whether Connection's WebView is about to unload.
            */
            'isOnLinkCallbackSet': false,
            
        // xmpp credentials
            
            /** @member {string} Connection.username
                @desc   XMPP username credential.
                @see    {@link Connection.password}
                @see    {@link Connection.domain}
                @see    {@link Connection.url}
            */
            'username': null,
            
            /** @member {string} Connection.password
                @desc   XMPP password credential.
                @see    {@link Connection.username}
                @see    {@link Connection.domain}
                @see    {@link Connection.url}
            */
            'password': null,
            
            /** @member {string} Connection.domain
                @desc   XMPP server domain.
                @see    {@link Connection.username}
                @see    {@link Connection.password}
                @see    {@link Connection.url}
            */
            'domain': null,
            
            /** @member {string} Connection.url
                @desc   XMPP server path.
                @see    {@link Connection.username}
                @see    {@link Connection.password}
                @see    {@link Connection.url}
            */
            'url': null,
            
        // user info
            
            /** @member {number} Connection.my_customer
                @desc   User's customer id.
            */
            'my_customer': 0,
            
            /** @member {number} Connection.my_location
                @desc   User's location id.
            */
            'my_location': 0,
            
            /** @member {number} Connection.my_extension
                @desc   User's default extension id.
            */
            'my_extension': 0,
            
            /** @member {string} Connection.my_extension_number
                @desc   User's default extension number.
            */
            'my_extension_number': '',
            
            /** @member {string} Connection.my_email
                @desc   User's email address.
            */
            'my_email': '',
            
            /** @member {number} Connection.my_user_id
                @desc   User's user id.
            */
            'my_user_id': 0,
            
            /** @member {number} Connection.user_id
                @desc   User's user id. (REDUNDANT)
                @see    {@link Connection.my_user_id}
            */
            'user_id': 0,
            
            /** @member {number} Connection.sessionId
                @desc  User's user server session id.
            */
            'sessionId': null,
            
            /** @member {string} Connection.sessionNick
                @desc   User's user server session nick.
            */
            'sessionNick': '',
            
            /** @member {number} Connection.view_all_calls
                @desc   Feature: Whether user can see all calls.
            */
            'view_all_calls': 0,
            
            /** @member {number} Connection.view_all_conferences
                @desc   Feature: Whether user can view all conferences.
            */
            'view_all_conference': 0,
            
            /** @member {number} Connection.view_privacy
                @desc   Feature: Whether user can view other private users.
            */
            'view_privacy': 0,
            
            /** @member {number} Connection.operator_mode
                @desc   Feature: Whether user interacts with calls and extensions as an operator.
            */
            'operator_mode': 1,
            
            /** @member {number} Connection.create_video_sessions
                @desc   Feature: Whether user can create video sessions.
            */
            'create_video_sessions': 1,
            
            /** @member {string} Connection.download_url
                @desc   User's download path (possibly unused).
            */
            'download_url': '',
            
            /** @member {number} Connection.release_notes
                @desc   Whether user has seen running Framework version's release notes.
            */
            'release_notes': 1,
            
            /** @member {number} Connection.show_unavailable
                @desc   Setting: Whether unavailable extensions are shown.
            */
            'show_unavailable': 0,
            
            /** @member   {object}  Connection.overlays
                @desc     Hashlike object of overlay states.
                
                @property {Boolean} shoebox    - Whether shoebox is open.
                @property {Boolean} navigation - Whether navigation is open.
                @property {Boolean} lightbox   - Whether a lightbox is open.
            */
            'overlays': {'shoebox': false, 'navigation': false, 'lightbox': false},
            
            /** @member {array} Connection.lightboxes
                @desc   Array of reserved WebView names to handle as lightboxes.
            */
            'lightboxes': ['help', 'whatsnew', 'feedback'],
            
            /** @member {boolean} Connection.visible
                @desc   State: Whether any Framework windows are visible to the user.
            */
            'visible': false,
            
            /** @member {boolean} Connection.focused
                @desc   State: Whether any Framework windows are focused.
            */
            'focused': true,
            
            /** @member {boolean} Connection.minimized
                @desc   State: Whether any Framework windows are minimized.
            */
            'minimized': false,
            
            /** @member {boolean} Connection.hidden
                @desc   State: Whether any Framework windows are hidden.
            */
            'hidden': false,
            
            /** @member {boolean} Connection.mouse
                @desc   State: Whether any Framework windows contain mouse pointer.
            */
            'mouse': false,
            
            /** @member {number} Connection.notificationsDismissed
                @desc   Last time a notification was dismissed (ms timestamp).
            */
            'notificationsDismissed': 0,
            
    /* callbacks */
        
        /**
            @member  {callbackProv} Connection~onReadyFramework
            @private
            @desc    Fires when framework signals readiness.
        */
        'onReadyFramework': function (provData)
        {
            log(L_MAIN, 'Connection.onReadyFramework', provData);
            
            // init
            
            var $document = $(document);
            
            this.provData = provData;
            
            // server overrides
            
            this.provData.xmpp.server = PRODUCTION
                ? '199.15.180.135'
                : 'xmpp.lb.star2star.net';
            
            this.provData.xmpp.port   = PRODUCTION
                ? '5280'
                : '80';
            
            // save server info
            
            this.username             = this.provData.xmpp.username;
            this.password             = this.provData.xmpp.password;
            this.domain               = this.provData.xmpp.domain;
            this.url                  = 'http://{0}:{1}/{2}'.format
                                      (
                                          this.provData.xmpp.server,
                                          this.provData.xmpp.port,
                                          this.provData.xmpp.path
                                      );
            
            // save user info
            
            this.my_customer          = this.provData.customers[0].id;
            this.my_email             = this.provData.userName;
            this.my_user_id           = this.provData.xmpp.userId;
            this.user_id              = this.provData.xmpp.userId;
            
            // browser object
            
            if (ISORION)
            {
                Browser.platform = OrionFramework.platform;
                Browser.version  = OrionFramework.version;
                Browser.apiUrl   = OrionFramework.apiURL;
                
            }
            
            // bind callbacks
            
            OrionUpload.setProgressCallback  ('', linkCallback(function (e) { $document.triggerHandler('uploadprogress'  , [e.uploads]);   }, window, true));
            OrionUpload.setFinishCallback    ('', linkCallback(function (e) { $document.triggerHandler('uploadfinish'    , [e]);           }, window, true));
            OrionUpload.setErrorCallback     ('', linkCallback(function (e) { $document.triggerHandler('uploaderror'     , [e]);           }, window, true));
            OrionUpload.setResponseCallback  ('', linkCallback(function (e) { $document.triggerHandler('uploadresponse'  , [e]);           }, window, true));
            
            OrionDownload.setProgressCallback('', linkCallback(function (e) { $document.triggerHandler('downloadprogress', [e.downloads]); }, window, true));
            OrionDownload.setFinishCallback  ('', linkCallback(function (e) { $document.triggerHandler('downloadfinish'  , [e]);           }, window, true));
            OrionDownload.setErrorCallback   ('', linkCallback(function (e) { $document.triggerHandler('downloaderror'   , [e]);           }, window, true));
            OrionDownload.setResponseCallback('', linkCallback(function (e) { $document.triggerHandler('downloadresponse', [e]);           }, window, true));
            
            //OrionConnection.setLinkCallback('Distributor', 'onLink');
            //OrionConnection.setAnimationStepCallback('Connection', 'onAnimationStep');
            
            OrionSystem.setSleepCallback('', linkCallback(function (e) {  Connection.sleeping = true;  Connection.onDisconnect(); }, window, true));
            OrionSystem.setWakeCallback ('', linkCallback(function (e) {  Connection.sleeping = false; Connection.checkAjax();    }, window, true));
            
            
            // signal
            
            Connection.readyFramework.resolve();
        },
        'onFinishedLoading': function() {
            //console.log('=========== Finished Loading ===========');
            
            //console.log('=========== Link callback set Loading ===========', Connection.isOnLinkCallbackSet, !Connection.isOnLinkCallbackSet);
            
            !Connection.isOnLinkCallbackSet && OrionConnection.setLinkCallback('Distributor', 'onLink');
            Connection.isOnLinkCallbackSet = true;
            //console.log('=========== Link callback set Loading ===========', Connection.isOnLinkCallbackSet, !Connection.isOnLinkCallbackSet);
          
        },
        /** @member  {callbackGeneric} Connection~onReadyDom
            @private
            @desc    Fires when DOM signals readiness.
        */
        'onReadyDom': function ()
        {
            log(L_MAIN, 'Connection.onReadyDom');
            
            // bind events
            
            $(window).on('beforeunload', Connection.onBeforeUnload);
            
            
            // signal
            
            this.readyDom.resolve();
        },
        
        /**
            @member {callbackGeneric} Connection~onReadyAPI
            @private
            @desc Fires when API is ready to query.
        */
        'onReadyAPI': function ()
        {
            log(L_MAIN, 'Connection.onReadyAPI');
            
            $.when
            (
                Bus.ask('users'  , {'action': 'detail', 'id': this.provData.xmpp.userId})
                //Bus.ask('options', {'action': 'list'  , 'category': '_global', 'filter': '^defaultExtensionID$'})
            )
            .then(this.onReadyData.context(this));
        },
        
        /** @member  {callbackGeneric} Connection~onReadyData
            @private
            @desc    Fires after basic user data is retrieved.
        */
        'onReadyData': function (usersPacket, defaultsPacket)
        {
            log(L_MAIN, 'Connection.onReadyData');
            
            // save user detail
            
            this.user = usersPacket.data[0];
            
            // generate nick
            
            var uName = this.user.firstName+' '+this.user.lastName;
            
            if (uName.trim().length === 0) {
                uName = this.user.email;
            }
            
            this.sessionNick = '{0}_{1}_{2}'.format
            (
                this.user_id,
                this.username.substring(String(this.user_id).length),
                uName
                //'{0} {1}'.format
                //(
                //    this.user.firstName,
                //    this.user.lastName
                //)
            );
            
            if (PRODUCTION)
            {
                var pd = Connection.provData;
                
                if (pd.customers.length > 1) // multiple customers?
                {
                    Bus.ask('options',
                    {
                        'action'  : 'list',
                        'category': 'framework',
                        'filter'  : 'multiplecustomer'
                    })
                    .then(function (packet)
                    {
                        if (packet.data.length && packet.data[0].value == '1') { return; } // already flagged
                        
                        // create zendesk ticket
                        
                        var message =
                            [
                                'Orion Framework has identified more than one customer for this user.',
                                'The system is using customer: {0}, other customers include:'
                            ];
                        
                        pd.customers.map(function (customer, index)
                        {
                            index && message.push('{{0}}{1}'.format
                            (
                                index,
                                index + 1 < pd.customers.length ? ',' : '.'
                            ));
                        });
                        
                        message.push('It is requested that support take the appropriate action to eliminate users expanding into multiple customers.');
                        
                        message = ''.format.apply(message.join(' '), pd.customers.pluck('id'));
                        
                        Bus.ask('feedback',
                        {
                            'action'    : 'list',
                            'tickettype': 'problem',
                            'message'   : message,
                            'log'       : false
                        })
                        .then(function (packet)
                        {
                            Bus.ask('options',
                            {
                                'action'  : 'set',
                                'category': 'framework',
                                'key'     : 'multiplecustomer',
                                'value'   : 1
                            })
                            .then(function (packet) { log(L_INFO, 'Multiple Customers Identified', 'support ticket has been opened'); });
                        });
                    });
                }
                else // single customer
                {
                    Bus.ask('options',
                    {
                        'action'  : 'list',
                        'category': 'framework',
                        'filter'  : 'multiplecustomer'
                    })
                    .then(function (packet)
                    {
                        if (packet.data.length > 0) // flag set?
                        {
                            // reset flag
                            
                            Bus.ask('options',
                            {
                                'action'  : 'set',
                                'category': 'framework',
                                'key'     : 'multiplecustomer'
                                // no value == delete
                            })
                            .then(function (packet) { log(L_INFO, 'Removing multiple customer setting' ); });
                        }
                    });
                }
            }
            
            // cache locations/extensions, even if empty
                                                                
            var myexts = this.provData.extensions
                ? this.provData.extensions.filter(function (item) {
                        //(item.frameworkHide || item.framework_hide) && console.log('hiding myext: ', item);
                        return !(item.frameworkHide || item.framework_hide); })
                : [];
            
            touch(this.cache, 'locationsByUser' , {})[this.user_id] = dataArrayToObject(this.provData.locations, 'id');
            touch(this.cache, 'extensionsByUser', {})[this.user_id] = dataArrayToObject(myexts, 'id');
            
            Bus.ask('extensiondefault', {'action': 'get'}).then(function (defaultsPacket)
            {
                // signal
                
                Connection.readyData.resolve();
            });
        },
        
        /** @member  {callbackGeneric} Connection~onRun
            @private
            @desc    Fires when Connection is ready to initiate user server XMPP connection.
        */
        'onRun': function ()
        {
            log(L_MAIN, 'Connection.onRun');
            
            XMPP.connect(this.username, this.password, this.domain, this.url);
            

        },
        
        /** @member  {callbackGeneric} Connection~onConnect
            @private
            @desc    Fires after user server XMPP connection is established.
        */
        'onConnect': function ()
        {
            if (!Connection.connected)
            {
                log(L_MAIN, 'Connection.onConnect');
                
                // signal
                
                this.connected = true;
                
                // monitor
                
                this.checkAjax.stop && this.checkAjax.stop();
                this.checkPing();
                
                var _self = this;
                
                //raygun stuff
                Raygun &&  Raygun.setUser(Connection.my_email);
                !Raygun && console.log('hmmmm raygun not found WTF');
 
                
                sdkjs.init(Browser.apiUrl, Connection.username, Connection.password);
                sdkjs.updateApiServerUrl({'id': Connection.my_user_id}).then(function ()
                {
                    // scenario-specific:
                    
                    if (!_self.connectedOnce) // first connect
                    {
                        _self.connectedOnce = true;
                        
                        log(L_DEBUG, 'Connection.onConnect', 'requesting remote starlets/features...');
                        
                        API.send('getStarlets', {'action': 'list', 'platform': Browser.platform, 'version': Browser.version});
                        Bus.ask('all', {'subscribe': true, 'callback': function () {}});
                    }
                    else // reconnect
                    {
                        $.each(Distributor.packets.xmppSubscribed, function (index, packetName)
                        {
                            log(L_DEBUG, 'Connection.onConnect', 're-subscribing to xmpp packet "{0}"'.format(packetName));
                            
                            XMPP.send($pres(
                            {
                                'name'    : packetName,
                                'category': 'update',
                                'type'    : 'subscribe_packet'
                            }));
                        });
                        
                        Connection.publish('connectivity', 'update', {'xmpp': true}, 'connection');
                    }
                        //OrionSystem.showDevTools();                    
                        var iLoading = setInterval(function(){
                                    
                                    //console.log('checking if loaded:', iTimes, sdkjs.queueRunning);
                                    iTimes++;
                                    if (sdkjs && sdkjs.queue.length === 0 && sdkjs.queueRunning === 0 && iTimes > 17) {
                                               clearInterval(iLoading);
                                               Connection.onFinishedLoading();
                                    }
                                    if (sdkjs.queueRunning > 0) {
                                                iTimes =0;
                                    }
                        }, 210), iTimes = 0;
                });
            }
            else
            {
                        log(L_ERROR, 'Connection.onConnect', 'already connected!');
                        Connection.checkAjax();
            }
        },
        
        /** @member  {callbackGeneric} Connection~onDisconnect
            @private
            @desc    Fires after user server XMPP connection is terminated.
        */
        'onDisconnect': function ()
        {
            if (Connection.connected)
            {
                log(L_MAIN, 'Connection.onDisconnect');
                
                // signal
                
                this.connected = false;
                Connection.publish('connectivity', 'update', {'xmpp': false}, 'connection');
                
                // reset requests
                
                //console.log('queue', sdkjs.queue);
                
                $.each(sdkjs.queue, function ()
                {
                        // jes wrapping in try catch since meta is empty 
                        try {
                            //console.log('rejecting', this);
                            this.deferred.rejectWith(this.promise, [[], this.promise.metas[0], '', 'error', 'abort']);
                        } catch(e) {
                            log(L_ERROR, 'Connection.onDisconnect', 'error on rejecting promises', e);
                        }
                    
                });
                
                sdkjs.queue        = [];
                sdkjs.queueRunning = 0;
                
                //console.log('requests', sdkjs.requests);
                
                for (var hash in sdkjs.requests)
                {
                    //console.log('aborting', sdkjs.requests[hash]);
                     sdkjs.requests[hash].jqXHR && sdkjs.requests[hash].jqXHR.abort();
                }
                
                // reset cache
                
                this.cache = {};
                
                // shutdown xmpp
                
                XMPP.disconnect();
                
               !(Connection.unloading || Connection.sleeping) && Connection.checkAjax();
                
            }
            else
            {
                log(L_ERROR, 'Connection.onDisconnect', 'already disconnected! calling checkAjax()');
                Connection.checkAjax();                        
            }
        },
        
        /** @member  {callbackGeneric} Connection~onBeforeUnload
            @private
            @desc    Fires before Connection's WebView is unloaded.
        */
        'onBeforeUnload': function ()
        {
            Connection.unloading = true;
            
            if (!Connection.reloading)
            {
                Connection.onBeforeExit();
                Connection.publish('connectivity', 'update', {'exiting': true}, 'connection');
            }
            
            XMPP && XMPP.connection && XMPP.connection.disconnect();
        },
        
        /** @member  {callbackGeneric} Connection~onBeforeExit
            @private
            @desc    Fires before Framework exits.
        */
        'onBeforeExit': function ()
        {
            
        },
        
        /** @member  {callbackGeneric} Connection~onPng
            @private
            @desc    Fires when user server XMPP ping is received.
        */
        'onPong': function () {
            //console.log('PONG');
            Connection.pingLast = (new Date()).getTime();
            Connection.pingInterval = T_SECOND * 10;
            
         },
        
        // 'onAnimationStep': function (e)
        // {
        //     log(L_DEBUG, 'Connection.onAnimationStep');
            
        //     amplify.publish('animation_step', {'x': e.x, 'y': e.y});
        // },
        
    /* methods */
        
        /**
            @method  Connection.reply
            @desc    Reply to specific starlet with data and/or message.
            
            @arg     {object}  packet - DataPacket object.
            @returns {boolean} Success or failure (of data processing, not Starlet's receipt of packet).
        */
        'reply': function ()
        {
            log(L_DEBUG, 'Connection.reply', arguments);
            
            // init
            
            var metas, data;
            
            switch (arguments.length)
            {
                case 1: // standardized packet
                    
                    var packet = arguments[0];
                    
                    if (!packet.isPacket) { log(L_ERROR, 'Connection.reply', 'invalid packet'); return false; }
                    
                    metas = packet.metas;
                    data  = packet;
                    break;
                    
                case 2: // legacy
                    
                    metas = arguments[0];
                    data  = arguments[1];
                    break;
                    
                default:
                    
                    log(L_ERROR, 'Connection.reply', 'invalid number of arguments');
                    return false;
            }
            
            // coerce to array, cleanup
            
            metas = dltypeof(metas) === 'array' ? metas : [metas];
            delete packet.metas;
            
            // send
            
            $.each(metas, function (index, meta)
            {
                // validate
                
                if ( meta.tell    ) {                                                             return true; }
                if (!meta.callback) { log(L_ERROR, 'Connection.reply', 'missing callback', meta); return true; }
                
                packet.meta = meta;
                
                //packet.meta.packet == 'activity' && console.log('********', data, meta, JSON.stringify(data), JSON.parse(JSON.stringify(data)));
                
                ISORION ?
                (
                    typeof meta.namespace === 'string'
                        ? Bus.tell(meta.starlet, meta.namespace, meta.callback, data)
                        : Bus.tell(meta.starlet, ''            , meta.callback, data)
                ):(
                    typeof meta.namespace === 'string'
                        ? window[meta.namespace][meta.callback](JSON.stringify(data))
                        : window                [meta.callback](JSON.stringify(data))
                );
            });
            
            return true;
        },
        
        /** @method Connection.publish
            @desc   Publish data and/or message to all starlets subscribing to a specific packet name.
            
            @arg    {object}       packet    - DataPacket object.
            @arg    {string}       action    - REST-like intention for recipient interface.
            @arg    {array|object} data      - Single or multiple data rows for display or processing.
            @arg    {string}       source    - Single or multiple informational objects to allow communication with
                                               recipient in non REST-like ways.
            @arg    {array|object} [message] - Single or multiple sets of recipient header information.
        */
        'publish': function (packet, action, data, source, message)
        {
            $(document).triggerHandler(packet, [action, data, source, message]);
        },
        
        /** @method  Connection.checkPing
            @private
            @desc    Initiate XMPP user server ping checking. Mutually exclusive of {@link Connection.checkAjax}.
        */
        'checkPing': function ()
        {
            if (Connection.connected)
            {
                var self = arguments.callee;
                
                
                self.send = self.send || function() {
                     XMPP.send($pres({'type': 'ping'}));
                     //console.log('sent ping -- waiting for (ms):  ', Connection.pongCheck, ' to check for pong');
                     setTimeout(self.checkPong.context(self), Connection.pongCheck  );
                };
                
                self.checkPong = self.checkPong || function() {
                    //Connection.pingInterval = 1;
                    
     
                    var now       = (new Date()).getTime(),
                        since     = now - Connection.pingLast,
                        tolerated = ((Connection.pingCheck * Connection.pingMisses) + Connection.pingTolerance) / 2,  //1*10 sec + 2 sec / 2
                        nextSend   = Connection.pingInterval - since, // default value for next send 
                        timeout   = T_SECOND * 10 * 4 + T_SECOND *5;  //1*10* 2  + 2 
                    
                    //log(L_DEBUG, 'Connection.checkPing.check', 'last ping {0}ms ago'.format(since));
                    //console.log('checking for pong: (since, tolerated, timeout, nextSend)', since, tolerated, timeout, nextSend);
                    if (since > timeout) // missed too many pings?
                    {
                        log(L_WARN, 'Connection.checkPing.check', 'timeout after {0}ms'.format(since));
                        XMPP.connection === null ? Connection.checkAjax() : XMPP.disconnect();
                    }
                    else // been longer than expected?
                    {
                        if (since > tolerated ) {
                           Connection.pingInterval = Connection.pingCheck * 3; // now check every  3 second
                        } else {
                           Connection.pingInterval = Connection.pingCheck * Connection.pingMisses;
                        }
                        nextSend   = Connection.pingInterval - since;
                    }
                    //console.log('checkPong, since: '+since+' interval: '+Connection.pingInterval + ' waiting to send: '+ nextSend);
                    
                    // only call send again if we are connected 
                    Connection.connected &&  setTimeout(self.send.context(self), nextSend);
                };

                
                self.send();
            }
            else
            {
                log(L_ERROR, 'Connection.checkPing', 'but we\'re not connected!');
                self.stop && self.stop();
            }
        },
        
        /** @method  Connection.checkAjax
            @private
            @desc    Initiate internet connectivity checking. Mutually exclusive of {@link Connection.checkPing}.
        */
        'checkAjax': function ()
        {
            var self = arguments.callee, iRotation = 0;
            //console.log('check AJAX Intitial');
            
            if (!Connection.connected)
            {
                self.start = self.start || function ()
                {
                    log(L_FUNC, 'Connection.checkAjax.start');
                    //console.log('Connection.checkAjax.start');
                    self.stop();
                    //self.interval = setInterval(self.check.context(self), Connection.pingCheck);
                    self.interval = setTimeout(self.check.context(self), Connection.pingCheck);
                    //self.throttleCount = 0;
                    //self.check();
                };
                
                self.stop = self.stop || function () {
                        if (self.interval)
                        {
                            log(L_FUNC, 'Connection.checkAjax.stop');
                            //console.log('Connection.checkAjax.stop');
                            //clearInterval(self.interval);
                            clearTimeout(self.interval);
                            delete self.interval;
                            //self.interval = null;
                            self.request && self.request.abort();
                            //self.throttleCount = 0;
                        }
                 };
                
                self.check = self.check || function ()
                {
                    //log(L_DEBUG, 'Connection.checkAjax.check');
                    //console.log('Connection.checkAjax.check');
                    self.request && self.request.abort();
                    //console.log('-----', this);
                    self.request = $.ajax(
                    {
                        'url'    : Connection.ajaxCheckUrl,
                        'timeout': Connection.ajaxCheckTimeout,
                        'cache'  : false,
                        'success': function ()
                        {
                            log(L_INFO, 'Connection.checkAjax.check', 'success');
                            //console.log('-----aaaa', this);
                            
                            // jes if guest restart manually
                            Connection.user.guest && OrionConnection.closeFramework(true, false);
                            
                            // jes postpone to later 
                            
                            self.stop();
                            
                            //Connection.internet = true;
                            
                            // jes check password here
                            
                            Bus.ask('authenticate',
                            {
                                'action':'get',
                                'username': Connection.provData.userName,
                                'userpassword': Connection.provData.hash_key,
                                'notnow' : true,
                                'version_number': OrionFramework.version,
                                'device_id': String(CryptoJS.SHA1(OrionFramework.deviceID)),
                                'application_key': Connection.provData.applicationKey
                            })
                            .then(function (data)
                            {
                                log(L_WARN, 'Connection.checkAjax. authenticate call', 'returned "{0}"'.format(JSON.stringify(data)));
                                //console.log(data);
                                //alert( JSON.stringify(data) );
                                if (data.action === 'delete')
                                {
                                    var API_AUTHENTICATE_URL = '/' + API.versionURL + '/client/' + OrionFramework.platform + '/authenticate';
                                    
                                    // we cannot use our xmpp creds we have
                                    //OrionConnection.setStarletAPIKey(null,null);
                                    
                                    OrionAPI.getFrameworkURL('', linkCallback(function (url)
                                    {
                                        url = OrionFramework.apiURL + url;
                                        
                                        $.get(url, function (data, status)
                                        {
                                            //console.log(data, status);
                                                
                                            //alert(JSON.stringify(data)+ " status:" + status);
                                            
                                            if (!data || (status == 401 || data.code == 401|| data.displayPasswordChange === 1))
                                            {
                                                OrionConnection.closeFramework(true, false);
                                            } 
                                            else if
                                            (
                                                (
                                                    data.frameworkUpdateStatus
                                                        && !OrionFramework.managedInstall
                                                        && data.frameworkUpdateStatus.targetVersion
                                                        && data.frameworkUpdateStatus.forced
                                                )
                                                || (data.frameworkUpdateStatus.status == 'failure')
                                            ){
                                                // update so we will restart which will kick us through the update process ... easiest at this point 
                                                OrionConnection.closeFramework(true, true);
                                            }
                                            
                                            // jes postponed to here 
                                            
                                            //self.stop();
                                            
                                            Connection.internet = true;
                                            Connection.username = data.xmpp.username;
                                            Connection.password = data.xmpp.password;
                                            
                                            OrionConnection.setStarletAPIKey(Connection.username, Connection.password);
                                            
                                            setTimeout(function ()
                                            {
                                                self.throttleCount = 0;
                                                
                                                XMPP.connect(Connection.username, Connection.password, Connection.domain, Connection.url);
                                                
                                                Bus.ask('starlets', {'action': 'active'}).then(function (starletPacket)
                                                {
                                                    var activeName = starletPacket.data[0].name.toLowerCase();
                                                    OrionConnection.focusStarlet(activeName, true);
                                                });
                                            },
                                            200);
                                            
                                            //XMPP.connect(Connection.username, Connection.password, Connection.domain, Connection.url);
                                        })
                                        .fail(function ()
                                        {
                                             OrionConnection.closeFramework(true, false);
                                        });
                                    }),
                                    API_AUTHENTICATE_URL,
                                    {
                                        'username'       : Connection.provData.userName,
                                        'userpassword'   : Connection.provData.hash_key,
                                        'version_number' : OrionFramework.version,
                                        'notnow'         : true,
                                        'device_id'      : String(CryptoJS.SHA1(OrionFramework.deviceID)),
                                        'application_key': Connection.provData.applicationKey
                                    });
                                }
                                else
                                {
                                    //console.log('Connection: 971 data:', data );
                                    if (data && !data.data[0]) {
                                                Connection.internet = false;
                                                    
                                                self.start();
                                    } else {
                                                if (data.data[0].password_state === 'expired' || data.data[0].password_state === 'reset')
                                                {
                                                     OrionConnection.closeFramework(true, false);
                                                }
                                                else if (data.data[0].code && (data.data[0].code == '555'))
                                                {
                                                    // throttling so just close andrestart 
                                                    // OrionConnection.closeFramework(true, false);
                                                    
                                                    log(L_WARN, 'Connection.checkAjax.check', 'throttling 555 "{0} "'.format(data.data[0].description), self.throttleCount);
                                                    
                                                    self.throttleCount++
                                                        && self.throttleCount > 120
                                                        && OrionConnection.closeFramework(true, false);
                                                    
                                                    Connection.internet = false;
                                                    
                                                    self.start();
                                                }
                                                else if
                                                (
                                                    (
                                                        data.data[0].frameworkUpdateStatus
                                                            && !OrionFramework.managedInstall
                                                            && data.data[0].frameworkUpdateStatus.targetVersion
                                                            && data.data[0].frameworkUpdateStatus.forced
                                                    )
                                                    || (data.data[0].frameworkUpdateStatus && (data.data[0].frameworkUpdateStatus.status == 'failure'))
                                                ){
                                                    // update so we will restart which will kick us through the update process ... easiest at this point 
                                                    OrionConnection.closeFramework(true, true);
                                                }
                                                else
                                                {
                                                    // jes postponed to here
                                                    
                                                    log(L_WARN, 'Connection.checkAjax.check:  all successful so will reconnect via xmpp now ');
                                                    
                                                    //self.stop();
                                                    
                                                    Connection.internet = true;
                                                    Connection.username = data.data[0].xmpp.username;
                                                    Connection.password = data.data[0].xmpp.password;
                                                            
                                                    OrionConnection.setStarletAPIKey(Connection.username, Connection.password);
                                                            
                                                    setTimeout(function ()
                                                    {
                                                        self.throttleCount = 0;
                                                        
                                                        XMPP.connect(Connection.username, Connection.password, Connection.domain, Connection.url);
                                                    },
                                                    200);
                                                }       
                                    }
                                    
                                }
                            });
                        },
                        'error'  : function (xhr, status, message)
                        {
                            log(L_WARN, 'Connection.checkAjax.check', 'error "{0}"'.format(status));
                            Connection.internet = false;
                            //jes 20141016
                            self.start();
                        }
                    });
                };
                
                self.start();
            }
            else
            {
                log(L_WARN, 'Connection.checkAjax', 'but we\'re connected!');
                self.stop && self.stop();
            }
        },
        
        /** @method  Connection.reload
            @private
            @desc    Reload a starlet specified by Framework WebView name.
        */
        'reload': function (nocache)
        {
            Connection.reloading = true;
            
            nocache = typeof nocache === 'undefined' ? true : !!nocache;
            
            OrionConnection.reloadStarlet('connection_starlet', nocache);
        }
};

/* synchronizing */
    
    function on_load(data) { Connection.onReadyFramework(data); }

    $(function () { Connection.onReadyDom(); });

    $.when
    (
        Connection.readyFramework,
        Connection.readyDom
    )
    .then(Connection.onReadyAPI.context(Connection));

    $.when
    (
        Connection.readyFramework,
        Connection.readyDom,
        Connection.readyData
    )
    .then(Connection.onRun.context(Connection));
    
/* misc */
    
    var Browser = typeof Browser !== 'undefined' ? Browser :
    {
        'isOrion' : ISORION,
        'platform': '',
        'version' : '',
        'apiUrl'  : OrionFramework.apiURL
        //'apiUrl'  : 'http://web1-srq.star2star.net:8080'
    };
    
    //OrionSystem.showDevTools();