3 * Copyright 2012 Samsung Electronics Co., Ltd
5 * Licensed under the Flora License, Version 1.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
9 * http://floralicense.org/license/
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.
18 #include "month-data.h"
20 #include "list-data.h"
22 #define CAL_MONTH_CALENDAR_LAST_LINE_POS_INDEX 41
27 cal_month_calendar_event* event_table[WEEKS_OF_MONTH][DAYS_OF_WEEK][CAL_MONTH_MAX_ROWS_PER_CELL];
28 int count_table[WEEKS_OF_MONTH][DAYS_OF_WEEK];
29 struct tm grid_start_date;
30 struct tm grid_end_date;
33 cal_month_data_h cal_month_data_create(struct appdata *ad, int rows_per_cell)
35 c_retv_if(ad == NULL, NULL);
37 cal_month_data_s* p = calloc(1, sizeof(cal_month_data_s));
39 p->rows_per_cell = rows_per_cell;
43 int cal_month_data_get_day_time_by_pos(struct appdata *ad,
44 int pos_today, int pos_selected, int pos_start, int pos_end,
45 int *first_day, int *last_day, struct tm *start_time, struct tm *end_time, int day_pos)
56 day = CAL_MONTH_CALENDAR_LAST_LINE_POS_INDEX <= day_pos ? pos_end : day_pos;
57 } else if (-1 == pos_selected) {
64 today = day - pos_start + 1;
65 start_day = day - (day_tmp % DAYS_OF_WEEK) + 1;
67 if (day < DAYS_OF_WEEK) {
69 *last_day = DAYS_OF_WEEK - pos_start;
70 } else if (0 == (day_tmp % DAYS_OF_WEEK)) {
71 *first_day = today - DAYS_OF_WEEK + 1;
74 *first_day = today - (day % DAYS_OF_WEEK);
75 if (pos_end < (start_day + DAYS_OF_WEEK - 1))
76 *last_day = pos_end - pos_start + 1;
78 *last_day = *first_day + DAYS_OF_WEEK - 1;
81 *start_time = ad->base_tm;
82 start_time->tm_mday = *first_day;
83 start_time->tm_hour = 0;
84 start_time->tm_min = 0;
85 start_time->tm_sec = 0;
87 *end_time = ad->base_tm;
88 end_time->tm_mday = *last_day;
89 end_time->tm_hour = 23;
90 end_time->tm_min = 59;
91 end_time->tm_sec = 59;
93 if (0 < pos_start && day < DAYS_OF_WEEK)
94 cal_util_update_tm_day(start_time, -pos_start);
95 else if ((0 != (day_tmp % DAYS_OF_WEEK)) && (pos_end < (start_day + DAYS_OF_WEEK - 1)))
96 cal_util_update_tm_day(end_time, start_day + DAYS_OF_WEEK - 1 - pos_end);
98 if (pos_end < day_pos && pos_end <= CAL_MONTH_CALENDAR_LAST_LINE_POS_INDEX && CAL_MONTH_CALENDAR_LAST_LINE_POS_INDEX < day_pos) {
99 r = cal_util_update_tm_day(start_time, DAYS_OF_WEEK);
100 c_retvm_if(-1 == r, -1, "start_time is out of range.");
102 r = cal_util_update_tm_day(end_time, DAYS_OF_WEEK);
103 c_retvm_if(-1 == r, -1, "end_time is out of range.");
109 static void __cal_month_data_get_grid_range(struct appdata *ad, struct tm* grid_start_time, struct tm* grid_end_time)
111 struct tm month_start_time;
112 struct tm month_end_time;
113 cal_util_get_month_start_time(&ad->base_tm, &month_start_time);
114 cal_util_get_month_end_time(&ad->base_tm, &month_end_time);
116 cal_util_get_week_start_time(&month_start_time, grid_start_time, ad->wday_start);
117 cal_util_get_week_end_time(&month_end_time, grid_end_time, ad->wday_start);
120 static cal_list_data_h __cal_month_data_retreive_list(const struct tm* start_time, const struct tm* end_time)
122 calendar_query_h query_allday = cal_query_create_list_range_query(
123 _calendar_instance_allday_calendar_book._uri,
124 _calendar_instance_allday_calendar_book.start_time,
125 _calendar_instance_allday_calendar_book.end_time,
126 start_time, end_time, true);
128 calendar_query_h query_normal = cal_query_create_list_range_query(
129 _calendar_instance_normal_calendar_book._uri,
130 _calendar_instance_normal_calendar_book.start_time,
131 _calendar_instance_normal_calendar_book.end_time,
132 start_time, end_time, false);
134 calendar_query_h query_task = cal_query_create_list_range_query(
135 _calendar_todo_calendar_book._uri,
136 _calendar_todo_calendar_book.due_time,
137 _calendar_todo_calendar_book.due_time,
138 start_time, end_time, false);
140 cal_list_data_h list_data = cal_list_data_create(query_allday, query_normal, query_task,
141 _calendar_instance_allday_calendar_book.start_time,
142 _calendar_instance_normal_calendar_book.start_time,
143 _calendar_todo_calendar_book.due_time);
145 calendar_query_destroy(query_allday);
146 calendar_query_destroy(query_normal);
147 calendar_query_destroy(query_task);
152 static void __cal_month_get_mweek_and_wday(cal_month_data_s* p, const struct tm* date, int* mweek, int* wday)
154 int offset = cal_util_get_day_diff(date, &p->grid_start_date);
155 // DBG("grid_start(%s), day(%s), offset(%d)", cal_util_print_day(&p->grid_start_date), cal_util_print_day(date), offset);
156 c_warn_if(offset < 0, "@@@@@@@@@@@@@@ Something's wrong here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
165 #define INVALID_ROW -1
167 static cal_month_calendar_event* _cal_month_data_create_node(
168 calendar_record_h record, int wday, int* remaining_width,
171 int target_width = 7 - wday;
172 if (target_width > *remaining_width)
173 target_width = *remaining_width;
174 *remaining_width -= target_width;
176 cal_month_calendar_event* event = calloc(1, sizeof(cal_month_calendar_event));
177 event->calendar_id = _calendar_get_calendar_index(record);
178 event->width = target_width;
179 event->title = strdup(_calendar_get_summary(record));
180 event->prev_row = prev_node_row;
181 event->next_row = INVALID_ROW;
185 static cal_month_calendar_event* __cal_month_data_create_plus_node(int count)
187 cal_month_calendar_event* event = calloc(1, sizeof(cal_month_calendar_event));
188 event->calendar_id = 1;
192 sprintf(buffer, "+%d more", count);
193 event->title = strdup(buffer);
194 event->prev_row = INVALID_ROW;
195 event->next_row = INVALID_ROW;
199 static const cal_month_calendar_event __dummy;
201 static int __cal_month_data_find_first_empty_row(cal_month_data_s* p, int mweek, int wday)
204 for (row = 0; row < p->rows_per_cell; row++) {
205 if (p->event_table[mweek][wday][row] == NULL)
209 if (row == p->rows_per_cell) // No empty row!
215 static void __cal_month_data_occupy(cal_month_data_s* p, calendar_record_h record)
217 struct tm date = {0};
218 struct tm end_date = {0};
220 cal_svc_get_start_date(record, &date);
221 cal_svc_get_end_date(record, &end_date);
223 if (cal_util_get_day_diff(&date, &p->grid_start_date) < 0)
224 date = p->grid_start_date;
226 if (cal_util_get_day_diff(&p->grid_end_date, &end_date) < 0)
227 end_date = p->grid_end_date;
229 int remaining_width = cal_util_get_day_diff(&end_date, &date) + 1;
231 cal_month_calendar_event* prev_node = NULL;
232 int prev_node_row = INVALID_ROW;
235 __cal_month_get_mweek_and_wday(p, &date, &mweek, &wday);
236 p->count_table[mweek][wday]++;
238 int row = __cal_month_data_find_first_empty_row(p, mweek, wday);
240 prev_node = p->event_table[mweek][wday][row] =
241 _cal_month_data_create_node(record, wday, &remaining_width, INVALID_ROW);
244 cal_util_update_tm_day(&date, 1);
246 // Iterate through rest of the span of the event
247 while (cal_util_compare_day(&date, &end_date) >= 0) {
249 __cal_month_get_mweek_and_wday(p, &date, &mweek, &wday);
250 p->count_table[mweek][wday]++;
253 if (prev_node != NULL) {
254 row = __cal_month_data_find_first_empty_row(p, mweek, wday);
256 cal_util_update_tm_day(&date, 1);
260 prev_node->next_row = row;
261 prev_node = p->event_table[mweek][wday][row] =
262 _cal_month_data_create_node(record, wday, &remaining_width, prev_node_row);
267 p->event_table[mweek][wday][row] = &__dummy;
270 cal_util_update_tm_day(&date, 1);
274 static const char* tab(int n)
276 static const char tabs[] = " ";
277 return tabs + strlen(tabs) - n;
280 static void __fix_width(char* buffer, int len)
282 strcat(buffer, tab(15 - len));
285 static void __cal_month_data_dump(cal_month_data_s* p)
288 for (mweek = 0; mweek < WEEKS_OF_MONTH; mweek++) {
289 static char buffer[1000];
293 for (wday = 0; wday < DAYS_OF_WEEK; wday++) {
295 sprintf(buffer2, "%d", p->count_table[mweek][wday]);
296 strcat(buffer, buffer2);
297 __fix_width(buffer, strlen(buffer2));
302 for (row = 0; row < p->rows_per_cell; row++) {
304 for (wday = 0; wday < DAYS_OF_WEEK; wday++) {
305 cal_month_calendar_event* event =
306 p->event_table[mweek][wday][row];
307 // p->event_table[mweek][wday][p->rows_per_cell - row - 1];
310 __fix_width(buffer, 0);
311 } else if (event == &__dummy) {
312 strcat(buffer, "(dummy)");
313 __fix_width(buffer, 7);
315 strncat(buffer, event->title, 14);
316 int len = strlen(event->title);
319 __fix_width(buffer, len);
324 DBG("---------------------------------------------------------------------------------------------------");
328 static void __cal_month_data_unoccupy(cal_month_data_s* p, int mweek, int wday, int row, int dir)
330 if (p->event_table[mweek][wday][row] == NULL) // This row's already been cleared
335 DBG("===================================================================================");
337 DBG("%d %d %d", mweek, wday, row);
339 // Unoccupy tailing blocks.
340 for (wd = wday + 1; wd < DAYS_OF_WEEK; wd++) {
341 if (p->event_table[mweek][wd][row] != &__dummy) // Head of another event or NULL
343 p->event_table[mweek][wd][row] = NULL;
344 DBG("Unoccupying dummy at %d %d %d", mweek, wd, row);
347 // Find head of the event block in last row.
348 for (wd = wday; wd >= 0; wd--) {
349 if (p->event_table[mweek][wd][row] != &__dummy) // Head of this event
351 p->event_table[mweek][wd][row] = NULL; // Unoccupy blocks along the way
352 DBG("Unoccupying dummy at %d %d %d", mweek, wd, row);
355 cal_month_calendar_event* head = p->event_table[mweek][wd][row];
356 int prev_row = head->prev_row;
357 int next_row = head->next_row;
359 // Unoccupy the head itself.
361 p->event_table[mweek][wd][row] = NULL;
362 DBG("Unoccupying head at %d %d %d", mweek, wd, row);
364 __cal_month_data_dump(p);
366 // Recursively propagate to previous chained block.
367 if (dir <= 0 && prev_row != INVALID_ROW)
368 __cal_month_data_unoccupy(p, mweek - 1, DAYS_OF_WEEK - 1, prev_row, -1);
370 // Recursively propagate to next chained block.
371 if (dir >= 0 && next_row != INVALID_ROW)
372 __cal_month_data_unoccupy(p, mweek + 1, 0, next_row, 1);
376 int cal_month_data_load(cal_month_data_h month_data)
378 c_retv_if(!month_data, -1);
379 cal_month_data_s* p = (cal_month_data_s*)month_data;
381 __cal_month_data_get_grid_range(p->ad, &p->grid_start_date, &p->grid_end_date);
383 cal_list_data_h* cursor = __cal_month_data_retreive_list(&p->grid_start_date, &p->grid_end_date);
385 // 1. Make a pass to fill up the grid with blocks greedily.
386 bool day_has_changed;
387 calendar_record_h record = cal_list_data_get_next(cursor, &day_has_changed);
389 __cal_month_data_occupy(p, record);
390 record = cal_list_data_get_next(cursor, &day_has_changed);
393 __cal_month_data_dump(p);
397 // 2. Make second pass to make room for the +n blocks where necessary.
398 for (mweek = 0; mweek < WEEKS_OF_MONTH; mweek++) {
400 for (wday = 0; wday < DAYS_OF_WEEK; wday++) {
401 if (p->count_table[mweek][wday] > p->rows_per_cell &&
402 p->event_table[mweek][wday][p->rows_per_cell - 1] != NULL) {
403 __cal_month_data_unoccupy(p, mweek, wday, p->rows_per_cell - 1, 0);
408 // 3. Make third pass to place +n blocks where necessary.
409 for (mweek = 0; mweek < WEEKS_OF_MONTH; mweek++) {
411 for (wday = 0; wday < DAYS_OF_WEEK; wday++) {
413 for (row = 0; row < p->rows_per_cell; row++) {
414 if (p->event_table[mweek][wday][row] == NULL) {
415 int num_of_showing_blocks = row;
416 int total_count = p->count_table[mweek][wday];
417 if (num_of_showing_blocks < total_count) {
418 p->event_table[mweek][wday][row] =
419 __cal_month_data_create_plus_node(total_count - num_of_showing_blocks);
427 __cal_month_data_dump(p);
429 cal_list_data_destroy(cursor, true);
434 int cal_month_data_get_event_count(cal_month_data_h month_data, int week, int wday)
436 c_retv_if(!month_data, -1);
437 cal_month_data_s* p = (cal_month_data_s*)month_data;
439 return p->count_table[week][wday];
442 cal_month_calendar_event* cal_month_data_get_event(cal_month_data_h month_data, int mweek, int wday, int row)
444 c_retv_if(!month_data, false);
445 cal_month_data_s* p = (cal_month_data_s*)month_data;
446 cal_month_calendar_event* event = p->event_table[mweek][wday][row];
447 if (event == &__dummy)
453 void cal_month_data_clear(cal_month_data_h month_data)
455 c_ret_if(!month_data);
456 cal_month_data_s* p = (cal_month_data_s*)month_data;
459 for (mweek = 0; mweek < WEEKS_OF_MONTH; mweek++) {
461 for (wday = 0; wday < DAYS_OF_WEEK; wday++) {
462 p->count_table[mweek][wday] = 0;
464 for (row = 0; row < p->rows_per_cell; row++) {
465 cal_month_calendar_event* event = p->event_table[mweek][wday][row];
466 if (event != NULL && event != &__dummy) {
467 if (event->title != NULL)
471 p->event_table[mweek][wday][row] = NULL;
477 void cal_month_data_destroy(cal_month_data_h month_data)
479 c_ret_if(!month_data);
480 cal_month_data_s* p = (cal_month_data_s*)month_data;
482 cal_month_data_clear(month_data);