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