tizen 2.4 release
[framework/context/context-service.git] / src / context_trigger / timer.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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 #include <stdlib.h>
18 #include <time.h>
19 #include <types_internal.h>
20 #include <scope_mutex.h>
21 #include <timer_mgr.h>
22 #include "timer.h"
23 #include "trigger.h"
24 #include "timer_types.h"
25 #include <context_mgr.h>
26
27 #define MAX_HOUR        24
28 #define MAX_DAY         7
29
30 using namespace ctx::timer_manager;
31 static GMutex timer_mutex;
32
33 ctx::trigger_timer::ref_count_array_s::ref_count_array_s()
34 {
35         memset(count, 0, sizeof(int) * MAX_DAY);
36 }
37
38 ctx::trigger_timer::trigger_timer(ctx::context_trigger* tr)
39         : trigger(tr)
40 {
41         submit_trigger_item();
42 }
43
44 ctx::trigger_timer::~trigger_timer()
45 {
46         clear();
47 }
48
49 void ctx::trigger_timer::submit_trigger_item()
50 {
51         context_manager::register_trigger_item(TIMER_EVENT_SUBJECT, OPS_SUBSCRIBE,
52                         "{"
53                                 "\"TimeOfDay\":{\"type\":\"integer\",\"min\":0,\"max\":1439},"
54                                 "\"DayOfWeek\":{\"type\":\"string\",\"values\":[\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\",\"Weekday\",\"Weekend\"]}"
55                         "}",
56                         NULL);
57
58         context_manager::register_trigger_item(TIMER_CONDITION_SUBJECT, OPS_READ,
59                         "{"
60                                 "\"TimeOfDay\":{\"type\":\"integer\",\"min\":0,\"max\":1439},"
61                                 "\"DayOfWeek\":{\"type\":\"string\",\"values\":[\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\",\"Weekday\",\"Weekend\"]},"
62                                 "\"DayOfMonth\":{\"type\":\"integer\",\"min\":1,\"max\":31}"
63                         "}",
64                         NULL);
65
66 }
67
68 int ctx::trigger_timer::merge_day_of_week(int* ref_cnt)
69 {
70         int day_of_week = 0;
71
72         for (int d = 0; d < MAX_DAY; ++d) {
73                 if (ref_cnt[d] > 0) {
74                         day_of_week |= (0x01 << d);
75                 }
76         }
77
78         return day_of_week;
79 }
80
81 bool ctx::trigger_timer::add(int minute, int day_of_week)
82 {
83         IF_FAIL_RETURN_TAG(minute >=0 && minute < 1440 &&
84                         day_of_week > 0 && day_of_week <= timer_manager::EVERYDAY,
85                         false, _E, "Invalid parameter");
86
87         ctx::scope_mutex sm(&timer_mutex);
88
89         ref_count_array_s &ref = ref_count_map[minute];
90
91         for (int d = 0; d < MAX_DAY; ++d) {
92                 if ((day_of_week & (0x01 << d)) != 0) {
93                         ref.count[d] += 1;
94                 }
95         }
96
97         return reset_timer(minute);
98 }
99
100 bool ctx::trigger_timer::remove(int minute, int day_of_week)
101 {
102         IF_FAIL_RETURN_TAG(minute >=0 && minute < 1440 &&
103                         day_of_week > 0 && day_of_week <= timer_manager::EVERYDAY,
104                         false, _E, "Invalid parameter");
105
106         ctx::scope_mutex sm(&timer_mutex);
107
108         ref_count_array_s &ref = ref_count_map[minute];
109
110         for (int d = 0; d < MAX_DAY; ++d) {
111                 if ((day_of_week & (0x01 << d)) != 0 && ref.count[d] > 0) {
112                         ref.count[d] -= 1;
113                 }
114         }
115
116         return reset_timer(minute);
117 }
118
119 bool ctx::trigger_timer::reset_timer(int minute)
120 {
121         int day_of_week = merge_day_of_week(ref_count_map[minute].count);
122         timer_state_s &timer = timer_state_map[minute];
123
124         if (day_of_week == timer.day_of_week) {
125                 /* Necessary timers are already running... */
126                 return true;
127         }
128
129         if (day_of_week == 0 && timer.timer_id > 0) {
130                 /* Turn off the timer at hour, if it is not necessray anymore. */
131                 timer_manager::remove(timer.timer_id);
132                 timer_state_map.erase(minute);
133                 ref_count_map.erase(minute);
134                 return true;
135         }
136
137         if (timer.timer_id > 0) {
138                 /* Turn off the current timer, to set a new one. */
139                 timer_manager::remove(timer.timer_id);
140                 timer.timer_id = -1;
141                 timer.day_of_week = 0;
142         }
143
144         /* Create a new timer, w.r.t. the new day_of_week value. */
145         int h = minute / 60;
146         int m = minute - h * 60;
147         int tid = timer_manager::set_at(h, m, day_of_week, this);
148         IF_FAIL_RETURN_TAG(tid > 0, false, _E, "Timer setting failed");
149
150         timer.timer_id = tid;
151         timer.day_of_week = day_of_week;
152
153         return true;
154 }
155
156 void ctx::trigger_timer::clear()
157 {
158         ctx::scope_mutex sm(&timer_mutex);
159
160         for (timer_state_map_t::iterator it = timer_state_map.begin(); it != timer_state_map.end(); ++it) {
161                 if (it->second.timer_id > 0) {
162                         timer_manager::remove(it->second.timer_id);
163                 }
164         }
165
166         timer_state_map.clear();
167         ref_count_map.clear();
168 }
169
170 bool ctx::trigger_timer::on_timer_expired(int timer_id, void* user_data)
171 {
172         time_t rawtime;
173         struct tm timeinfo;
174
175         time(&rawtime);
176         tzset();
177         localtime_r(&rawtime, &timeinfo);
178
179         int hour = timeinfo.tm_hour;
180         int min = timeinfo.tm_min;
181         int day_of_week = (0x01 << timeinfo.tm_wday);
182
183         on_timer_expired(hour, min, day_of_week);
184
185         return true;
186 }
187
188 void ctx::trigger_timer::on_timer_expired(int hour, int min, int day_of_week)
189 {
190         _I("Time: %02d:%02d, Day of Week: %#x", hour, min, day_of_week);
191
192         ctx::json result;
193         result.set(NULL, TIMER_RESPONSE_KEY_TIME_OF_DAY, hour * 60 + min);
194         result.set(NULL, TIMER_RESPONSE_KEY_DAY_OF_WEEK, convert_day_of_week_to_string(day_of_week));
195
196         ctx::json dummy = NULL;
197         trigger->push_fact(TIMER_EVENT_REQ_ID, ERR_NONE, TIMER_EVENT_SUBJECT, dummy, result);
198 }
199
200 int ctx::trigger_timer::get_day_of_month()
201 {
202         time_t rawtime;
203         struct tm timeinfo;
204
205         time(&rawtime);
206         tzset();
207         localtime_r(&rawtime, &timeinfo);
208
209         int day_of_month = timeinfo.tm_mday;
210
211         return day_of_month;
212 }
213
214 std::string ctx::trigger_timer::get_day_of_week()
215 {
216         time_t rawtime;
217         struct tm timeinfo;
218
219         time(&rawtime);
220         tzset();
221         localtime_r(&rawtime, &timeinfo);
222
223         int day_of_week = (0x01 << timeinfo.tm_wday);
224
225         return convert_day_of_week_to_string(day_of_week);
226 }
227
228 int ctx::trigger_timer::get_minute_of_day()
229 {
230         time_t rawtime;
231         struct tm timeinfo;
232
233         time(&rawtime);
234         tzset();
235         localtime_r(&rawtime, &timeinfo);
236
237         int hour = timeinfo.tm_hour;
238         int minute = timeinfo.tm_min;
239
240         return hour * 60 + minute;
241 }
242
243 int ctx::trigger_timer::convert_string_to_day_of_week(std::string d)
244 {
245         int day = 0;
246         d = d.substr(1, d.length() - 2);
247
248         if (d.compare(TIMER_SUN) == 0) {
249                 day = SUN;
250         } else if (d.compare(TIMER_MON) == 0) {
251                 day = MON;
252         } else if (d.compare(TIMER_TUE) == 0) {
253                 day = TUE;
254         } else if (d.compare(TIMER_WED) == 0) {
255                 day = WED;
256         } else if (d.compare(TIMER_THU) == 0) {
257                 day = THU;
258         } else if (d.compare(TIMER_FRI) == 0) {
259                 day = FRI;
260         } else if (d.compare(TIMER_SAT) == 0) {
261                 day = SAT;
262         } else if (d.compare(TIMER_WEEKDAY) == 0) {
263                 day = WEEKDAY;
264         } else if (d.compare(TIMER_WEEKEND) == 0) {
265                 day = WEEKEND;
266         } else if (d.compare(TIMER_EVERYDAY) == 0) {
267                 day = EVERYDAY;
268         }
269
270         return day;
271 }
272
273 std::string ctx::trigger_timer::convert_day_of_week_to_string(int d)
274 {
275         std::string day;
276
277         if (d == SUN) {
278                 day = TIMER_SUN;
279         } else if (d == MON) {
280                 day = TIMER_MON;
281         } else if (d == TUE) {
282                 day = TIMER_TUE;
283         } else if (d == WED) {
284                 day = TIMER_WED;
285         } else if (d == THU) {
286                 day = TIMER_THU;
287         } else if (d == FRI) {
288                 day = TIMER_FRI;
289         } else if (d == SAT) {
290                 day = TIMER_SAT;
291         } else if (d == WEEKDAY) {
292                 day = TIMER_WEEKDAY;
293         } else if (d == WEEKEND) {
294                 day = TIMER_WEEKEND;
295         } else if (d == EVERYDAY) {
296                 day = TIMER_EVERYDAY;
297         }
298
299         return day;
300 }
301
302 bool ctx::trigger_timer::empty()
303 {
304         return timer_state_map.empty();
305 }