mediadata: add function to create list with media modified time
[profile/tv/apps/native/air_mediahub.git] / src / data / mediadata.c
1 /*
2  * Copyright (c) 2015 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 #include <Elementary.h>
18 #include <media_content.h>
19 #include <app_debug.h>
20 #include <app_media.h>
21
22 #include "data/mediadata.h"
23
24 typedef int (*media_compare)(struct group_info *gi, app_media_info *info);
25 typedef char *(*group_name_get)(app_media_info *info);
26
27 static int _compare_cb_date(const void *, const void *);
28 static int _compare_cb_name(const void *, const void *);
29
30 static int _compare_title(struct group_info *, app_media_info *);
31 static char *_get_title(app_media_info *);
32 static int _compare_modified_time(struct group_info *, app_media_info *);
33 static char *_get_modified_time(app_media_info *);
34
35 enum _filter_type {
36         E_FILTER_FOLDER = 0,
37         E_FILTER_MEDIA
38 };
39
40 struct mediadata {
41         Eina_List *folder_list;
42         Eina_List *media_list;
43 };
44
45 struct _data {
46         const char *media_type;
47         int source_type;
48         int sort_type;
49         Eina_List *item_list;
50         Eina_List *folder_list;
51         Eina_List *media_list;
52 };
53
54 struct _sort_info {
55         int order_type;
56         const char *order_keyword;
57         Eina_Compare_Cb func;
58 };
59
60 struct _list_info {
61         media_compare media_cmp;
62         group_name_get name_get;
63 };
64
65 static struct _sort_info g_sort_info[E_SORT_MAX] = {
66         [E_SORT_DATE] = {
67                 .order_type = MEDIA_CONTENT_ORDER_DESC,
68                 .order_keyword = MEDIA_MODIFIED_TIME,
69                 .func = _compare_cb_date,
70         },
71         [E_SORT_NAME] = {
72                 .order_type = MEDIA_CONTENT_ORDER_ASC,
73                 .order_keyword = MEDIA_TITLE,
74                 .func = _compare_cb_name,
75         }
76 };
77
78 static struct _list_info g_list_info[E_LIST_MAX] = {
79         [E_LIST_NAME] = {
80                 .media_cmp = _compare_title,
81                 .name_get = _get_title,
82         },
83         [E_LIST_DATE] = {
84                 .media_cmp = _compare_modified_time,
85                 .name_get = _get_modified_time,
86         }
87 };
88
89 static bool _create_filter(struct _data *data, filter_h *filter, int type)
90 {
91         filter_h tmp_filter;
92         int ret;
93         char buf[1024];
94
95         ret = media_filter_create(&tmp_filter);
96         if (ret != MEDIA_CONTENT_ERROR_NONE) {
97                 _ERR("failed to create media filter");
98                 return false;
99         }
100
101         snprintf(buf, sizeof(buf), "%s", data->media_type);
102
103         if (type == E_FILTER_FOLDER && data->source_type != E_SOURCE_ALL) {
104                 char s[64];
105
106                 snprintf(s, sizeof(s), " AND MEDIA_STORAGE_TYPE=%d",
107                                         data->source_type);
108                 strcat(buf, s);
109         }
110
111         media_filter_set_condition(tmp_filter, buf,
112                         MEDIA_CONTENT_COLLATE_DEFAULT);
113
114         media_filter_set_order(tmp_filter,
115                         g_sort_info[data->sort_type].order_type,
116                         g_sort_info[data->sort_type].order_keyword,
117                         MEDIA_CONTENT_COLLATE_NOCASE);
118
119         *filter = tmp_filter;
120
121         return true;
122 }
123
124 static char *_get_date_string(time_t time)
125 {
126         struct tm tm;
127         char buf[32];
128
129         localtime_r(&time, &tm);
130         strftime(buf, sizeof(buf), "%Y.%m.%d", &tm);
131
132         return strdup(buf);
133 }
134
135 static int _compare_title(struct group_info *gi, app_media_info *info)
136 {
137         if (!gi || !gi->name || !info->title)
138                 return -1;
139
140         return strncasecmp(gi->name, info->title, 1);
141 }
142
143 static char *_get_title(app_media_info *info)
144 {
145         if (!info->title)
146                 return NULL;
147
148         return strndup(info->title, 1);
149 }
150
151 static int _compare_modified_time(struct group_info *gi, app_media_info *info)
152 {
153         char *date;
154         int r;
155
156         if (!gi || !gi->name)
157                 return -1;
158
159         date = _get_date_string(info->modified_time);
160
161         r = strcasecmp(gi->name, date);
162
163         free(date);
164
165         return r;
166 }
167
168 static char *_get_modified_time(app_media_info *info)
169 {
170         return  _get_date_string(info->modified_time);
171 }
172
173 static int _compare_cb_date(const void *data1, const void *data2)
174 {
175         app_media *am1, *am2;
176         app_media_info *info1, *info2;
177
178         am1 = (app_media *)data1;
179         am2 = (app_media *)data2;
180
181         info1 = app_media_get_info(am1);
182         info2 = app_media_get_info(am2);
183
184         if (!info1 || !info2)
185                 return -1;
186
187         if (info1->modified_time < info2->modified_time)
188                 return 1;
189
190         return -1;
191 }
192
193 static int _compare_cb_name(const void *data1, const void *data2)
194 {
195         app_media *am1, *am2;
196         app_media_info *info1, *info2;
197
198         am1 = (app_media *)data1;
199         am2 = (app_media *)data2;
200
201         info1 = app_media_get_info(am1);
202         info2 = app_media_get_info(am2);
203
204         if (!info1 || !info2 || !info1->display_name || !info2->display_name)
205                 return -1;
206
207         return strcasecmp(info1->display_name, info2->display_name);
208 }
209
210 static Eina_List *_sort_list(Eina_List *list, int sort)
211 {
212         Eina_List *sorted_list;
213
214         sorted_list = eina_list_sort(list, 0, g_sort_info[sort].func);
215
216         return sorted_list;
217 }
218
219 static void _destroy_folderlist(Eina_List *list)
220 {
221         struct group_info *gi;
222         app_media *am;
223
224         EINA_LIST_FREE(list, gi) {
225                 free(gi->name);
226                 EINA_LIST_FREE(gi->list, am)
227                         app_media_destroy(am);
228                 free(gi);
229         }
230 }
231
232 static bool _get_each_media_info(media_info_h media_h, void *dt)
233 {
234         app_media *am;
235         struct _data *data;
236
237         if (!dt)
238                 return false;
239
240         data = dt;
241
242         am = app_media_create(media_h);
243         if (!am) {
244                 _ERR("failed to create app media");
245                 return false;
246         }
247
248         data->item_list = eina_list_append(data->item_list, am);
249
250         return true;
251 }
252
253 static bool _get_each_folder_info(media_folder_h folder, void *dt)
254 {
255         filter_h filter;
256         struct _data *data;
257         struct group_info *gi;
258         int ret;
259         char *uuid;
260
261         if (!dt)
262                 return false;
263
264         data = dt;
265
266         gi = calloc(1, sizeof(*gi));
267         if (!gi) {
268                 _ERR("failed to create folderdata");
269                 return false;
270         }
271
272         if (media_folder_get_name(folder, &(gi->name))
273                         != MEDIA_CONTENT_ERROR_NONE) {
274                 _ERR("Media folder id Fetch error");
275                 goto err;
276         }
277
278         if (media_folder_get_folder_id(folder, &uuid)
279                 != MEDIA_CONTENT_ERROR_NONE) {
280                 _ERR("failed to fetch media folder id");
281                 goto err;
282         }
283
284         if (!_create_filter(data, &filter, E_FILTER_MEDIA)) {
285                 _ERR("failed to create filter");
286                 goto err;
287         }
288
289         ret = media_folder_foreach_media_from_db(uuid, filter,
290                                 _get_each_media_info, data);
291         if (ret != MEDIA_CONTENT_ERROR_NONE) {
292                 _ERR("failed to get media info");
293                 goto err;
294         }
295
296         gi->list = eina_list_clone(data->item_list);
297         data->media_list = eina_list_merge(data->media_list, data->item_list);
298         data->item_list = NULL;
299
300         data->folder_list = eina_list_append(data->folder_list, gi);
301
302         media_filter_destroy(filter);
303         free(uuid);
304
305         return true;
306
307 err:
308         media_filter_destroy(filter);
309         free(uuid);
310         _destroy_folderlist(data->folder_list);
311         return false;
312 }
313
314 static bool _get_folderlist(struct _data *data)
315 {
316         filter_h filter;
317         int ret;
318
319         if (!_create_filter(data, &filter, E_FILTER_FOLDER)) {
320                 _ERR("failed to create filter");
321                 return false;
322         }
323
324         ret = media_folder_foreach_folder_from_db(filter,
325                         _get_each_folder_info, data);
326         if (ret != MEDIA_CONTENT_ERROR_NONE) {
327                 _ERR("failed to get folder info");
328                 media_filter_destroy(filter);
329                 return false;
330         }
331
332         media_filter_destroy(filter);
333
334         return true;
335 }
336
337 struct mediadata *mediadata_create(const char *media_type,
338                         int source_type, int sort_type)
339 {
340         struct mediadata *md;
341         struct _data data;
342         int ret;
343
344         if (!media_type || source_type < 0 || source_type >= E_SOURCE_MAX
345                 || sort_type < 0 || sort_type >= E_SORT_MAX) {
346                 _ERR("invalid argument");
347                 return NULL;
348         }
349
350         md = calloc(1, sizeof(*md));
351         if (!md) {
352                 _ERR("failed to create mediadata");
353                 return NULL;
354         }
355
356         ret = media_content_connect();
357         if (ret != MEDIA_CONTENT_ERROR_NONE) {
358                 _ERR("failed to connect to media content");
359                 free(md);
360                 return NULL;
361         }
362
363         data.media_type = media_type;
364         data.source_type = source_type;
365         data.sort_type = sort_type;
366         data.item_list = NULL;
367         data.folder_list = NULL;
368         data.media_list = NULL;
369
370         if (!_get_folderlist(&data)) {
371                 _ERR("failed to get folderlist");
372                 free(md);
373                 media_content_disconnect();
374                 return NULL;
375         }
376
377         media_content_disconnect();
378
379         md->folder_list = data.folder_list;
380         md->media_list = _sort_list(data.media_list, data.sort_type);
381
382         return md;
383 }
384
385 void mediadata_destroy(struct mediadata *md)
386 {
387         if (!md) {
388                 _ERR("failed to get mediadata");
389                 return;
390         }
391
392         _destroy_folderlist(md->folder_list);
393         eina_list_free(md->media_list);
394 }
395
396 Eina_List *mediadata_get_list(struct mediadata *md, int list_type)
397 {
398         Eina_List *list, *l;
399         struct group_info *gi;
400         app_media *am;
401         app_media_info *info;
402
403         if (!md) {
404                 _ERR("failed to get mediadata");
405                 return NULL;
406         }
407
408         if (list_type < 0 || list_type >= E_LIST_MAX) {
409                 _ERR("invalid argument");
410                 return NULL;
411         }
412
413         gi = NULL;
414         list = NULL;
415         EINA_LIST_FOREACH(md->media_list, l, am) {
416                 info = app_media_get_info(am);
417                 if (!info) {
418                         _ERR("failed to get media info");
419                         mediadata_free_list(list);
420                         return NULL;
421                 }
422
423                 if (g_list_info[list_type].media_cmp(gi, info)) {
424                         gi = calloc(1, sizeof(*gi));
425                         if (!gi) {
426                                 _ERR("failed to create group info");
427                                 mediadata_free_list(list);
428                                 return NULL;
429                         }
430
431                         gi->name = g_list_info[list_type].name_get(info);
432
433                         list = eina_list_append(list, gi);
434                 }
435
436                 gi->list = eina_list_append(gi->list, am);
437         }
438
439         return list;
440 }
441
442 void mediadata_free_list(Eina_List *list)
443 {
444         Eina_List *l;
445         struct group_info *gi;
446
447         EINA_LIST_FOREACH(list, l, gi) {
448                 free(gi->name);
449                 eina_list_free(gi->list);
450
451                 free(gi);
452         }
453 }