merge wrt-plugins-tizen_0.2.0-8
[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 "JSCalendarEvent.h"
27 #include "JSCalendarItemProperties.h"
28 #include "CalendarConverter.h"
29 #include "JSCalendarEventId.h"
30 #include "plugin_config.h"
31 #include "CalendarResponseDispatcher.h"
32 #include <Tizen/TimeUtil/TimeUtilConverter.h>
33 #include <Tizen/TimeUtil/JSTZDate.h>
34 #include <Tizen/Common/JSTizenException.h>
35 #include <Tizen/Common/JSTizenExceptionFactory.h>
36 #include <Tizen/Common/SecurityExceptions.h>
37
38 using namespace TizenApis::Api::Calendar;
39 using namespace WrtDeviceApis::Commons;
40 using namespace WrtDeviceApis::CommonsJavaScript;
41 using namespace TizenApis::Commons;
42
43 namespace {
44 /**
45  * @throw InvalidArgumentException If not a callback nor JS null nor JS undefined.
46  */
47 JSValueRef getFunctionOrNull(JSContextRef ctx,
48         JSValueRef arg)
49 {
50     if (Validator(ctx).isCallback(arg)) {
51         return arg;
52     } else if (!JSValueIsNull(ctx, arg) && !JSValueIsUndefined(ctx, arg)) {
53         ThrowMsg(InvalidArgumentException, "Not a function nor JS null.");
54     }
55     return NULL;
56 }
57 }
58
59 namespace TizenApis {
60 namespace Tizen1_0 {
61 namespace Calendar {
62
63 JSClassDefinition JSCalendarEvent::m_classInfo = {
64     0,
65     kJSClassAttributeNone,
66     TIZEN_INTERFACE_CALENDAR_EVENT,
67     JSCalendarItemProperties::getClassRef(),
68     m_property,
69     m_function,
70     initialize,
71     finalize,
72     NULL, //hasProperty,
73     NULL, //getProperty,
74     NULL, //setProperty,
75     NULL, //DeleteProperty,
76     NULL, //GetPropertyNames,
77     NULL, //CallAsFunction,
78     constructor,
79     NULL, //HasInstance,
80     NULL  //ConvertToType
81 };
82
83 JSStaticValue JSCalendarEvent::m_property[] = {
84     { TIZEN_CALENDAR_EVENT_ID, getPropertyId,
85       NULL, kJSPropertyAttributeReadOnly },
86     { TIZEN_CALENDAR_EVENT_LAST_MODIFICATION_DATE, getPropertyLastModificationDate,
87       NULL, kJSPropertyAttributeReadOnly },
88     { TIZEN_CALENDAR_EVENT_IS_DETACHED, getPropertyIsDetached,
89       NULL, kJSPropertyAttributeReadOnly },
90
91     { 0, 0, 0, 0 }
92 };
93
94 JSStaticFunction JSCalendarEvent::m_function[] = {
95     { CALENDAR_FUNCTION_API_EXPAND_RECURRENCE, expandRecurrence, kJSPropertyAttributeNone },
96
97     { 0, 0, 0 }
98 };
99
100 JSClassRef JSCalendarEvent::m_jsClassRef = JSClassCreate(JSCalendarEvent::getClassInfo());
101
102 ICalendarPtr JSCalendarEvent::m_calendar = CalendarFactory::getInstance().createCalendarObject();
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     if (!m_calendar) {
120         LogDebug("Calendar object does not exist!");
121     } else {
122         m_calendar->setType(CalendarEvent::EVENT_TYPE);
123         LogDebug("Calendar object type is set.");
124     }
125 }
126
127 void JSCalendarEvent::finalize(JSObjectRef object)
128 {
129     LogDebug("entered");
130 }
131
132 JSObjectRef JSCalendarEvent::constructor(JSContextRef context,
133     JSObjectRef constructor,
134     size_t argumentCount,
135     const JSValueRef arguments[],
136     JSValueRef* exception)
137 {
138         LogDebug("entered");
139
140     Try
141     {
142                 CalendarEventPrivObject* privateObject = static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(constructor));
143                 JSContextRef globalContext = privateObject ? privateObject->getContext() : context;
144
145         CalendarConverter converter(globalContext);
146         CalendarEventPtr event;
147
148         if (argumentCount==0) {
149             CalendarEventPtr result(new CalendarEvent());
150             event = result;
151         } else if (argumentCount==1) { // eventInitDict case
152             event = converter.toEvent(arguments[0]);
153             if (!event) {
154                 ThrowMsg(ConversionException, "Parameter conversion failed.");
155             }
156         } else if (argumentCount==2) { // stringRepresentation case
157             if (!JSValueIsString(context, arguments[0]) || !JSValueIsString(context, arguments[1])) {
158                 ThrowMsg(ConversionException, "Wrong parameter type.");
159             }
160
161             std::string eventStr;
162             CalendarEvent::VObjectFormat format = CalendarEvent::ICALENDAR_20;
163             eventStr = converter.toString(arguments[0]);
164             format = converter.toVObjectFormat(converter.toString(arguments[1]));
165
166             IEventCreateEventFromStringPtr dplEvent(new IEventCreateEventFromString());
167             dplEvent->setEventString(eventStr);
168             dplEvent->setFormat(format);
169             dplEvent->setForSynchronousCall();
170             m_calendar->createEventFromString(dplEvent);
171
172             // Process the returned object.
173             if (dplEvent->getResult()) {
174                 LogInfo("Successfully created an item.");
175                 event = dplEvent->getEvent();
176             } else {
177                 ThrowMsg(UnknownException, "Converting from string failed by unkown reason.");
178             }
179         } else {
180             ThrowMsg(InvalidArgumentException, "Wrong number of parameters.");
181         }
182
183         return createJSCalendarEvent(globalContext, event);
184     }
185     Catch(UnsupportedException)
186     {
187         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
188         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::NOT_SUPPORTED_ERROR, _rethrown_exception.GetMessage());
189     }
190     Catch(InvalidArgumentException)
191     {
192         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
193         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, _rethrown_exception.GetMessage());
194     }
195     Catch(ConversionException)
196     {
197         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
198         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::TYPE_MISMATCH_ERROR, _rethrown_exception.GetMessage());
199     }
200     Catch(Exception)
201     {
202         LogWarning("Exception: "<<_rethrown_exception.GetMessage());
203         *exception = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, _rethrown_exception.GetMessage());
204     }
205
206     return NULL;
207 }
208
209 JSObjectRef JSCalendarEvent::createJSCalendarEvent(JSContextRef context, CalendarEventPtr event)
210 {
211     CalendarEventPrivObject *priv = new CalendarEventPrivObject(context, event);
212     return JSObjectMake(context, getClassRef(), priv);
213 }
214
215 const JSClassRef JSCalendarEvent::getClassRef()
216 {
217     if (!m_jsClassRef) {
218         m_jsClassRef = JSClassCreate(&m_classInfo);
219     }
220     return m_jsClassRef;
221 }
222
223 const JSClassDefinition* JSCalendarEvent::getClassInfo()
224 {
225     return &m_classInfo;
226 }
227
228 CalendarEventPtr JSCalendarEvent::getPrivateObject(JSObjectRef object)
229 {
230     LogDebug("entered");
231     CalendarEventPrivObject *priv =
232         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
233     if (!priv) {
234         ThrowMsg(NullPointerException, "Private object is null");
235     }
236     CalendarEventPtr result = priv->getObject();
237     if (!result) {
238         ThrowMsg(NullPointerException, "Private object is null");
239     }
240     return result;
241 }
242
243 void JSCalendarEvent::setPrivateObject(const CalendarEventPtr &event,
244         JSContextRef ctx,
245         const JSObjectRef object)
246 {
247     LogDebug("entered");
248     Try
249     {
250         CalendarEventPrivObject *priv =
251             static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
252         delete priv;
253         priv = new CalendarEventPrivObject(ctx, event);
254         if (!JSObjectSetPrivate(object, static_cast<void*>(priv))) {
255             delete priv;
256         }
257     }
258     Catch(Exception)
259     {
260         LogError("Error during replacing event object");
261     }
262 }
263
264 JSValueRef JSCalendarEvent::expandRecurrence(JSContextRef context,
265         JSObjectRef object,
266         JSObjectRef thisObject,
267         size_t argumentCount,
268         const JSValueRef arguments[],
269         JSValueRef* exception)
270 {
271     LogDebug("entered");
272     CalendarEventPrivObject *privateObject =
273         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(thisObject));
274     assert(privateObject);
275
276     AceSecurityStatus status = CALENDAR_CHECK_ACCESS(privateObject->getContext(), CALENDAR_FUNCTION_API_EXPAND_RECURRENCE);
277
278     TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
279
280     JSCallbackManagerPtr cbm(NULL);
281
282     Try
283     {
284         if (argumentCount<3 || argumentCount>4) {
285             ThrowMsg(InvalidArgumentException, "Wrong number of parameters.");
286         }
287
288         CalendarEventPtr event = privateObject->getObject();
289         if (!event) {
290             ThrowMsg(ConversionException, "Parameter conversion failed.");
291         }
292
293         JSValueRef onError =(argumentCount > 3 ? getFunctionOrNull(context, arguments[3]) : NULL);
294         JSContextRef globalContext = privateObject->getContext();
295         cbm = JSCallbackManager::createObject(globalContext, NULL, onError);
296
297         Validator validator(context);
298         if (validator.isCallback(arguments[2])) {
299             cbm->setOnSuccess(arguments[2]);
300         } else if (JSValueIsNull(context, arguments[2]) || JSValueIsUndefined(context, arguments[2])) {
301             ThrowMsg(ConversionException, "Wrong parameter type.");
302         } else {
303             ThrowMsg(ConversionException, "Wrong parameter type.");
304         }
305
306         std::time_t startDate = 0;
307         std::time_t endDate = INT_MAX; // about 60 years in 4 bytes system.
308         Converter converter(context);
309         TimeUtilConverter timeConverter(context);
310         if (JSValueIsObjectOfClass(context, arguments[0], JSTZDate::getClassRef())) {
311             startDate = timeConverter.toTZDateTimeT(arguments[0]);
312         } else {
313             ThrowMsg(ConversionException, "Wrong first parameter type.");
314         }
315         if (JSValueIsObjectOfClass(context, arguments[1], JSTZDate::getClassRef())) {
316             endDate = timeConverter.toDateTimeT(arguments[1]);
317         } else {
318             ThrowMsg(ConversionException, "Wrong second parameter type.");
319         }
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         return JSValueMakeUndefined(context);
330     }
331     Catch(UnsupportedException)
332     {
333                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
334         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, _rethrown_exception.GetMessage());
335     }
336     Catch(InvalidArgumentException)
337     {
338                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
339         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::INVALID_VALUES_ERROR, _rethrown_exception.GetMessage());
340     }
341     Catch(ConversionException)
342     {
343                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
344         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, _rethrown_exception.GetMessage());
345     }
346     Catch (NotFoundException)
347     {
348                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
349         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_FOUND_ERROR, _rethrown_exception.GetMessage());
350     }
351     Catch(Exception)
352     {
353                 LogWarning("Exception: "<<_rethrown_exception.GetMessage());
354         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::UNKNOWN_ERROR, _rethrown_exception.GetMessage());
355     }
356
357     return JSValueMakeUndefined(context);
358 }
359
360 JSValueRef JSCalendarEvent::getPropertyId(JSContextRef context,
361         JSObjectRef object,
362         JSStringRef propertyName,
363         JSValueRef* exception)
364 {
365     LogDebug("entered");
366     Try
367     {
368         CalendarEventPrivObject *privateObject =
369             static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
370         CalendarEventPtr event = privateObject->getObject();
371
372         EventIdPtr eventId( new EventId() );
373         eventId->setUId(event->getUId());
374         eventId->setRecurrenceId(event->getRecurrenceId());
375         eventId->setTimeZone(event->getTimeZone());
376         return JSCalendarEventId::createJSCalendarEventId(privateObject->getContext(), eventId);
377     }
378     Catch(Exception)
379     {
380         LogWarning("trying to get incorrect value");
381     }
382     return JSValueMakeUndefined(context);
383 }
384
385 JSValueRef JSCalendarEvent::getPropertyLastModificationDate(JSContextRef context,
386         JSObjectRef object,
387         JSStringRef propertyName,
388         JSValueRef* exception)
389 {
390     LogDebug("entered");
391     Try
392     {
393         CalendarEventPrivObject *privateObject =
394             static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
395         CalendarEventPtr event = privateObject->getObject();
396
397         if (!event) {
398             Throw(NullPointerException);
399         }
400         if (event->getLastModifiedDate() != 0) {
401             // Use the global context saved in the event struct.
402             return JSTZDate::createJSObject(privateObject->getContext(), event->getLastModifiedDate(), event->getTimeZone());
403         } else {
404             return JSValueMakeUndefined(context);
405         }
406     }
407     Catch(Exception)
408     {
409         LogWarning("trying to get incorrect value");
410     }
411     return JSValueMakeUndefined(context);
412 }
413
414 JSValueRef JSCalendarEvent::getPropertyIsDetached(JSContextRef context,
415         JSObjectRef object,
416         JSStringRef propertyName,
417         JSValueRef* exception)
418 {
419     LogDebug("entered");
420     Try
421     {
422         CalendarEventPtr event = getPrivateObject(object);
423         if(CalendarEvent::EVENT_TYPE != event->getCalendarType()) {
424             return JSValueMakeUndefined(context);
425         }
426
427         Converter converter(context);
428         return converter.toJSValueRef(event->getIsDetached());
429     }
430     Catch(Exception)
431     {
432         LogWarning("trying to get incorrect value");
433     }
434     return JSValueMakeUndefined(context);
435 }
436
437 bool JSCalendarEvent::validate(JSContextRef ctx,
438         const JSObjectRef object,
439         JSValueRef* exception)
440 {
441     LogDebug("entered");
442     CalendarEventPrivObject *priv =
443         static_cast<CalendarEventPrivObject*>(JSObjectGetPrivate(object));
444     if (priv == NULL) {
445         return false;
446     }
447     CalendarEventPtr event = priv->getObject();
448     if (!event) {
449         return false;
450     }
451     return event->validate();
452 }
453
454 }
455 }
456 }