[Request]Update Flora license version
[apps/home/clock.git] / worldclock / src / worldclock_util.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 <stdio.h>
19 #include <string.h>
20 #include <appcore-efl.h>
21 #include <Elementary.h>
22 #include <Ecore_X.h>
23 #include <vconf.h>
24 #include <unicode/ustring.h>
25 #include <unicode/ucol.h>
26
27 #include "worldclock_util.h"
28 #include "worldclock_dlog.h"
29 #include "worldclock_fwk_icu.h"
30 #include "worldclock_data.h"
31
32 /**
33  * Compare the city name of two cities
34  *
35  * @param[in]  data1   record data of city1
36  * @param[in]  data2   record data of city2
37  *
38  * @return     -1 if city name of city2 is bigger than city1's
39  *              1 if city name of city1 is bigger than city2's
40  *              0 if city name of city2 is equal to city1, or meet error
41  */
42 int worldclock_city_compare_cb(const void *data1, const void *data2)
43 {
44         retv_if(!data1 || !data2, 0);
45
46         UChar bufcity1[CITY_BUF_SIZE] = { 0 };
47         UChar bufcity2[CITY_BUF_SIZE] = { 0 };
48
49         const Wcl_CitySet *cs1, *cs2;
50
51         cs1 = (const Wcl_CitySet *)data1;
52         cs2 = (const Wcl_CitySet *)data2;
53
54         char *city1 = _(cs1->city);
55         char *city2 = _(cs2->city);
56
57         u_uastrcpy(bufcity1, city1);
58         u_uastrcpy(bufcity2, city2);
59
60         UErrorCode status = U_ZERO_ERROR;
61         UCollator *coll = ucol_open(getenv("LANG"), &status);
62         UCollationResult ret = ucol_strcoll(coll, bufcity1, -1, bufcity2, -1);
63
64         ucol_close(coll);
65
66         switch (ret) {
67         case UCOL_EQUAL:
68                 return 0;
69         case UCOL_GREATER:
70                 return 1;
71         case UCOL_LESS:
72                 return -1;
73         default:
74                 return 0;
75         }
76 }
77
78 /**
79  * Compare timezone of two cities
80  *
81  * @param[in]  data1   recorder of city1
82  * @param[in]  data2   recorder of city2
83  *
84  * @return      1 if timezone of city1 is bigger than city2's
85  *              0 if timezone of city2 is equal to city1, or meet error
86  *             -1 if timezone of city2 is bigger than city1's
87  */
88 int worldclock_time_compare_cb(const void *data1, const void *data2)
89 {
90         retv_if(!data1 || !data2, 0);
91
92         float diff_val = 0.0;
93         int ret;
94         // get record data
95         const Wcl_CitySet *cs1 = (const Wcl_CitySet *)data1;
96         const Wcl_CitySet *cs2 = (const Wcl_CitySet *)data2;
97
98         char buf_tz1[TIMEZONE_BUF_SIZE] = { 0, };
99         char buf_tz2[TIMEZONE_BUF_SIZE] = { 0, };
100
101         const char *pbegin = NULL;
102         const char *ppos = NULL;
103
104         g_strlcpy(buf_tz1, cs1->timezone + 3, TIMEZONE_BUF_SIZE);
105         pbegin = buf_tz1;
106         ppos = strstr(buf_tz1, ":");
107         if (ppos) {
108                 buf_tz1[ppos - pbegin] = '.';
109         }
110
111         g_strlcpy(buf_tz2, cs2->timezone + 3, TIMEZONE_BUF_SIZE);
112         pbegin = buf_tz2;
113         ppos = strstr(buf_tz2, ":");
114         if (ppos) {
115                 buf_tz2[ppos - pbegin] = '.';
116         }
117         // get timezone
118         float d1 = atof(buf_tz1);
119         float d2 = atof(buf_tz2);
120
121         // get diff between of two cities
122         diff_val = d1 - d2;
123         // get result
124         if (diff_val > 0) {
125                 ret = 1;
126         } else if (diff_val < 0) {
127                 ret = -1;
128         } else {
129                 ret = 0;
130         }
131         return ret;
132 }
133
134 /**
135  * Compare sequence of two cities
136  *
137  * @param[in]  data1   recorder of city1
138  * @param[in]  data2   recorder of city2
139  *
140  * @return      1 if sequence of city1 is bigger than city2's
141  *              0 if sequence of city2 is equal to city1, or meet error
142  *             -1 if sequence of city2 is bigger than city1's
143  */
144 int worldclock_sequence_compare_cb(const void *data1, const void *data2)
145 {
146         retv_if(!data1 || !data2, 0);
147         int ret;
148
149         const Wcl_CitySet *cs1 = (const Wcl_CitySet *)data1;
150         const Wcl_CitySet *cs2 = (const Wcl_CitySet *)data2;
151
152         // get result
153         if (cs1->sequence > cs2->sequence) {
154                 ret = 1;
155         } else if (cs1->sequence < cs2->sequence) {
156                 ret = -1;
157         } else {
158                 ret = 0;
159         }
160         return ret;
161 }
162
163 /**
164  * Checking whether the count of city list meet the max number
165  *
166  * @param[in]  ap  given data used in this function
167  * @param[in]  cs  given city
168  *
169  * @return     EINA_TRUE if list full
170  *             EINA_FALSE if not
171  */
172 Eina_Bool worldclock_is_city_list_full(Eina_List * eina_list)
173 {
174         CLK_FUN_DEBUG_BEG();
175         retv_if(!eina_list, EINA_FALSE);
176         Eina_Bool ret = EINA_FALSE;
177
178         int count = eina_list_count(eina_list);
179         if (count >= WORLDCLOCK_MAX_CITY_COUNT) {
180                 CLK_INFO("list full, please delete some\n");
181                 ret = EINA_TRUE;
182         }
183         CLK_FUN_DEBUG_END();
184         return ret;
185 }
186
187 /**
188  * Insert given city into given eina list
189  *
190  * @param[in]  p_eina_list  given data used in this function
191  * @param[in]  cs           given city
192  * @param[in]  position     position where the city is insert into(-1: append to list)
193  *
194  * @return     -1 if not exist
195  *             0 if list full
196  *             list-count if success,
197  */
198 int worldclock_insert_city_to_list(Eina_List ** p_eina_list, Wcl_CitySet * cs,
199                                    int position)
200 {
201         CLK_FUN_DEBUG_BEG();
202         retv_if(!p_eina_list || !cs, -1);
203
204         int count = 0;
205         count = eina_list_count(*p_eina_list);
206         if (count >= WORLDCLOCK_MAX_CITY_COUNT) {
207                 CLK_INFO("list full, please delete some\n");
208                 return 0;
209         }
210         // set selected flag
211         cs->selected = 1;
212
213         if (0 > position) {
214                 *p_eina_list = eina_list_append(*p_eina_list, cs);
215
216                 // set sequence
217                 cs->sequence = count;
218         } else if (0 == position) {
219                 *p_eina_list = eina_list_prepend(*p_eina_list, cs);
220
221                 // set sequence
222                 Eina_List *el = *p_eina_list;
223                 int index = 0;
224                 while (el) {
225                         cs = (Wcl_CitySet *) el->data;
226                         cs->sequence = index;
227                         worldclock_data_update_db_record(cs);
228
229                         // get next item
230                         el = el->next;
231                         index++;
232                 }
233         } else {
234                 //  T.B.D.
235         }
236
237         count = eina_list_count(*p_eina_list);
238
239         CLK_FUN_DEBUG_END();
240         return count;
241 }
242
243 /**
244  * Remove all items in eina_list
245  *
246  * @param[in]  glist            given eina list
247  * @param[in]  is_free_element  flag to define if free data in every item is needed
248  *
249  * @return     EINA_TRUE if remove successfully
250  */
251 Eina_Bool worldclock_util_glist_remove_all(Eina_List * glist,
252                                            Eina_Bool is_free_element)
253 {
254         CLK_FUN_DEBUG_BEG();
255         if (glist != NULL) {
256                 if (EINA_TRUE == is_free_element) {
257                         void *user_data = NULL;
258                         Eina_List *tmp_list = glist;
259                         while (tmp_list) {
260                                 user_data = tmp_list->data;
261                                 if (user_data) {
262                                         free(user_data);
263                                         user_data = NULL;
264                                 }
265                                 // get next data
266                                 tmp_list = tmp_list->next;
267                         }
268                 }
269                 // free eina list
270                 eina_list_free(glist);
271                 glist = NULL;
272         }
273
274         CLK_FUN_DEBUG_END();
275         return EINA_TRUE;
276 }
277
278 /**
279  * Creat new popup window, and show it
280  *
281  * @param[in]  data   Data used in this function
282  * @param[in]  info   String displayed on popup
283  *
284  * @return
285  */
286 void worldclock_show_popup(Evas_Object * parent, Evas_Object ** p_popup,
287                            char *info)
288 {
289         ret_if(!p_popup);
290         Evas_Object *popup = *p_popup;
291         // reset popup
292         EVAS_OBJECT_DELIF(popup);
293         //to show popup
294         popup = elm_popup_add(parent);
295         evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND,
296                                          EVAS_HINT_EXPAND);
297         elm_popup_orient_set(popup, ELM_POPUP_ORIENT_CENTER);
298         elm_object_part_text_set(popup, "title", S_("IDS_COM_POP_WARNING"));
299         elm_object_text_set(popup, _(info));
300         Evas_Object *btn = elm_button_add(popup);
301         elm_object_text_set(btn, S_("IDS_COM_SK_OK"));
302         elm_object_part_content_set(popup, "button1", btn);
303         // show popup
304         evas_object_show(popup);
305 }
306
307 // if exist, return EINA_TRUE, else return EINA_FALSE
308 /**
309  * Check whether given city exist in given eina_list
310  *
311  * @param[in]  eina_list   given eina list
312  * @param[in]  cs          record of given city
313  * @return     EINA_FALSE if not exist
314  *             EINA_TRUE if exist
315  */
316 Eina_Bool worldclock_whether_city_exist_in_eina_list(Eina_List * eina_list,
317                                                      Wcl_CitySet * cs)
318 {
319         CLK_FUN_DEBUG_BEG();
320         Wcl_CitySet *cs_tmp = NULL;
321         Eina_List *el = NULL;
322         // get data list
323         el = eina_list;
324         while (el) {
325                 // get data
326                 cs_tmp = (Wcl_CitySet *) el->data;
327                 if (cs_tmp->index == cs->index) {
328                         CLK_FUN_DEBUG_END();
329                         return EINA_TRUE;
330                 }
331                 // get next data
332                 el = el->next;
333         }
334
335         CLK_FUN_DEBUG_END();
336         return EINA_FALSE;
337 }
338
339 /**
340  * Reset now time of genlist item data
341  *
342  * @param[in]  data      Data used in this function
343  *
344  * @return
345  */
346 void worldclock_reset_now_time(Eina_List * eina_list)
347 {
348         CLK_FUN_DEBUG_BEG();
349         ret_if(!eina_list);
350
351         Wcl_CitySet *cs = NULL;
352         // get data list
353         Eina_List *el = eina_list;
354         while (el) {
355                 cs = (Wcl_CitySet *) el->data;
356                 cs->now_time = 0;
357                 // get next item
358                 el = el->next;
359         }
360
361         CLK_FUN_DEBUG_END();
362 }
363
364 /**
365  * Create layout by load edj according group name from edj file
366  *
367  * @param[in]  parent   Parent of new layout
368  * @param[in]  file     EDJE file
369  * @param[in]  group    name of group
370  *
371  * @return     NULL if meet error
372  *             Pointer to new layout
373  */
374 Evas_Object *worldclock_load_edj(Evas_Object * parent, const char *file,
375                                  const char *group)
376 {
377         CLK_FUN_DEBUG_BEG();
378         Evas_Object *eo = NULL;
379         int r = 0;
380         // add new layout
381         eo = elm_layout_add(parent);
382         if (eo) {
383                 // set edje file & name of group
384                 r = elm_layout_file_set(eo, file, group);
385                 if (!r) {
386                         evas_object_del(eo);
387                         return NULL;
388                 }
389                 // set hint
390                 evas_object_size_hint_weight_set(eo, EVAS_HINT_EXPAND,
391                                                  EVAS_HINT_EXPAND);
392         }
393
394         CLK_FUN_DEBUG_END();
395         return eo;
396 }
397
398 /**
399  * Search word in string
400  * * Set color on the word if found
401  * * Set max length to aimed string, replace tail with ...
402  *
403  * @param[in]  string      source string for search
404  * @param[in]  searchword  word which used for search
405  * @param[in]  max_len     Max length of string which to display
406  *
407  * @return  string which for displaying
408  */
409 const char *worldclock_searchword_in_string(const char *string,
410                                             char *searchword, int max_len)
411 {
412         //SEARCH_FUNC_START;
413         char pstr[BUF_LARGE_SIZE] = { 0, };
414         char result_str[BUF_LARGE_SIZE] = { 0, }, start_str[BUF_LARGE_SIZE] = {
415         0,};
416         static char return_string[BUF_LARGE_SIZE] = { 0, };
417         int word_len = 0, search_len = 0, i = 0;        //, hilight_len = 0, hilight_len_2 = 0;
418         Eina_Bool found = EINA_FALSE;
419         g_strlcpy(pstr, string, BUF_LARGE_SIZE);
420         word_len = strlen(pstr);
421         search_len = strlen(searchword);
422         if (word_len > max_len) {
423                 snprintf(&pstr[max_len], BUF_LARGE_SIZE - max_len - 1, "%s",
424                          "...");
425         }
426         for (i = 0; i < word_len; i++) {
427                 if (!strncasecmp(searchword, &pstr[i], search_len)) {
428                         found = EINA_TRUE;
429                         break;
430                 }
431         }
432         if (EINA_TRUE == found) {
433                 if (i == 0) {
434                         strncpy(result_str, &pstr[i], search_len);
435                         result_str[search_len] = '\0';
436                         snprintf(return_string, BUF_LARGE_SIZE,
437                                  "<color=#e58616>%s</color>%s", &result_str[0],
438                                  &pstr[search_len]);
439                 } else if (i > 0) {
440                         strncpy(start_str, &pstr[0], i);
441                         start_str[i + 1] = '\0';
442                         strncpy(result_str, &pstr[i], search_len);
443                         result_str[search_len] = '\0';
444                         snprintf(return_string, BUF_LARGE_SIZE,
445                                  "%s<color=#e58616>%s</color>%s", &start_str[0],
446                                  &result_str[0], &pstr[i + search_len]);
447                 }
448         } else {
449                 snprintf(return_string, BUF_LARGE_SIZE, "%s", pstr);
450         }
451
452         return return_string;
453 }
454
455 /**
456  * This function is used to compute the length of string which displaying on entry
457  * The html flag which could change the actual length of string should be ignored.
458  *
459  * @param[in]  str    source string which got from entry
460  *
461  * @return  The length of the displaying part about str
462  */
463 int worldclock_str_get_displaying_length(const char *str)
464 {
465         retv_if(NULL == str, -1);
466         int len = strlen(str);
467
468         char *pre_flag = strchr(str, '<');
469
470         while (pre_flag) {
471                 int sub_num = 1;
472                 char *end_flag = strchr(pre_flag, '>');
473                 if (end_flag) {
474                         sub_num += end_flag - pre_flag;
475                         pre_flag = strchr(end_flag, '<');
476                 }
477                 len -= sub_num;
478         }
479
480         return len;
481 }
482
483 /**
484  * This function is used to get the displaying of string which displaying on entry
485  *
486  * @param[in]  src    source string which got from entry
487  * @param[in]  dst    dest string which write the displaying part to
488  *
489  * @return  The length of displaying part
490  */
491 int worldclock_str_get_displaying_part(const char *src, char *dst)
492 {
493         retv_if(NULL == src || NULL == dst, -1);
494         int len = strlen(src);
495         int sub_num = 0;
496         char *pre_flag = NULL;
497         char *end_flag = NULL;
498         char tmp_buf1[BUF_SIZE] = { '\0' };
499         char tmp_buf2[BUF_SIZE] = { '\0' };
500
501         snprintf(tmp_buf1, BUF_SIZE, src);
502
503         // get the first position where '<' found
504         pre_flag = strchr(tmp_buf1, '<');
505
506         while (pre_flag) {
507                 // get the begin position of '<' found
508                 int begin_pos = pre_flag - tmp_buf1;
509                 snprintf(tmp_buf2, begin_pos + 1, tmp_buf1);
510                 //CLK_ERR("tmp_buf2 : %s\n", tmp_buf2);
511                 sub_num = 1;
512                 // get the position of '>' which match previous '<'
513                 end_flag = strchr(pre_flag, '>');
514                 if (end_flag) {
515                         snprintf(tmp_buf2 + begin_pos, BUF_SIZE, end_flag + 1);
516                         sub_num += end_flag - pre_flag;
517                 } else {
518                         break;
519                 }
520                 len -= sub_num;
521                 snprintf(tmp_buf1, BUF_SIZE, tmp_buf2);
522                 pre_flag = strchr(tmp_buf1, '<');
523                 //CLK_ERR("tmp_buf1 : %s\n", tmp_buf1);
524         }
525
526         snprintf(dst, BUF_SIZE, tmp_buf1);
527         return len;
528 }
529
530 /**
531  * This function is used to justify whethet html flag exist in string
532  *
533  * @param[in]  str    source string which got from entry
534  *
535  * @return  EINA_TRUE if contain html
536  */
537 Eina_Bool worldclock_str_is_contain_html(const char *str)
538 {
539         retv_if(NULL == str, EINA_FALSE);
540         Eina_Bool ret = EINA_FALSE;
541
542         char *pre_flag = strchr(str, '<');
543
544         if (pre_flag) {
545                 ret = EINA_TRUE;
546         }
547
548         return ret;
549 }
550
551 /**
552  * This function is used to convert string type from Unicode to UTF8
553  *
554  * @param[in]  unichars    source string whose type is Unicode
555  *
556  * @return  The result string whose type is UTF8
557  */
558 char *worldclock_strToUTF8(const UChar * unichars)
559 {
560         retv_if(unichars == NULL, NULL);
561         int len = 0;
562         int len_str = 0;
563         int len_utf8 = 0;
564         char *str = NULL;
565         UErrorCode status = U_ZERO_ERROR;
566
567         len = u_strlen(unichars);
568         len_str = sizeof(char) * 4 * (len + 1);
569         str = (char *)calloc(1, len_str);
570         retv_if(NULL == str, NULL);
571
572         u_strToUTF8(str, len_str, &len_utf8, unichars, len, &status);
573         return str;
574 }
575
576 /*BEG: Gong Xingsheng<x536.gong@samsung.com> add in Mon Nov 21 01:10:19 PST 2011
577  * this function is used to get dst value by cs->dst_type
578  */
579 int worldclock_dst_get(const Wcl_CitySet * cs)
580 {
581         int dst = 0;
582         CLK_FUN_DEBUG_BEG();
583         if (cs->dst_enabled) {
584                 switch (cs->dst_type) {
585                 case WCL_DST_AUTO:
586                         dst = worldclock_icu_dst_get(cs->tz_path);
587                         break;
588                 case WCL_DST_1_HOUR:
589                         dst = 1;
590                         break;
591                 case WCL_DST_2_HOURS:
592                         dst = 2;
593                         break;
594                 default:
595                         dst = 0;
596                         break;
597                 }
598         }
599         CLK_FUN_DEBUG_END();
600         return dst;
601 }
602
603 /*END: Gong Xingsheng<x536.gong@samsung.com> add in Mon Nov 21 01:10:19 PST 2011 */
604
605 /* BEG:Gong Xingsheng<x536.gong@samsung.com> added Mon Nov 21 00:57:05 PST 2011
606  * this is for set date before show genlist, it is used to set dst value
607  * dst value is include three type:
608  *      off             : off, need to sub the dst value, which is got from icu
609  *      auto            : auto, get default dst value from icu
610  *      user set        : user set, get user set, which is saved in db
611  */
612 time_t worldclock_genlist_time_get(Wcl_CitySet * cs, void *data)
613 {
614         retv_if(!cs || !data, 0);
615         struct appdata *ad = (struct appdata *)data;
616         Wcl_CitySet *home_cs;
617         CLK_FUN_DEBUG_BEG();
618         // get homezone
619         if (ad->home_cs) {
620                 home_cs = ad->home_cs;
621                 home_cs->now_time = time(NULL);
622         } else {
623                 // get home city
624                 home_cs = worldclock_data_get_local_city();
625                 retv_if(!home_cs, FAILED);
626                 ad->home_cs = home_cs;
627         }
628         cs->dst = worldclock_dst_get(cs);
629         cs->now_time = home_cs->now_time;
630
631         int inc = 0;
632         struct tm tm;
633         time_t ntime = cs->now_time;
634         if (!cs->dst_enabled) {
635                 inc = (-1) * worldclock_icu_dst_get(cs->tz_path);
636         } else if (!IS_EQUAL(cs->dst_type, WCL_DST_AUTO)) {
637                 inc = cs->dst;
638         }
639
640         localtime_r(&ntime, &tm);
641         tm.tm_hour = (tm.tm_hour + 24 + (inc)) % 24;
642         ntime = mktime(&tm);
643         CLK_FUN_DEBUG_END();
644         return ntime;
645 }
646
647 /* END:Gong Xingsheng<x536.gong@samsung.com> added Mon Nov 21 00:57:05 PST 2011 */