Added wrt files, prior to converting into Qt/C++.
[ptas] / wrt / misc / rss / preview / script / lib / device.js
1 /**
2  * device.js
3  * 
4  * Nokia Web Runtime Service API emulation 
5  * WRT v1.1
6  * 
7  * Copyright 2009 Nokia Corporation. All rights reserved.
8 */
9
10
11 /**
12  * device object. entry point to device service API (SAPI)
13  */
14 var device = {
15         /**
16          * device API public method
17          * 
18          * @method
19          * @param {string} provider Name of service provider, eg, "Service.Calendar"
20          * @param {string} Interface Name of interface, eg, "IDataSource"
21          * @return {Object} service object  
22          */
23         getServiceObject: function(provider, Interface){
24
25                 if (!device.implementation.context)
26                         throw 'device implementation object not instantiated!'
27
28                 if (device.implementation.options.enabled) 
29                         return device.implementation.getInterface(provider, Interface);
30                 else {
31                         device.implementation.context.notify('device SAPI is disabled.');
32                         throw 'device not defined!';
33                 }
34         }
35 };
36
37
38
39 /**
40  * implementation of device emulation mode
41  * 
42  * @param {String}              version - version number (default: current version)
43  * @return {Object}     returns new implementation context object 
44  * @constructor                 
45  */
46 device.implementation = function(version){
47
48         this.version = version || '';
49         
50         // set context to current object
51         device.implementation.context = this;   
52
53         var libpath = 'preview/script/lib/',
54                 datapath = 'preview/data/';
55         
56         // load implementation files
57         // this is done async by the browser engine, so be aware of sync conditions!!
58         if (version == '1')
59                 loadSAPI(libpath + 'sapi1/');
60         else if (!version)
61                 loadSAPI();
62         else
63                 throw 'unsuppported SAPI version!';
64         
65         function loadSAPI(path){
66                 var path = path || (libpath + "sapi/");
67                 
68                 // load API
69                 loadScript(path + "AppManager.js");
70                 loadScript(path + "Calendar.js");
71                 loadScript(path + "Contact.js");
72                 loadScript(path + "Landmarks.js");
73                 loadScript(path + "Location.js");
74                 loadScript(path + "Logging.js");
75                 loadScript(path + "MediaManagement.js");
76                 loadScript(path + "Messaging.js");
77                 loadScript(path + "Sensor.js");
78                 loadScript(path + "SysInfo.js");
79                 
80                 // load sample data
81                 loadScript(datapath + "appManager_data.js");
82                 loadScript(datapath + "calendar_data.js");
83                 loadScript(datapath + "contact_data.js");
84                 loadScript(datapath + "landmarks_data.js");
85                 loadScript(datapath + "location_data.js");
86                 loadScript(datapath + "logging_data.js");
87                 loadScript(datapath + "mediaManagement_data.js");
88                 loadScript(datapath + "messaging_data.js");
89                 loadScript(datapath + "sensor_data.js");
90                 loadScript(datapath + "sysInfo_data.js");
91         }
92         
93         function loadScript(src){
94                 var head = document.getElementsByTagName("head")[0] || document.documentElement, 
95                         script = document.createElement("script");
96                 
97                 script.type = "text/javascript";
98                 script.src = src;
99                 head.appendChild(script);
100         }
101 };
102
103 (function(){
104 device.implementation.prototype = {
105         
106         /**
107          * Result object
108          * 
109          * object returned by API calls
110          * 
111          * @param {Object} value
112          * @param {Integer} code
113          * @param {String} msg
114          */
115         Result : function(value, code, msg){
116                 return {
117                         ReturnValue     : value,
118                         ErrorCode       : code || 0,
119                         ErrorMessage: msg || undefined
120                 };
121         },
122         
123         /**
124          * AsyncResult object
125          * 
126          * object returned by API calls with callbacks
127          * 
128          * @param {Integer} transaction id
129          * @param {Integer} code
130          * @param {String} msg
131          */
132         AsyncResult : function(id, code, msg){
133                 return {
134                         TransactionID   : id,
135                         ErrorCode               : code || 0,
136                         ErrorMessage    : msg || undefined
137                 };
138         },
139         /**
140          * ErrorResult object
141          * 
142          * object returned by API calls when error
143          * 
144          * @param {Integer} code
145          * @param {String} msg
146          */
147         ErrorResult : function(code, msg){
148                 device.implementation.context.debug(code, msg);         
149                 return {
150                         ErrorCode       : code || 0,
151                         ErrorMessage: msg || undefined
152                 };
153         },
154         
155         /**
156          * Iterator object
157          * 
158          * object returned as ReturnValue by some API
159          * 
160          * @param {Array} data
161          */
162         Iterator : function(data){
163                 var index = 0,
164                         data = data || [];
165                 return {
166                         /**
167                          * reset
168                          */
169                         reset : function(){
170                                 index = 0;
171                         },
172                         
173                         /**
174                         * getNext
175                         */
176                         getNext : function(){
177                                 return index < data.length ? data[index++] : undefined;
178                         }
179                 }
180         },
181         
182         
183         /**
184          * internal __methods__
185          */
186         
187         $break:         {}, // 'not implemented',
188         
189         debug: function() {
190                 if (device.implementation.options.debug && window.console && console.log) 
191                         console.log(arguments);
192         },
193         
194         // notify developer of api action
195         notify: function(msg){
196                 if (window.console && console.warn)
197                         console.warn('API Notice -- ' + msg);
198         },
199         
200         getData : function(provider){
201                 if (!device.implementation.data[provider])
202                         throw "no data defined for provider '"+provider+"'";
203                 
204                 if (device.implementation.data[provider]['default'])
205                         return device.implementation.data[provider]['default'];
206                 else 
207                         return device.implementation.data[provider]; 
208         },      
209         
210         getUniqueID : function(){
211                 return Number(''+Number(new Date())+ Math.floor(1000*Math.random()));
212         },
213         
214         callAsync : function(object, method, criteria, callback, flag){
215                 flag = flag || false;
216                 var tid = setTimeout(function(){
217                         var result,
218                                 eventCode = {completed:2, error:4, progress:9},
219                                 code = eventCode.completed;
220                         try{
221                                 // call method in object's context
222                                 // flag is passed to trigger the method in case of mandatory callback arg
223                                 if (flag)
224                                         result = method.call(object, criteria, null, flag);
225                                 else
226                                         result = method.call(object, criteria);
227                         } 
228                         catch(e){
229                                 code = eventCode.error;
230                         }
231                         callback(tid, code, result);
232                         
233                 }, device.implementation.options.callbackDelay);
234                 
235                 return this.AsyncResult(tid);
236         },
237                 
238         addListener : function(provider, eventType, criteria, callback, handler){
239                 if (!device.implementation.listeners[provider])
240                         device.implementation.listeners[provider] = {};
241                         
242                 var tid = this.getUniqueID();
243                 device.implementation.listeners[provider][eventType] = {
244                         'criteria': criteria,
245                         'callback': callback,
246                         'handler': handler,
247                         'transactionID' : tid
248                 };
249                 return this.AsyncResult(tid);
250         },
251
252         /*
253          * specify either eventType or transactionID
254          * return true if found and removed
255          */
256         removeListener: function(provider, eventType, transactionID){
257                 transactionID = transactionID || null;
258                 if (transactionID) {
259                         var allEvents = device.implementation.listeners[provider];
260                         for (var i in allEvents) {
261                                 var event = allEvents[i];
262                                 if (event.transactionID == transactionID) {
263                                         device.implementation.listeners[provider][i] = null;
264                                         delete device.implementation.listeners[provider][i];
265                                         return true;
266                                 }
267                         }
268                 }
269                 else 
270                         if (eventType &&
271                         this.hasListener(provider, eventType)) {
272                                 device.implementation.listeners[provider][eventType] = null;
273                                 delete device.implementation.listeners[provider][eventType];
274                                 return true;
275                         }
276                 return false;
277         },
278
279         hasListener: function(provider, eventType) {    
280                 if (!device.implementation.listeners[provider]
281                         || !device.implementation.listeners[provider][eventType])
282                         return false;
283                                 
284                 return true;
285         },
286
287         // pluck object properties as array     
288         keys: function(obj) {
289                 var keys = [];
290                 for (var p in obj)
291                         keys.push(p);
292                 return keys;
293         },
294         
295         // extend object properties 
296         extend: function(root, ext) {
297                 for (var p in ext)
298                         root[p] = ext[p];
299                 return root;
300         },
301         
302         // extended text string functionality 
303         _t: function(str){
304                 
305                 str = typeof str != 'undefined' ? String(str) : '';
306                 return new StringEx(str);
307         }               
308 };
309
310         /**
311          * extended String object (available only within device.implementation.context through _t() method)
312          */ 
313         var StringEx = function(str){
314                 // define base String non-transferrable methods!
315                 this.toString = function(){return str;};
316                 this.valueOf = function(){return str.valueOf();};
317         };
318         StringEx.prototype = new String();
319
320         
321         /**
322          * simple sprintf-type functionality
323          * 
324          * "string {title} %s and %s and {here} ".arg({title:'T', here:'H'}, 1, 'there')"
325          * ==> string T 1 and there and H
326          * hash (if present) must be first argument
327          *
328          * @param {Object} [hash] optional hash to replace {tags}
329          * @param {String,Number} data for %s tags
330          * @return {String} original string with tags replaced   
331          */
332         StringEx.prototype.arg = function(){
333             var pattern = /\%s|\{\w+\}/g;
334             var args = arguments, 
335                         len = arguments.length, 
336                         hash = arguments[0],
337                         i = typeof hash == 'object' && !(hash instanceof String) ? 1 : 0;
338                         
339             return this.replace(pattern, function(capture){
340                         var key = capture != '%s' && capture.match(/\w+/);
341                         if (key)
342                                 return hash && hash[key] ? hash[key] : capture;
343                         else            
344                                 return i < len ? args[i++] : capture;
345                 });
346         }
347         
348         /**
349          * trim whitespace from beginning and end of string
350          * @return {String} trimmed string
351          */
352         StringEx.prototype.trim = function(){
353                 return this.replace(/^\s+/, '').replace(/\s+$/, '');
354         }
355         
356         /**
357          * capitalize string
358          * @return {String} capitalized string
359          */
360         StringEx.prototype.capitalize = function(){
361         return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
362         }
363         
364 })();
365
366
367 /*
368  * device.implementation static (class) properties
369  */
370
371
372 /**
373  * pointer to current instantiated device.implementation object.
374  * use to access device.implemenation namespace.
375  * 
376  * @see device.implementation 
377  */
378 device.implementation.context = null;   
379
380
381 /**
382  * emulation settings options
383  */
384 device.implementation.options = {
385         
386         /**
387          * callback delay (msec)
388          * @property {Number} 
389          */
390         callbackDelay   : 1200,
391         
392         /**
393          * debug flag
394          * @property {Boolean} 
395          */
396         debug                   : false,
397         
398         /**
399          * enabled flag
400          * @property {Boolean} 
401          */
402         enabled                 : true
403 };
404
405
406 /**
407  * store of interfaces (objects) in the current device implementation.
408  * format: [provider][interface]
409  * 
410  * @property {Object} 
411  */
412 device.implementation.interfaces = {};
413
414
415 /**
416  * store of data objects defined for current implementation.
417  * data is added useing the loadData method. 
418  * 
419  * @property {Object} format depends on data
420  */
421 device.implementation.data = {};
422
423
424 /**
425  * store of event listeners
426  * format: [provider][eventType]
427  */
428 device.implementation.listeners = {}; 
429
430
431 /*
432  * device.implementation static (class) methods
433  */
434
435
436 /**
437  * Add a service provider to device implementation
438  * 
439  * @param {string} provider Name of service provider, eg, "Service.Calendar"
440  * @param {string} Interface Name of interface, eg, "IDataService"
441  * @param {Object} serviceProvider Service object
442  * @return  none
443  */
444 device.implementation.extend = function(provider, Interface, serviceProvider){
445
446         if (!device.implementation.interfaces[provider])
447                 device.implementation.interfaces[provider] = {}; 
448         
449         device.implementation.interfaces[provider][Interface] = serviceProvider;
450 };
451
452
453 /**
454  * Internal implementation to return a service provider interface object
455  * 
456  * @param {String} provider  Service provider name 
457  * @param {String} Interface    Provider interface name
458  * @exception {String} exception thrown if provider or interface is not implemented 
459  * @return {Object} the service provider interface object or 'undefined'
460  */     
461 device.implementation.getInterface = function(provider, Interface){
462                 
463         if (device.implementation.interfaces[provider] 
464                 && typeof device.implementation.interfaces[provider][Interface] == 'object') 
465         {
466                 var service = new Object();
467                 service[Interface] = device.implementation.interfaces[provider][Interface];
468                 return service;
469         }
470         else
471                 throw 'Error: unknown error'; 
472 };
473
474
475 /**
476  * Loads data to the data store
477  * 
478  * @param {String} provider  Service provider name 
479  * @param {String} type Data name/label
480  * @param {Function,Object,Array} dataFactory Function to generate the data object, or array/object
481  * @return none
482  */
483 device.implementation.loadData = function(provider, type, dataFactory){
484
485         type = type || 'default';
486         if (!device.implementation.data[provider]) 
487                 device.implementation.data[provider] = {};
488                 
489         device.implementation.data[provider][type] = 
490                 typeof dataFactory == 'function' 
491                         ? dataFactory()
492                         : dataFactory;
493 };
494
495
496 /**
497  * trigger an event listener
498  * 
499  * @param {String} provider Service provider name
500  * @param {String} eventType event type 
501  * @param {Variant} data ReturnValue for callback function 
502  */
503 device.implementation.triggerListener = function(provider, eventType, data){
504
505         if (!device.implementation.context.hasListener(provider, eventType)) {
506                 device.implementation.context.notify('no listener defined for provider=' + provider + ', eventType=' + eventType);
507                 return;
508         }
509         var listener = device.implementation.listeners[provider][eventType];
510
511         // call the provider's handler
512         listener.handler(listener.transactionID, listener.criteria, listener.callback, data);
513 }
514
515
516
517 /*
518  * ERROR CODES
519  */
520 device.implementation.ERR_SUCCESS                                       = 0;
521 device.implementation.ERR_INVALID_SERVICE_ARGUMENT      = 1000;
522 device.implementation.ERR_UNKNOWN_ARGUMENT_NAME         = 1001;
523 device.implementation.ERR_BAD_ARGUMENT_TYPE                     = 1002;
524 device.implementation.ERR_MISSING_ARGUMENT                      = 1003;
525 device.implementation.ERR_SERVICE_NOT_SUPPORTED         = 1004;
526 device.implementation.ERR_SERVICE_IN_USE                        = 1005;
527 device.implementation.ERR_SERVICE_NOT_READY             = 1006;
528 device.implementation.ERR_NO_MEMORY                                     = 1007;
529 device.implementation.ERR_HARDWARE_NOT_AVAILABLE        = 1008;
530 device.implementation.ERR_SEVER_BUSY                            = 1009;
531 device.implementation.ERR_ENTRY_EXISTS                          = 1010;
532 device.implementation.ERR_ACCESS_DENIED                         = 1011;
533 device.implementation.ERR_NOT_FOUND                                     = 1012;
534 device.implementation.ERR_UNKNOWN_FORMAT                        = 1013;
535 device.implementation.ERR_GENERAL_ERROR                         = 1014;
536 device.implementation.ERR_CANCEL_SUCCESS                        = 1015;
537 device.implementation.ERR_SERVICE_TIMEDOUT                      = 1016;
538 device.implementation.ERR_PATH_NOT_FOUND                        = 1017;
539
540
541
542 // instantiate device imlementation
543 new device.implementation();
544