Update change log and spec for wrt-plugins-tizen_0.4.70
[framework/web/wrt-plugins-tizen.git] / src / Calendar / JSCalendarEvent.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 #include <ctime>
19 #include <CommonsJavaScript/PrivateObject.h>
20 #include <CommonsJavaScript/Converter.h>
21 #include <CommonsJavaScript/JSUtils.h>
22 #include <CommonsJavaScript/Utils.h>
23 #include <CommonsJavaScript/Validator.h>
24 #include <CommonsJavaScript/JSCallbackManager.h>
25 #include "EventId.h"
26 #include "JSCalendarEvent.h"
27 #include "JSCalendarItemProperties.h"
28 #include "CalendarConverter.h"
29 #include "JSCalendarEventId.h"
30 #include "JSCalendarRecurrenceRule.h"
31 #include "plugin_config.h"
32 #include "CalendarResponseDispatcher.h"
33 #include <TimeUtilConverter.h>
34 #include <JSTZDate.h>
35 #include <JSWebAPIErrorFactory.h>
36 #include <Security.h>
37 #include <SecurityExceptions.h>
38 #include <GlobalContextManager.h>
39 #include <TimeTracer.h>
40 #include <Logger.h>
41 #include <Export.h>
42
43 using namespace WrtDeviceApis::Commons;
44 using namespace WrtDeviceApis::CommonsJavaScript;
45 using namespace DeviceAPI::Common;
46 using namespace DeviceAPI::Time;
47
48 namespace DeviceAPI {
49 namespace Calendar {
50
51 using WrtDeviceApis::Commons::UnknownException;
52 using WrtDeviceApis::Commons::NotFoundException;
53
54 JSClassDefinition JSCalendarEvent::m_classInfo = {
55     0,
56     kJSClassAttributeNone,
57     TIZEN_INTERFACE_CALENDAR_EVENT,
58     JSCalendarItemProperties::getClassRef(),
59     m_property,
60     m_function,
61     initialize,
62     finalize,
63     NULL, //hasProperty,
64     NULL, //getProperty,
65     NULL, //setProperty,
66     NULL, //DeleteProperty,
67     NULL, //GetPropertyNames,
68     NULL, //CallAsFunction,
69     NULL, //constructor,
70     NULL, //HasInstance,
71     NULL  //ConvertToType
72 };
73
74 JSStaticValue JSCalendarEvent::m_property[] = {
75     { TIZEN_CALENDAR_EVENT_ID, getPropertyId, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
76     { TIZEN_CALENDAR_EVENT_IS_DETACHED, getPropertyIsDetached, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
77     { TIZEN_CALENDAR_EVENT_AVAILABILITY, getPropertyAvailability, setPropertyAvailability, kJSPropertyAttributeNone | kJSPropertyAttributeDontDelete },
78     { TIZEN_CALENDAR_EVENT_RECURRENCE_RULE, getPropertyRecurrenceRule, setPropertyRecurrenceRule, kJSPropertyAttributeNone | kJSPropertyAttributeDontDelete },
79
80     { 0, 0, 0, 0 }
81 };
82
83 JSStaticFunction JSCalendarEvent::m_function[] = {
84     { CALENDAR_FUNCTION_API_EXPAND_RECURRENCE, expandRecurrence, kJSPropertyAttributeNone },
85
86     { 0, 0, 0 }
87 };
88
89 JSClassRef JSCalendarEvent::m_jsClassRef = JSClassCreate(JSCalendarEvent::getClassInfo());
90
91 ICalendarPtr JSCalendarEvent::m_calendar;
92
93 void JSCalendarEvent::initialize(JSContextRef context,
94         JSObjectRef object)
95 {
96     if (!JSObjectGetPrivate(object)) {
97         LoggerD("Create calendar event private object.");
98         CalendarEventPtr event( new CalendarEvent() );
99         CalendarEventPrivObject *priv = new CalendarEventPrivObject(context, event);
100         if (!JSObjectSetPrivate(object, static_cast<void*>(priv))) {
101             delete priv;
102         }
103     } else {
104         LoggerD("Private object already set.");
105     }
106
107         if (NULL==m_calendar) {
108                 m_calendar = CalendarFactory::getInstance().createCalendarObject();
109                 m_calendar->setType(CalendarEvent::EVENT_TYPE);
110                 LoggerD("Static calendar for event created.");
111         }
112 }
113
114 void JSCalendarEvent::finalize(JSObjectRef object)
115 {
116     CalendarEventPrivObject* priv = static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
117     if (priv) {
118         delete priv;
119         JSObjectSetPrivate(object, NULL);
120     }
121 }
122
123 JSObjectRef DLL_EXPORT JSCalendarEvent::constructor(JSContextRef context,
124     JSObjectRef constructor,
125     size_t argumentCount,
126     const JSValueRef arguments[],
127     JSValueRef* exception)
128 {
129     CalendarEventPtr event(new CalendarEvent());
130         JSContextRef globalContext = GlobalContextManager::getInstance()->getGlobalContext(context);
131
132     DeviceAPI::Common::SecurityAccessor *securityAccessor = NULL;
133
134     try
135     {
136         securityAccessor = DeviceAPI::Common::JSObjectGetSecurityAccessor(context, constructor);
137     }
138     catch(BasePlatformException &e)
139     {
140         event->setCalendarType(CalendarEvent::EVENT_TYPE);
141         return createJSCalendarEvent(globalContext, event, securityAccessor);
142     }
143
144     Try
145     {
146         CalendarConverter converter(globalContext);
147
148         if (argumentCount==0) {
149                         LoggerD("No arguments provided.");
150         } else if (argumentCount==1) {
151             LoggerI("eventInitDict case");
152             if (JSValueIsUndefined(context, arguments[0]) || JSValueIsNull(context, arguments[0])) {
153                                 LoggerD("Null or undefined case.");
154             } else if (JSValueIsObject(context, arguments[0])) {
155                 event = converter.toItem(arguments[0], false);
156                 if (!event) {
157                     ThrowMsg(ConversionException, "Parameter conversion failed.");
158                 }
159             } else {
160                 //ThrowMsg(ConversionException, "Parameter conversion failed.");
161             }
162         } else if (argumentCount>=2) {
163             LoggerI("event stringRepresentation case");
164             std::string eventStr;
165             CalendarEvent::VObjectFormat format = CalendarEvent::UNDEFINED_FORMAT;
166             eventStr = converter.toString(arguments[0]);
167             format = converter.toVObjectFormat(converter.toString(arguments[1]));
168
169                         if (NULL==m_calendar) {
170                                 m_calendar = CalendarFactory::getInstance().createCalendarObject();
171                                 m_calendar->setType(CalendarEvent::EVENT_TYPE);
172                                 LoggerD("Static calendar for event created.");
173                         }
174
175             IEventCreateEventFromStringPtr dplEvent(new IEventCreateEventFromString());
176             dplEvent->setEventString(eventStr);
177             dplEvent->setFormat(format);
178             dplEvent->setForSynchronousCall();
179             m_calendar->createEventFromString(dplEvent);
180
181             // Process the returned object.
182             if (dplEvent->getResult()) {
183                 LoggerI("Successfully created an event.");
184                 event = dplEvent->getEvent();
185             } else {
186                 if (dplEvent->getExceptionCode()==ExceptionCodes::InvalidArgumentException) {
187                     //ThrowMsg(InvalidArgumentException, "Wrong string to convert.");
188                 } else {
189                     //ThrowMsg(UnknownException, "Converting string failed.");
190                 }
191             }
192         }
193
194         event->setCalendarType(CalendarEvent::EVENT_TYPE);
195         return createJSCalendarEvent(globalContext, event, securityAccessor);
196     }
197     Catch(UnsupportedException)
198     {
199         LoggerW("Exception: "<<_rethrown_exception.GetMessage());
200         //return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, _rethrown_exception.GetMessage());
201     }
202     Catch(InvalidArgumentException)
203     {
204         LoggerW("Exception: "<<_rethrown_exception.GetMessage());
205         //return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, _rethrown_exception.GetMessage());
206     }
207     Catch(ConversionException)
208     {
209         LoggerW("Exception: "<<_rethrown_exception.GetMessage());
210         //return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, _rethrown_exception.GetMessage());
211     }
212     Catch(Exception)
213     {
214         LoggerW("Exception: "<<_rethrown_exception.GetMessage());
215         //return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::UNKNOWN_ERROR, _rethrown_exception.GetMessage());
216     }
217
218     event->setCalendarType(CalendarEvent::EVENT_TYPE);
219     return createJSCalendarEvent(globalContext, event, securityAccessor);
220 }
221
222 JSObjectRef JSCalendarEvent::createJSCalendarEvent(JSContextRef context, CalendarEventPtr event, const DeviceAPI::Common::SecurityAccessor *securityAccessor)
223 {
224     CalendarEventPrivObject *priv = new CalendarEventPrivObject(context, event);
225     priv->copyAceCheckAccessFunction(securityAccessor);
226     return JSObjectMake(context, getClassRef(), priv);
227 }
228
229 const JSClassRef DLL_EXPORT JSCalendarEvent::getClassRef()
230 {
231     if (!m_jsClassRef) {
232         m_jsClassRef = JSClassCreate(&m_classInfo);
233     }
234     return m_jsClassRef;
235 }
236
237 const JSClassDefinition* JSCalendarEvent::getClassInfo()
238 {
239     return &m_classInfo;
240 }
241
242 CalendarEventPtr JSCalendarEvent::getPrivateObject(JSObjectRef object)
243 {
244     CalendarEventPrivObject *priv =
245         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
246     if (!priv) {
247         ThrowMsg(NullPointerException, "Private object is null");
248     }
249     CalendarEventPtr result = priv->getObject();
250     if (!result) {
251         ThrowMsg(NullPointerException, "Private object is null");
252     }
253     return result;
254 }
255
256 void JSCalendarEvent::setPrivateObject(const CalendarEventPtr &event,
257         JSContextRef ctx,
258         const JSObjectRef object)
259 {
260     Try
261     {
262         CalendarEventPrivObject *priv =
263             static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
264         delete priv;
265         priv = new CalendarEventPrivObject(ctx, event);
266         if (!JSObjectSetPrivate(object, static_cast<void*>(priv))) {
267             delete priv;
268         }
269     }
270     Catch(Exception)
271     {
272         LoggerE("Error during replacing event object");
273     }
274 }
275
276 JSValueRef JSCalendarEvent::expandRecurrence(JSContextRef context,
277         JSObjectRef object,
278         JSObjectRef thisObject,
279         size_t argumentCount,
280         const JSValueRef arguments[],
281         JSValueRef* exception)
282 {
283         TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
284     CalendarEventPrivObject *privateObject =
285         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(thisObject));
286
287     TIZEN_CHECK_ACCESS(context, exception, privateObject, CALENDAR_FUNCTION_API_EXPAND_RECURRENCE);
288
289     Try
290     {
291         if (!privateObject) {
292             ThrowMsg(ConversionException, "Object is null.");
293         }
294
295         CalendarEventPtr event = privateObject->getObject();
296         if (!event) {
297             ThrowMsg(ConversionException, "Parameter conversion failed.");
298         }
299
300         JSContextRef globalContext = GlobalContextManager::getInstance()->getGlobalContext(context);
301         CalendarConverter converter(context);
302
303         std::time_t startDate = 0;
304         std::time_t endDate = INT_MAX; // about 60 years in 4 bytes system.
305         TimeUtilConverter timeConverter(context);
306         if (argumentCount>=1) {
307             if (JSValueIsObjectOfClass(context, arguments[0], JSTZDate::getClassRef())) {
308                 startDate = (long long int) (timeConverter.getTimeInMilliseconds(arguments[0])/1000);
309                 LoggerI("startDate: "<<startDate);
310             } else {
311                 ThrowMsg(ConversionException, "Wrong first parameter type.");
312             }
313         }
314         if (argumentCount>=2) {
315             if (JSValueIsObjectOfClass(context, arguments[1], JSTZDate::getClassRef())) {
316                 endDate = (long long int) (timeConverter.getTimeInMilliseconds(arguments[1])/1000);
317                 LoggerI("endDate: "<<endDate);
318             } else {
319                 ThrowMsg(ConversionException, "Wrong second parameter type.");
320             }
321         }
322
323         JSValueRef onError = argumentCount > 3 ? converter.toFunctionOrNull(arguments[3]) : NULL;
324
325         JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext, NULL, onError);
326
327         Validator validator(context);
328         if (validator.isCallback(arguments[2])) {
329             cbm->setOnSuccess(arguments[2]);
330         } else {
331             ThrowMsg(ConversionException, "Wrong third parameter type.");
332         }
333
334                 cbm->setObject(thisObject);
335
336         LoggerD("Proceed the expand event to the platform.");
337
338         IEventExpandEventRecurrencePtr dplEvent(new IEventExpandEventRecurrence());
339         dplEvent->setPrivateData(DPL::StaticPointerCast<IEventPrivateData>(cbm));
340         dplEvent->setForAsynchronousCall(&CalendarResponseDispatcher::getInstance());
341         dplEvent->setEvent(event);
342         dplEvent->setStartDate(startDate);
343         dplEvent->setEndDate(endDate);
344         dplEvent->copyAceCheckAccessFunction(privateObject);
345         m_calendar->expandEventRecurrence(dplEvent);
346
347                 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
348         return JSValueMakeUndefined(context);
349     }
350     Catch(UnsupportedException)
351     {
352                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
353         return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, _rethrown_exception.GetMessage());
354     }
355     Catch(InvalidArgumentException)
356     {
357                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
358         return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, _rethrown_exception.GetMessage());
359     }
360     Catch(ConversionException)
361     {
362                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
363         return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, _rethrown_exception.GetMessage());
364     }
365     Catch (NotFoundException)
366     {
367                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
368         return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_FOUND_ERROR, _rethrown_exception.GetMessage());
369     }
370     Catch(Exception)
371     {
372                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
373         return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::UNKNOWN_ERROR, _rethrown_exception.GetMessage());
374     }
375 }
376
377 JSValueRef JSCalendarEvent::getPropertyId(JSContextRef context,
378         JSObjectRef object,
379         JSStringRef propertyName,
380         JSValueRef* exception)
381 {
382     Try
383     {
384         CalendarEventPrivObject *privateObject = static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
385         CalendarEventPtr event = privateObject->getObject();
386
387         EventIdPtr eventId( new EventId() );
388
389             if (UNDEFINED_ITEM_ID==event->getId()) {
390             return JSValueMakeNull(context);
391             } else {
392                 eventId->setUId(event->getUId());
393             }
394
395         std::stringstream ss;
396         std::time_t rid = event->getRecurrenceId();
397         ss<<rid;
398         eventId->setRecurrenceId(ss.str());
399         return JSCalendarEventId::createJSCalendarEventId(context, eventId);
400     }
401     Catch(Exception)
402     {
403                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
404     }
405     return JSValueMakeUndefined(context);
406 }
407
408 JSValueRef JSCalendarEvent::getPropertyIsDetached(JSContextRef context,
409         JSObjectRef object,
410         JSStringRef propertyName,
411         JSValueRef* exception)
412 {
413     Try
414     {
415         CalendarEventPtr event = getPrivateObject(object);
416         Converter converter(context);
417         return converter.toJSValueRef(event->getIsDetached());
418     }
419     Catch(Exception)
420     {
421                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
422     }
423     return JSValueMakeUndefined(context);
424 }
425
426 JSValueRef JSCalendarEvent::getPropertyAvailability(JSContextRef context,
427         JSObjectRef object,
428         JSStringRef propertyName,
429         JSValueRef* exception)
430 {
431     Try
432     {
433         CalendarConverter converter(context);
434         CalendarEventPtr event = getPrivateObject(object);
435         std::string availability = converter.toTizenValue(event->getAvailability());
436         return converter.toJSValueRef(availability);
437     }
438     Catch(Exception)
439     {
440                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
441     }
442     return JSValueMakeUndefined(context);
443 }
444
445 bool JSCalendarEvent::setPropertyAvailability(JSContextRef context,
446         JSObjectRef object,
447         JSStringRef propertyName,
448         JSValueRef value,
449         JSValueRef* exception)
450 {
451     CalendarEventPtr event(NULL);
452     Try
453     {
454         event = getPrivateObject(object);
455         CalendarConverter converter(context);
456         CalendarEvent::EventAvailability availability = converter.toEventAvailability(converter.toString(value));
457         event->setAvailability(availability);
458         return true;
459     }
460     Catch(Exception)
461     {
462                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
463     }
464
465     return true;
466 }
467
468 JSValueRef JSCalendarEvent::getPropertyRecurrenceRule(JSContextRef context,
469         JSObjectRef object,
470         JSStringRef propertyName,
471         JSValueRef* exception)
472 {
473     Try
474     {
475         CalendarItemPropertiesPrivObject *priv = static_cast<CalendarItemPropertiesPrivObject*>(JSObjectGetPrivate(object));
476
477         CalendarEventPtr event = getPrivateObject(object);
478         EventRecurrenceRulePtr rrule;
479         if (event->getIsDetached()) {
480             LoggerD("This is a detached event.");
481             return JSValueMakeUndefined(context);
482         } else {
483             rrule = event->getRecurrenceRule();
484         }
485
486                 if (NULL==rrule) {
487                         LogInfo("Null rrule.");
488                         return JSValueMakeNull(context);
489                 } else if (EventRecurrenceRule::NO_RECURRENCE==rrule->getFrequency()) {
490             return JSValueMakeNull(context);
491         } else {
492             return JSCalendarRecurrenceRule::createJSCalendarRecurrenceRule(priv->getContext(), rrule);
493         }
494     }
495     Catch(Exception)
496     {
497                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
498     }
499     return JSValueMakeUndefined(context);
500 }
501
502 bool JSCalendarEvent::setPropertyRecurrenceRule(JSContextRef context,
503         JSObjectRef object,
504         JSStringRef propertyName,
505         JSValueRef value,
506         JSValueRef* exception)
507 {
508     CalendarEventPtr event(NULL);
509     Try
510     {
511         event = getPrivateObject(object);
512         if (event->getIsDetached()) {
513             LoggerW("Can't set the recurrenceRule of a detached event!");
514             DeviceAPI::Common::JSWebAPIErrorFactory::postException(context, exception, DeviceAPI::Common::JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR);
515         }
516
517                 if (JSValueIsNull(context, value)) {
518                         event->getRecurrenceRule()->setFrequency(EventRecurrenceRule::NO_RECURRENCE);
519         } else if (!JSValueIsObjectOfClass(context, value, JSCalendarRecurrenceRule::getClassRef())) {
520             ThrowMsg(ConversionException, "Wrong parameter type.");
521                 } else {
522                 event->setRecurrenceRule(JSCalendarRecurrenceRule::getPrivateObject(JSValueToObject(context, value, NULL)));
523                 }
524         return true;
525     }
526     Catch(Exception)
527     {
528                 LoggerW("Exception: "<<_rethrown_exception.GetMessage());
529     }
530
531     return true;
532 }
533
534 }
535 }