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