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