1 /**
  2  * @fileOverview Exposes a set of API wrappers that will hide the dirty work of
  3  *     constructing Finesse API requests and consuming Finesse events.
  4  *
  5  * @name finesse.containerservices.ContainerServices
  6  * @requires OpenAjax, jQuery 1.5, finesse.utilities.Utilities
  7  */
  8 var finesse = finesse || {};
  9 finesse.containerservices = finesse.containerservices  || {};
 10 /**
 11  * @class
 12  * Provide container level services for gadget developers, exposing container events by
 13  * calling a set of exposed functions. Gadgets can utilize the container dialogs and 
 14  * event handling (add/remove)
 15  */
 16 finesse.containerservices.ContainerServices = (function () {
 17 
 18     var
 19 
 20     /**
 21      * Shortcut reference to the finesse.utilities.Utilities singleton
 22      * This will be set by init()
 23      * @private
 24      */
 25     _util,
 26 
 27     /**
 28      * Shortcut reference to the gadget pubsub Hub instance.
 29      * This will be set by init()
 30      * @private
 31      */
 32     _hub,
 33 
 34     /**
 35      * @private
 36      * Whether the Client Services have been initiated yet.
 37      */
 38     _inited = false,
 39     
 40      /**
 41      * Stores the list of subscription IDs for all subscriptions so that it
 42      * could be retrieve for unsubscriptions.
 43      * @private
 44      */
 45     _subscriptionID = {},
 46     
 47     /**
 48      * @private
 49      * Reference to the gadget's parent container
 50      */
 51     _parent,
 52     
 53     /**
 54      * @private
 55      * Reference to the gadget's parent container
 56      */
 57     _tabVisibleNotifier,
 58     
 59     /**
 60      * @private
 61      * Reference to the gadget's prefs object
 62      */
 63     _prefs,
 64     
 65     /**
 66      * @private
 67      * Reference to the tabId that is associated with the gadget
 68      */
 69     _myTab,
 70     
 71     /**
 72      * @private
 73      * Reference to the visibility of current gadget
 74      */
 75     _visible,
 76     
 77     /**
 78      * Shortcut reference to the Topics class.
 79      * This will be set by init()
 80      * @private
 81      */
 82     _topics,
 83 
 84     /**
 85      * Ensure that ClientServices have been inited.
 86      * @private
 87      */
 88     _isInited = function () {
 89         if (!_inited) {
 90             throw new Error("ContainerServices needs to be inited.");
 91         }
 92     },
 93    /**
 94      * Retrieves a reference to a particular notifierType.
 95      * @param {String} notifierType
 96      *      Specifies the notifier to retrieve (tabVisible: when the parent tab becomes visible)
 97      * @return {Notifier} The notifier object.
 98      */
 99     _getNotifierReference = function (notifierType) {
100         var notifierReference = null;
101         if (notifierType === 'tabVisible') {
102             notifierReference = _tabVisibleNotifier;
103         }  else {
104             throw new Error("_getNotifierReference(): Trying to get unknown notifier(notifierType=" + notifierType + ")");
105         }
106         return notifierReference;
107     },
108     /**
109          * @private
110          * Utility function to make a subscription to a particular topic. Only one
111          * callback function is registered to a particular topic at any time.
112          * @param {String} topic
113          *     The full topic name. The topic name should follow the OpenAjax
114          *     convention using dot notation (ex: finesse.api.User.1000).
115          * @param {Function} callback
116          *     The function that should be invoked with the data when an event
117          *     is delivered to the specific topic.
118          * @returns {Boolean}
119          *     True if the subscription was made successfully and the callback was
120          *     been registered. False if the subscription already exist, the
121          *     callback was not overwritten.
122          */
123         _subscribe = function (topic, callback) {
124             _isInited();
125 
126             //Ensure that the same subscription isn't made twice.
127             if (!_subscriptionID[topic]) {
128                 //Store the subscription ID using the topic name as the key.
129                 _subscriptionID[topic] = _hub.subscribe(topic,
130                     //Invoke the callback just with the data object.
131                     function (topic, data) {
132                         callback(data);
133                     });
134                 return true;
135             }
136             return false;
137         },
138 
139         /**
140          * @private
141          * Unsubscribe from a particular topic.
142          * @param {String} topic
143          *     The full topic name.
144          */
145         _unsubscribe = function (topic) {
146             _isInited();
147 
148             //Unsubscribe from the topic using the subscription ID recorded when
149             //the subscription was made, then delete the ID from data structure.
150             _hub.unsubscribe(_subscriptionID[topic]);
151             delete _subscriptionID[topic];
152         },
153         
154         _tabTracker = function(tabId) {
155             if (tabId === _myTab) {
156                 if(!_visible) {
157                     _visible = true;
158                     _tabVisibleNotifier.notifyListeners(this);
159                 }
160             } else {
161                 _visible = false;
162             }
163         };
164 
165     return {
166         /**
167          * Shows the jQuery UI Dialog with the specified parameters and the
168          * following defaults:
169          *     - The only button "Ok" closes the dialog
170          *     - Modal
171          *     - Not draggable
172          *     - Fixed size
173          * @param {Object} options
174          *     An object containing additional options for the dialog.
175          * @param {String/Boolean} options.title
176          *     Title to use. undefined defaults to "Cisco Finesse".
177          *     false to hide
178          * @param {Function} options.close
179          *     A function to invoke when the dialog is closed.
180          * @param {String} options.message
181          *     The message to display in the dialog.
182          *     Defaults to "A generic error has occurred."
183          * @param {Boolean} options.isBlocking
184          *     Flag indicating whether this dialog will block other
185          *     dialogs from being shown.
186          * @returns {jQuery}
187          *     jQuery wrapped object of the dialog DOM element
188          */
189         showDialog: function(options) {
190             if ((_parent.showDialog !== undefined) && (_parent.showDialog !== this.showDialog)) {
191                 return _parent.showDialog(options);
192             }
193         },
194         
195         /**
196          * Hides the jQuery UI Dialog
197          * @returns {jQuery}
198          *     jQuery wrapped object of the dialog DOM element
199          */
200         hideDialog: function() {
201             if ((_parent.hideDialog !== undefined) && (_parent.hideDialog !== this.hideDialog)) {
202                 return _parent.hideDialog();
203             }
204         },
205         
206         /**
207      * Adds an handler to this object.
208      * @param {String} notifierType
209      *     The type of notifier to add to ('tabVisible')
210      * @param {Function} callback
211      *     The function callback to invoke.
212      */
213         addHandler: function (notifierType, callback) {
214           _isInited();
215           var notifier = null;
216         try {
217             _util.validateHandler(callback);
218 
219             notifier = _getNotifierReference(notifierType);
220 
221             notifier.addListener(callback);
222             
223         } catch (err) {
224             throw new Error("addHandler(): " + err);
225         }
226         }, 
227         
228         /**
229      * Removes a handler from this object.
230      * @param {String} notifierType
231      *     The type of notifier to remove ('tabVisible')
232      * @param {Function} callback
233      *     The function to remove.
234      */
235         removeHandler: function(notifierType, callback) {
236             var notifier = null;
237         try {
238             _util.validateHandler(callback);
239 
240             notifier = _getNotifierReference(notifierType);
241 
242             notifier.removeListener(callback);
243         } catch (err) {
244             throw new Error("removeHandler(): " + err);
245         }
246         },
247         /**
248          * Returns the visibility of current gadget
249          * @return {Boolean} 
250          *         The visibility of current gadget
251          */
252         tabVisible: function(){
253             return _visible;
254         },
255         
256          /**
257          * Make a request to the check the current tab
258          */
259         makeActiveTabReq : function () {
260             if(_hub){
261                 var data = {
262                     type: "ActiveTabReq",
263                     data: {},
264                     invokeID: (new Date()).getTime()          
265                 };
266                 _hub.publish(_topics.REQUESTS, data);
267             } else {
268                 throw new Error("Hub is not defined.");
269             }
270             
271         },
272 
273         /**
274          * Initiates the Container Services.
275          * @return {Object} 
276          *         The ContainerServices instance
277          */
278         init: function () {
279             if (!_inited) {
280                 // Set shortcuts
281                 _util = finesse.utilities.Utilities;
282                 _parent = parent.finesse.container.Container;
283                 _prefs = new gadgets.Prefs();
284                 _myTab = _prefs.getString("tabId");
285                 _tabVisibleNotifier = new finesse.restservices.Notifier();
286                 _inited = true;
287                 //init the hub only when it's available
288                 if(gadgets.Hub) {
289                     _hub = gadgets.Hub;
290                     _subscribe("finesse.containerservices.activeTab", _tabTracker);
291                 }
292                 if(finesse.containerservices.Topics) {
293                     _topics = finesse.containerservices.Topics;
294                 }
295                 if(finesse.containerservices.MasterPublisher){
296                    publisher = new finesse.containerservices.MasterPublisher();
297                 }
298             }
299 
300             //Return the CS object for object chaining.
301             return this;
302         },
303 
304         
305 
306         //BEGIN TEST CODE//
307         /**
308          * Test code added to expose private functions that are used by unit test
309          * framework. This section of code is removed during the build process
310          * before packaging production code. The [begin|end]TestSection are used
311          * by the build to identify the section to strip.
312          * @ignore
313          */
314         beginTestSection : 0,
315 
316         /**
317          * @ignore
318          */
319         getTestObject: function () {
320             //Load mock dependencies.
321             var _mock = new MockControl();
322             _util = _mock.createMock(finesse.utilities.Utilities);
323             _hub = _mock.createMock(gadgets.Hub);
324             _inited = true;
325             _tabVisibleNotifier = new finesse.restservices.Notifier();
326             return {
327                 //Expose mock dependencies
328                 mock: _mock,
329                 hub: _hub,
330                 util: _util,
331                 tabVisibleNotifier: _tabVisibleNotifier,
332                 addHandler: this.addHandler, 
333                 removeHandler: this.removeHandler         
334                 
335             };
336         },
337 
338         /**
339          * @ignore
340          */
341        endTestSection: 0
342         //END TEST CODE//
343     };
344 }());
345