Update change log and spec for wrt-plugins-tizen_0.4.13
[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
19 #include <ctime>
20 #include <dpl/log/log.h>
21 #include <CommonsJavaScript/PrivateObject.h>
22 #include <CommonsJavaScript/Converter.h>
23 #include <CommonsJavaScript/JSUtils.h>
24 #include <CommonsJavaScript/Utils.h>
25 #include <CommonsJavaScript/Validator.h>
26 #include <CommonsJavaScript/JSCallbackManager.h>
27 #include "EventId.h"
28 #include "JSCalendarEvent.h"
29 #include "JSCalendarItemProperties.h"
30 #include "CalendarConverter.h"
31 #include "JSCalendarEventId.h"
32 #include "JSCalendarRecurrenceRule.h"
33 #include "plugin_config.h"
34 #include "CalendarResponseDispatcher.h"
35 #include <TimeUtilConverter.h>
36 #include <JSTZDate.h>
37 #include <JSTizenException.h>
38 #include <JSTizenExceptionFactory.h>
39 #include <SecurityExceptions.h>
40
41 #include "CalendarAsyncCallbackManager.h"
42 #include <GlobalContextManager.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     constructor,
68     NULL, //HasInstance,
69     NULL  //ConvertToType
70 };
71
72 JSStaticValue JSCalendarEvent::m_property[] = {
73     { TIZEN_CALENDAR_EVENT_ID, getPropertyId, NULL, kJSPropertyAttributeReadOnly },
74     { TIZEN_CALENDAR_EVENT_IS_DETACHED, getPropertyIsDetached, NULL, kJSPropertyAttributeReadOnly },
75     { TIZEN_CALENDAR_EVENT_RECURRENCE_RULE, getPropertyRecurrenceRule, setPropertyRecurrenceRule, kJSPropertyAttributeNone },
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         LogDebug("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         LogDebug("Private object already set.");
102     }
103
104     if (m_calendar) {
105         m_calendar->setType(CalendarEvent::EVENT_TYPE);
106         LogDebug("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 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             LogInfo("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             LogInfo("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                 LogInfo("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         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
179         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::NOT_SUPPORTED_ERROR, _rethrown_exception.GetMessage());
180     }
181     Catch(InvalidArgumentException)
182     {
183         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
184         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, _rethrown_exception.GetMessage());
185     }
186     Catch(ConversionException)
187     {
188         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
189         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::TYPE_MISMATCH_ERROR, _rethrown_exception.GetMessage());
190     }
191     Catch(Exception)
192     {
193         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
194         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, _rethrown_exception.GetMessage());
195     }
196
197     return NULL;
198 }
199
200 JSObjectRef JSCalendarEvent::createJSCalendarEvent(JSContextRef context, CalendarEventPtr event)
201 {
202     CalendarEventPrivObject *priv = new CalendarEventPrivObject(context, event);
203     return JSObjectMake(context, getClassRef(), priv);
204 }
205
206 const JSClassRef JSCalendarEvent::getClassRef()
207 {
208     if (!m_jsClassRef) {
209         m_jsClassRef = JSClassCreate(&m_classInfo);
210     }
211     return m_jsClassRef;
212 }
213
214 const JSClassDefinition* JSCalendarEvent::getClassInfo()
215 {
216     return &m_classInfo;
217 }
218
219 CalendarEventPtr JSCalendarEvent::getPrivateObject(JSObjectRef object)
220 {
221     CalendarEventPrivObject *priv =
222         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
223     if (!priv) {
224         ThrowMsg(NullPointerException, "Private object is null");
225     }
226     CalendarEventPtr result = priv->getObject();
227     if (!result) {
228         ThrowMsg(NullPointerException, "Private object is null");
229     }
230     return result;
231 }
232
233 void JSCalendarEvent::setPrivateObject(const CalendarEventPtr &event,
234         JSContextRef ctx,
235         const JSObjectRef object)
236 {
237     Try
238     {
239         CalendarEventPrivObject *priv =
240             static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
241         delete priv;
242         priv = new CalendarEventPrivObject(ctx, event);
243         if (!JSObjectSetPrivate(object, static_cast<void*>(priv))) {
244             delete priv;
245         }
246     }
247     Catch(Exception)
248     {
249         LogError("Error during replacing event object");
250     }
251 }
252
253 JSValueRef JSCalendarEvent::expandRecurrence(JSContextRef context,
254         JSObjectRef object,
255         JSObjectRef thisObject,
256         size_t argumentCount,
257         const JSValueRef arguments[],
258         JSValueRef* exception)
259 {
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                 LogInfo("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                 LogInfo("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         LogDebug("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
326         return JSValueMakeUndefined(context);
327     }
328     Catch(UnsupportedException)
329     {
330                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
331         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, _rethrown_exception.GetMessage());
332     }
333     Catch(InvalidArgumentException)
334     {
335                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
336         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::INVALID_VALUES_ERROR, _rethrown_exception.GetMessage());
337     }
338     Catch(ConversionException)
339     {
340                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
341         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, _rethrown_exception.GetMessage());
342     }
343     Catch (NotFoundException)
344     {
345                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
346         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_FOUND_ERROR, _rethrown_exception.GetMessage());
347     }
348     Catch(Exception)
349     {
350                 LogWarning("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                 LogWarning("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                 LogWarning("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             LogDebug("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                 LogWarning("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             LogWarning("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                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
470         DeviceAPI::Common::JSTizenExceptionFactory::postException(context, exception, DeviceAPI::Common::JSTizenException::TYPE_MISMATCH_ERROR);
471     }
472
473     return false;
474 }
475
476 }
477 }