Added wrt files, prior to converting into Qt/C++.
[ptas] / wrt / zouba / preview / script / lib / sapi / Calendar.js
1 /**
2  * Calendar.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 (function(){
12         
13         var provider = 'Service.Calendar' ,
14                 Interface = 'IDataSource';
15
16         /**
17          * Calendar service
18          */
19         var CalendarService = function(){
20                 this.GetList    = __GetList;
21                 this.Add                = __Add;
22                 this.Delete     = __Delete;
23                 this.Import     = __Import;
24                 this.Export     = __Export;
25                 this.Cancel     = __Cancel;
26                 this.RequestNotification = __RequestNotification;
27         }
28
29         device.implementation.extend(provider, Interface, new CalendarService() );
30
31
32         /******************************************************/        
33         /******************************************************/        
34         /******************************************************/        
35
36         var     context = device.implementation.context,
37                 _t = context._t,
38                 method = '',
39                 result = false,
40                 DBase = null,
41                 default_calendar = 'C:Calendar';
42         
43         /**
44          * Calendar: GetList
45          * @param {Object} criteria
46          */
47         function __GetList(criteria){
48                 if ((result = validator.apply('GetList', arguments)) !== false)
49                         return result; 
50
51                 var returnValue = [], 
52                         match = null,
53                         filter = criteria.Filter || null;
54  
55                 DBase = context.getData(provider);
56
57                 // Type = Calendar
58                 if (!/CalendarEntry/i.test(criteria.Type)){
59                         var cals = [default_calendar];
60                         if (filter && filter.DefaultCalendar === false)
61                                 cals = context.keys(DBase)
62
63                         returnValue = cals;
64
65                 } else {
66                 // Type = CalendarEntry
67                         var cal = default_calendar;
68                         if (filter && filter.CalendarName)
69                                 cal = filter.CalendarName;
70                         
71                         if (!(cal in DBase))
72                                 return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.badCalendar);
73
74                         // filter by id or LocalId
75                         if (filter && (filter.id || filter.LocalId)) {
76                                 var which = filter.id ? 'id' : 'LocalId', 
77                                         id = filter[which];
78                                         
79                                 for (var i in DBase[cal]) {
80                                         if (id == DBase[cal][i][which]) {
81                                                 returnValue.push(DBase[cal][i]);
82                                         }
83                                 }
84                         }
85                         // filter by type 
86                         else if (filter && filter.Type && !/IncludeAll/i.test(filter.Type)) {
87                                 for (var i in DBase[cal]) {
88                                         // match on type is case insensitive
89                                         if (filter.Type.toLowerCase() == DBase[cal][i].Type.toLowerCase()) {
90                                                 returnValue.push(DBase[cal][i]);
91                                         }
92                                 }
93                         }
94                         // unsupported filters 
95                         else if (filter 
96                                 && (match = context.keys(filter).join().match(/StartRange|EndRange|SearchText/ig)) ) {
97                                 context.notify(_t('%s:: GetList : filter %s not implemented in preview').arg(provider, match.join()));
98                         }
99                         // return everything 
100                         else {
101                                 returnValue = DBase[cal];
102                         }
103                 }
104
105                 return context.Result(context.Iterator(returnValue));
106         }
107                         
108         /**
109          * Calendar: Add
110          * @param {Object} criteria
111          */
112         function __Add(criteria){
113                 if ((result = validator.apply('Add', arguments)) !== false)
114                         return result; 
115                 
116                 var Item = criteria.Item || false; 
117                 
118                 DBase = context.getData(provider);
119
120                 // Type = Calendar
121                 if (!/CalendarEntry/i.test(criteria.Type)){
122
123                         if (!Item || !Item.CalendarName)
124                                 return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.missingCalendar);
125                                 
126                         var cal = Item.CalendarName;
127                         if (cal in DBase) {
128                                 return error(device.implementation.ERR_ENTRY_EXISTS);
129                         }
130
131                         // @todo: validate calendar name <drive>:<name>
132                         // return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.badCalendar);
133                         
134                         // create new calendar
135                         device.implementation.loadData(provider, cal, []);
136                         return error(device.implementation.ERR_SUCCESS);
137
138                 } else {
139                 // Type = CalendarEntry
140
141                         if (!Item)
142                                 return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_missing, 'Item');
143                                 
144                         var cal = Item.CalendarName || default_calendar;
145
146                         // if calendar doesn't exist and it's the default, create it
147                         if (!(cal in DBase) && cal == default_calendar)
148                                 device.implementation.loadData(provider, cal, []);
149                         
150                         if (!(cal in DBase))
151                                 return error(device.implementation.ERR_NOT_FOUND);
152
153                         // update existing item?
154                         if ('LocalId' in Item) {
155                                 
156                                 if (!Item.LocalId && Item.LocalId !== 0)
157                                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_invalid, 'LocalId');
158                                 
159                                 if ('InstanceStartTime' in Item)
160                                         context.notify(_t('%s:: Add : InstanceStartTime not implemented in preview.').arg(provider));
161
162                                 // can't update id
163                                 delete Item.id;
164                                 
165                                 //  search for and update item
166                                 var found = false;
167                                 for (var i in DBase[cal]) {
168                                         var entry = DBase[cal][i];
169                                         if (entry.LocalId == Item.LocalId) {
170                                                 context.extend(entry, Item);
171                                                 Item.id = entry.id;
172                                                 found = true;
173                                                 break;
174                                         }
175                                 }
176                                 if (!found)
177                                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_invalid, 'LocalId');
178
179                         } else {
180                         // add new item
181                                 // generate new id and localId 
182                                 // -- in calendar id's are string!
183                                 Item.id = String(context.getUniqueID());
184                                 Item.LocalId = String(context.getUniqueID());
185                                 DBase[cal].push(Item);
186                         } 
187                 } 
188                 // return success
189                 return context.Result(Item.id, device.implementation.ERR_SUCCESS);
190         }
191                         
192
193         /**
194          * Calendar: Delete
195          * @param {Object} criteria
196          * @param {function} callback function for async call (optional - valid only for CalendarEntry)
197          */
198         function __Delete(criteria, callback){
199                 
200                 if ((result = validator.apply('Delete', arguments)) !== false)
201                         return result; 
202
203                 var Data = criteria.Data || false; 
204                 if (!Data || typeof Data != 'object')
205                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_invalid, 'Data');
206                 
207                 // only sync call supported for Calendar
208                 if (!/CalendarEntry/i.test(criteria.Type) && typeof callback == 'function')
209                         return error(device.implementation.ERR_SERVICE_NOT_SUPPORTED, msg.noAsync);
210
211                 DBase = context.getData(provider);
212                 var cal = Data.CalendarName || default_calendar;                        
213                 if (!(cal in DBase))
214                         return error(device.implementation.ERR_NOT_FOUND);
215                 
216                 // Type = Calendar
217                 if (!/CalendarEntry/i.test(criteria.Type)) {
218                         // CalendarName is mandatory
219                         if (!Data.CalendarName)
220                                 return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_missing, 'CalendarName');
221                                                 
222                         DBase[cal] = null;
223                         delete DBase[cal];
224                 }
225                 else {
226                 // Type = CalendarEntry
227
228                         if (!context.keys(Data).join().match(/IdList|LocalIdList|DeleteAll|StartRange|EndRange/ig))
229                                 return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_missing, 'Data');
230
231                         if (typeof callback == 'function') {
232                                 return context.callAsync(this, arguments.callee, criteria, callback);
233                         }
234
235                         var which = Data.IdList ? 'IdList' : 'LocalIdList',
236                                 idList = Data[which] || false;
237                                 
238                         if (idList) {
239                                 //  search for and delete items
240                                 for (var id in idList) {
241                                         id = idList[id];
242                                         for (var i in DBase[cal]) {
243                                                 if (id == DBase[cal][i][which]) {
244                                                         DBase[cal].splice(i, 1);
245                                                 }
246                                         }
247                                 }
248                         }
249                         else if (Data.DeleteAll && Data.DeleteAll === true){
250                                 delete DBase[cal];
251                                 DBase[cal] = [];
252                         }
253
254                         if (Data.StartRange || Data.EndRange) {
255                                 context.notify(_t('%s:: Delete : StartRange / EndRange not implemented in preview.').arg(provider));
256                         }
257                 }
258                 // return success
259                 return context.ErrorResult(device.implementation.ERR_SUCCESS);                          
260         }
261                         
262
263         /**
264          * Calendar: Import
265          * @param {Object} criteria
266          * @param {function} callback function for async call (optional)
267          */
268         function __Import(criteria, callback){
269
270                 if ((result = validator.apply('Import', arguments)) !== false)
271                         return result; 
272
273                 var Data = criteria.Data || false; 
274                 if (!Data)
275                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_invalid, 'Data');
276                 
277                 if (!Data.FileName)
278                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_invalid, 'FileName');
279
280                 if (!Data.Format)
281                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_invalid, 'Format');
282
283                 if (typeof callback == 'function') {
284                         return context.callAsync(this, arguments.callee, criteria, callback);
285                 }
286
287                 context.notify(_t('%s:: Import : not implemented in preview.').arg(provider));
288                 var returnValue = context.Iterator([]);
289                 return context.Result(returnValue, device.implementation.ERR_SUCCESS);          
290         }
291                         
292
293         /**
294          * Calendar: Export
295          * @param {Object} criteria
296          * @param {function} callback function for async call (optional)
297          */
298         function __Export(criteria, callback){
299
300                 if ((result = validator.apply('Export', arguments)) !== false)
301                         return result; 
302
303                 var Data = criteria.Data || false; 
304                 if (!Data)
305                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_invalid, 'Data');
306
307                 if (!Data.Format)
308                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.is_invalid, 'Format');
309
310                 if (typeof callback == 'function') {
311                         return context.callAsync(this, arguments.callee, criteria, callback);
312                 }
313                 context.notify(_t('%s:: Export : not implemented in preview.').arg(provider));
314                 var returnValue = '';
315                 return context.Result(returnValue, device.implementation.ERR_SUCCESS);          
316         }
317                         
318
319         /**
320          * Calendar: RequestNotification
321          * @param {Object} criteria
322          * @param {function} callback function for async call 
323          */
324         function __RequestNotification(criteria, callback){
325
326                 if ((result = validator.apply('RequestNotification', arguments)) !== false)
327                         return result; 
328
329                 if (typeof callback != 'function')
330                         return error(device.implementation.ERR_SERVICE_NOT_SUPPORTED, msg.badAsync);
331
332                 context.notify(_t('%s:: RequestNotification : not implemented in preview.').arg(provider));
333                 var result = context.ErrorResult(device.implementation.ERR_SUCCESS);
334                 result.TransactionID = 0;
335                 return result;          
336         }
337                         
338
339         /**
340          * Calendar: Cancel
341          * @param {Object} criteria
342          */
343         function __Cancel(criteria){
344                 method = 'Cancel';
345                 if (!criteria || !criteria.TransactionID)
346                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.missingTID);
347                 
348                 clearTimeout(criteria.TransactionID);
349                 return context.ErrorResult(device.implementation.ERR_SUCCESS);
350         }
351
352
353         
354         /*******************************
355          * helper functions
356          *******************************/
357         
358         function error(code, msg /*, args...*/){
359
360                 var args = ['Calendar',method].concat([].slice.call(arguments,2));
361                 msg = msg ? _t().arg.apply(msg,args) : undefined;
362                 return context.ErrorResult(code, msg);
363         }
364
365         /**
366          * validate common input arguments
367          * 'this' is string (object) name of calling function
368          * 
369          * @param {arguments} arguments of calling function
370          * @return {Result} Result object if error, false if no error.
371          */
372         function validator() {
373                 method = ''+this;
374                 var     failed = false,
375                         criteria = arguments[0] || false;
376                         
377                 if (!criteria)
378                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.badType);
379                         
380                 if (typeof criteria != 'object' || typeof criteria.Type == 'undefined')
381                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.badType);
382                 
383                 var TypeRE = /Import|Export|RequestNotification/i.test(method)
384                         ? /^CalendarEntry$/i
385                         : /^(Calendar|CalendarEntry)$/i;
386                  
387                 if (!TypeRE.test(criteria.Type)) 
388                         return error(device.implementation.ERR_INVALID_SERVICE_ARGUMENT, msg.badType);
389                 
390                 return failed;
391         }
392
393         /** 
394          * error messages
395          * order of %s args: Service name, method name, parameter name 
396          */
397         var msg = {
398                 badType                 : '%s : %s : Type is invalid',
399                 badCalendar             : '%s : %s : CalendarName is invalid',
400                 missingCalendar : '%s : %s : CalendarName is missing',
401                 missingTID              : '%s : %s : TransactionID is missing',
402                 badAsync                : '%s : %s : Invalid async parameters',
403                 noAsync                 : '%s : %s : Async not supported',
404                 is_missing              : '%s : %s : %s is missing',
405                 is_invalid              : '%s : %s : %s is invalid'
406         };
407                 
408
409 }) ();
410