Beta merge 2
[profile/ivi/wrt-plugins-tizen.git] / src / standards / Tizen / Calendar / JSCalendarEvent.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <ctime>
19 #include <dpl/log/log.h>
20 #include <CommonsJavaScript/PrivateObject.h>
21 #include <CommonsJavaScript/Converter.h>
22 #include <CommonsJavaScript/JSUtils.h>
23 #include <CommonsJavaScript/Validator.h>
24 #include <CommonsJavaScript/JSCallbackManager.h>
25 #include <API/Calendar/EventId.h>
26 #include <API/Calendar/ICalendar.h>
27 #include <API/Calendar/CalendarFactory.h>
28 #include "JSCalendarEvent.h"
29 #include "JSCalendarItemProperties.h"
30 #include "CalendarConverter.h"
31 #include "JSCalendarEventId.h"
32 #include "plugin_config.h"
33 #include "CalendarResponseDispatcher.h"
34 #include <Tizen/TimeUtil/TimeUtilConverter.h>
35 #include <Tizen/TimeUtil/JSTZDate.h>
36 #include <Tizen/Common/JSTizenException.h>
37 #include <Tizen/Common/JSTizenExceptionFactory.h>
38 #include <Tizen/Common/SecurityExceptions.h>
39
40 using namespace TizenApis::Api::Calendar;
41 using namespace WrtDeviceApis::Commons;
42 using namespace WrtDeviceApis::CommonsJavaScript;
43 using namespace TizenApis::Commons;
44
45 namespace {
46 /**
47  * @throw InvalidArgumentException If not a callback nor JS null nor JS undefined.
48  */
49 JSValueRef getFunctionOrNull(JSContextRef ctx,
50         JSValueRef arg)
51 {
52     if (Validator(ctx).isCallback(arg)) {
53         return arg;
54     } else if (!JSValueIsNull(ctx, arg) && !JSValueIsUndefined(ctx, arg)) {
55         ThrowMsg(InvalidArgumentException, "Not a function nor JS null.");
56     }
57     return NULL;
58 }
59 }
60
61 namespace TizenApis {
62 namespace Tizen1_0 {
63 namespace Calendar {
64
65 JSClassDefinition JSCalendarEvent::m_classInfo = {
66     0,
67     kJSClassAttributeNone,
68     TIZEN_INTERFACE_CALENDAR_EVENT,
69     JSCalendarItemProperties::getClassRef(),
70     m_property,
71     m_function,
72     initialize,
73     finalize,
74     NULL, //hasProperty,
75     NULL, //getProperty,
76     NULL, //setProperty,
77     NULL, //DeleteProperty,
78     NULL, //GetPropertyNames,
79     NULL, //CallAsFunction,
80     constructor,
81     NULL, //HasInstance,
82     NULL  //ConvertToType
83 };
84
85 JSStaticValue JSCalendarEvent::m_property[] = {
86     { TIZEN_CALENDAR_EVENT_ID, getPropertyId,
87       NULL, kJSPropertyAttributeReadOnly },
88     { TIZEN_CALENDAR_EVENT_LAST_MODIFICATION_DATE, getPropertyLastModificationDate,
89       NULL, kJSPropertyAttributeReadOnly },
90     { TIZEN_CALENDAR_EVENT_IS_DETACHED, getPropertyIsDetached,
91       NULL, kJSPropertyAttributeReadOnly },
92
93     { 0, 0, 0, 0 }
94 };
95
96 JSStaticFunction JSCalendarEvent::m_function[] = {
97     { CALENDAR_FUNCTION_API_EXPAND_RECURRENCE, expandRecurrence, kJSPropertyAttributeNone },
98
99     { 0, 0, 0 }
100 };
101
102 JSClassRef JSCalendarEvent::m_jsClassRef = JSClassCreate(JSCalendarEvent::getClassInfo());
103
104 void JSCalendarEvent::initialize(JSContextRef context,
105         JSObjectRef object)
106 {
107     LogDebug("entered");
108     CalendarEventPrivObject *priv =
109         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
110     if (!priv) {
111         CalendarEventPtr privateData(new CalendarEvent());
112         priv = new CalendarEventPrivObject(context, privateData);
113         JSObjectSetPrivate(object, static_cast<void*>(priv));
114         LogDebug("new event is created");
115     } else {
116         LogDebug("private object already exists");
117     }
118 }
119
120 void JSCalendarEvent::finalize(JSObjectRef object)
121 {
122     LogDebug("entered");
123 }
124
125 JSObjectRef JSCalendarEvent::constructor(JSContextRef context,
126     JSObjectRef constructor,
127     size_t argumentCount,
128     const JSValueRef arguments[],
129     JSValueRef* exception)
130 {
131         LogDebug("entered");
132
133     Try
134     {
135                 CalendarEventPrivObject* privateObject = static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(constructor));
136                 JSContextRef globalContext = privateObject ? privateObject->getContext() : context;
137
138         CalendarConverter converter(globalContext);
139         CalendarEventPtr event;
140
141         if (argumentCount==0) {
142             CalendarEventPtr result(new CalendarEvent());
143             event = result;
144         } else if (argumentCount==1) { // eventInitDict case
145             event = converter.toEvent(arguments[0]);
146             if (!event) {
147                 ThrowMsg(ConversionException, "Parameter conversion failed.");
148             }
149         } else if (argumentCount==2) { // stringRepresentation case
150             if (!JSValueIsString(context, arguments[0]) || !JSValueIsString(context, arguments[1])) {
151                 ThrowMsg(ConversionException, "Wrong parameter type.");
152             }
153
154             std::string eventStr;
155             CalendarEvent::VObjectFormat format = CalendarEvent::ICALENDAR_20;
156             eventStr = converter.toString(arguments[0]);
157             format = converter.toVObjectFormat(converter.toString(arguments[1]));
158
159             ICalendarPtr calendar = CalendarFactory::getInstance().createCalendarObject();
160             calendar->setType(CalendarEvent::EVENT_TYPE);
161
162             IEventCreateEventFromStringPtr dplEvent(new IEventCreateEventFromString());
163             dplEvent->setEventString(eventStr);
164             dplEvent->setFormat(format);
165             dplEvent->setForSynchronousCall();
166             calendar->createEventFromString(dplEvent);
167
168             // Process the returned object.
169             if (dplEvent->getResult()) {
170                 LogInfo("Successfully created an item.");
171                 event = dplEvent->getEvent();
172             } else {
173                 ThrowMsg(UnknownException, "Converting from string failed by unkown reason.");
174             }
175         } else {
176             ThrowMsg(InvalidArgumentException, "Wrong number of parameters.");
177         }
178
179         return createJSCalendarEvent(globalContext, event);
180     }
181     Catch(UnsupportedException)
182     {
183         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
184         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::NOT_SUPPORTED_ERROR, _rethrown_exception.GetMessage());
185     }
186     Catch(InvalidArgumentException)
187     {
188         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
189         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, _rethrown_exception.GetMessage());
190     }
191     Catch(ConversionException)
192     {
193         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
194         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::TYPE_MISMATCH_ERROR, _rethrown_exception.GetMessage());
195     }
196     Catch(Exception)
197     {
198         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
199         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, _rethrown_exception.GetMessage());
200     }
201
202     return NULL;
203 }
204
205 JSObjectRef JSCalendarEvent::createJSCalendarEvent(JSContextRef context, CalendarEventPtr event)
206 {
207     CalendarEventPrivObject *priv = new CalendarEventPrivObject(context, event);
208     return JSObjectMake(context, getClassRef(), priv);
209 }
210
211 const JSClassRef JSCalendarEvent::getClassRef()
212 {
213     if (!m_jsClassRef) {
214         m_jsClassRef = JSClassCreate(&m_classInfo);
215     }
216     return m_jsClassRef;
217 }
218
219 const JSClassDefinition* JSCalendarEvent::getClassInfo()
220 {
221     return &m_classInfo;
222 }
223
224 CalendarEventPtr JSCalendarEvent::getPrivateObject(JSObjectRef object)
225 {
226     LogDebug("entered");
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     LogDebug("entered");
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         LogError("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     LogDebug("entered");
268     CalendarEventPrivObject *privateObject =
269         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(thisObject));
270     assert(privateObject);
271
272     AceSecurityStatus status = CALENDAR_CHECK_ACCESS(privateObject->getContext(), CALENDAR_FUNCTION_API_EXPAND_RECURRENCE);
273
274     TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
275
276     JSCallbackManagerPtr cbm(NULL);
277
278     Try
279     {
280         if (argumentCount<3 || argumentCount>4) {
281             ThrowMsg(InvalidArgumentException, "Wrong number of parameters.");
282         }
283
284         CalendarEventPtr event = privateObject->getObject();
285         if (!event) {
286             ThrowMsg(ConversionException, "Parameter conversion failed.");
287         }
288
289         JSValueRef onError =(argumentCount > 3 ? getFunctionOrNull(context, arguments[3]) : NULL);
290         JSContextRef globalContext = privateObject->getContext();
291         cbm = JSCallbackManager::createObject(globalContext, NULL, onError);
292
293         Validator validator(context);
294         if (validator.isCallback(arguments[2])) {
295             cbm->setOnSuccess(arguments[2]);
296         } else if (JSValueIsNull(context, arguments[2]) || JSValueIsUndefined(context, arguments[2])) {
297             ThrowMsg(ConversionException, "Wrong parameter type.");
298         } else {
299             ThrowMsg(ConversionException, "Wrong parameter type.");
300         }
301
302         std::time_t startDate = 0;
303         std::time_t endDate = INT_MAX; // about 60 years in 4 bytes system.
304         Converter converter(context);
305         TimeUtilConverter timeConverter(context);
306         if (argumentCount>0 ) {
307             startDate = timeConverter.toTZDateTimeT(arguments[0]);
308         }
309         if (argumentCount>1 ) {
310             endDate = timeConverter.toDateTimeT(arguments[1]);
311         }
312
313         ICalendarPtr calendar = CalendarFactory::getInstance().createCalendarObject();
314         calendar->setType(event->getCalendarType());
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         calendar->expandEventRecurrence(dplEvent);
323
324         return JSValueMakeNull(context);
325     }
326     Catch(UnsupportedException)
327     {
328                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
329         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, _rethrown_exception.GetMessage());
330     }
331     Catch(InvalidArgumentException)
332     {
333                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
334         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::INVALID_VALUES_ERROR, _rethrown_exception.GetMessage());
335     }
336     Catch(ConversionException)
337     {
338                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
339         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, _rethrown_exception.GetMessage());
340     }
341     Catch (NotFoundException)
342     {
343                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
344         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_FOUND_ERROR, _rethrown_exception.GetMessage());
345     }
346     Catch(Exception)
347     {
348                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
349         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::UNKNOWN_ERROR, _rethrown_exception.GetMessage());
350     }
351
352     return JSValueMakeNull(context);
353 }
354
355 JSValueRef JSCalendarEvent::getPropertyId(JSContextRef context,
356         JSObjectRef object,
357         JSStringRef propertyName,
358         JSValueRef* exception)
359 {
360     LogDebug("entered");
361     Try
362     {
363         CalendarEventPrivObject *privateObject =
364             static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
365         CalendarEventPtr event = privateObject->getObject();
366
367         EventIdPtr eventId( new EventId() );
368         eventId->setUId(event->getUId());
369         eventId->setRecurrenceId(event->getRecurrenceId());
370         eventId->setTimeZone(event->getTimeZone());
371         return JSCalendarEventId::createJSCalendarEventId(privateObject->getContext(), eventId);
372     }
373     Catch(Exception)
374     {
375         LogWarning("trying to get incorrect value");
376     }
377     return JSValueMakeUndefined(context);
378 }
379
380 JSValueRef JSCalendarEvent::getPropertyLastModificationDate(JSContextRef context,
381         JSObjectRef object,
382         JSStringRef propertyName,
383         JSValueRef* exception)
384 {
385     LogDebug("entered");
386     Try
387     {
388         CalendarEventPrivObject *privateObject =
389             static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
390         CalendarEventPtr event = privateObject->getObject();
391
392         if (!event) {
393             Throw(NullPointerException);
394         }
395         if (event->getLastModifiedDate() != 0) {
396             // Use the global context saved in the event struct.
397             return JSTZDate::createJSObject(privateObject->getContext(), event->getLastModifiedDate(), event->getTimeZone());
398         } else {
399             return JSValueMakeUndefined(context);
400         }
401     }
402     Catch(Exception)
403     {
404         LogWarning("trying to get incorrect value");
405     }
406     return JSValueMakeUndefined(context);
407 }
408
409 JSValueRef JSCalendarEvent::getPropertyIsDetached(JSContextRef context,
410         JSObjectRef object,
411         JSStringRef propertyName,
412         JSValueRef* exception)
413 {
414     LogDebug("entered");
415     Try
416     {
417         CalendarEventPtr event = getPrivateObject(object);
418         if(CalendarEvent::EVENT_TYPE != event->getCalendarType()) {
419             return JSValueMakeUndefined(context);
420         }
421
422         Converter converter(context);
423         return converter.toJSValueRef(event->getIsDetached());
424     }
425     Catch(Exception)
426     {
427         LogWarning("trying to get incorrect value");
428     }
429     return JSValueMakeUndefined(context);
430 }
431
432 bool JSCalendarEvent::validate(JSContextRef ctx,
433         const JSObjectRef object,
434         JSValueRef* exception)
435 {
436     LogDebug("entered");
437     CalendarEventPrivObject *priv =
438         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
439     if (priv == NULL) {
440         return false;
441     }
442     CalendarEventPtr event = priv->getObject();
443     if (!event) {
444         return false;
445     }
446     return event->validate();
447 }
448
449 }
450 }
451 }