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