47a228132034daf825aea7aae6d5f9cc33b65821
[platform/core/uifw/libpui.git] / backends / default_backend.c
1 //#include <PUI.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <PUI_backend.h>
5
6 #include <json-c/json.h>
7 #include <dirent.h>
8 #include <errno.h>
9 #include <Eina.h>
10 #include <config.h>
11
12 #define ANI_COLLECTION_DIR "/usr/share/pui/"
13 #define MAX_STR 1024
14
15 #define ERROR_CHECK(exp, action, fmt, ...) \
16         do { \
17                 if (!(exp)) \
18                 { \
19                         printf(fmt, ##__VA_ARGS__);     \
20                         action; \
21                 } \
22         } while (0)
23
24 pui_backend_ani_func *ani_func = NULL;
25 Eina_Hash *_animations_hash = NULL;
26
27 typedef enum
28 {
29         None,
30         Linear,
31         EaseInSine,
32         EaseOutSine,
33         EaseInQuart,
34         EaseOutQuart
35 } pui_effect_func;
36
37 typedef struct _default_ani_info default_ani_info;
38 typedef struct _default_frame_info_t default_frame_info_t;
39 typedef struct _default_led_info_t default_led_info_t;
40
41 struct _default_ani_info
42 {
43         pui_id id;
44         pui_ani_status status;
45         pui_ani_control_buffer *buffer;
46         unsigned int repeat;
47
48         unsigned int key_frame_idx;
49         unsigned int num_key_frames;
50         default_frame_info_t *frames;
51         int interval;
52         pui_effect_func effect_func;
53 };
54
55 struct _default_frame_info_t
56 {
57         default_led_info_t *leds;
58         int num_led;
59 };
60
61 struct _default_led_info_t
62 {
63         unsigned int color;
64 };
65
66 pui_backend_ani_data *g_ani_data = NULL;
67
68 static pui_bool
69 _ani_backend_frame_cb(void *data, int serial)
70 {
71         pui_ani_t *ani = (pui_ani_t *)data;
72
73         //TODO
74         (void) ani;
75         //_get_next_frame();
76         //pui_backend_ani_get_buffer();
77         //pui_backend_ani_update();
78
79         pui_info("... serial=%d\n", serial);
80
81         return (pui_bool)1;
82 }
83
84 default_ani_info *
85 get_ani_info_from_ani_collection(pui_id id)
86 {
87         default_ani_info *ani_info = NULL;
88
89         //TODO
90         //ex> data->id = id;
91         //ex> data->interval = 30;
92
93         if (!_animations_hash)
94                 return NULL;
95
96         pui_info("... id: %s\n", id);
97
98         ani_info = eina_hash_find(_animations_hash, id);
99
100         if (!ani_info)
101         {
102                 pui_err("ani_info has NOT been found ! (id:%s)\n", id);
103                 return NULL;
104         }
105
106         pui_info("ani_info has been found ! (id:%s)\n", id);
107
108         return ani_info;
109 }
110
111 pui_error
112 _ani_start(pui_ani_t *ani, int repeat)
113 {
114         pui_bool ret = 0;
115         pui_int_error e = PUI_INT_ERROR_NONE;
116         pui_backend_ani_data *ani_data = NULL;
117
118         ani_data = pui_backend_ani_get_ani_data(ani);
119         default_ani_info *info = (default_ani_info *)ani_data->ani_info;
120
121         //TODO
122         (void) info;
123
124         pui_info("... info->id: %s, repeat : %d\n", info->id, repeat);
125
126         pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STARTED);
127         ret = pui_backend_ani_add_frame_cb(ani, _ani_backend_frame_cb, 0.1);
128
129         if (!ret)
130         {
131                 pui_err("Failed to add frame callback !\n");
132                 e = PUI_INT_ERROR_INVALID_RESOURCES;
133         }
134
135         return e;
136 }
137
138 pui_error
139 _ani_stop(pui_ani_t *ani)
140 {
141         pui_int_error e = PUI_INT_ERROR_NONE;
142         pui_backend_ani_data *ani_data = NULL;
143
144         ani_data = pui_backend_ani_get_ani_data(ani);
145         default_ani_info *info = (default_ani_info *)ani_data->ani_info;
146
147         //TODO
148         (void) info;
149
150         pui_info("... info->id: %s\n", info->id);
151
152         pui_backend_ani_remove_frame_cb(ani);
153         pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
154
155         return e;
156 }
157
158 static char *
159 _read_json_file(const char *path, int *data_size)
160 {
161         FILE *fp = fopen(path, "rb");
162         int size;
163         char *buffer;
164         ERROR_CHECK(fp, return NULL, "Failed to open file: %s\n", path);
165
166         fseek(fp, 0, SEEK_END);
167         size = ftell(fp);
168         fseek(fp, 0, SEEK_SET);
169
170         buffer = (char *)calloc(sizeof(char), size + 1);
171
172         if (fread(buffer, size, 1, fp) < 1) {
173                 *data_size = 0;
174                 free(buffer);
175                 fclose(fp);
176                 return NULL;
177         }
178
179         *data_size = size;
180         fclose(fp);
181         return buffer;
182 }
183
184 static default_ani_info *
185 _read_json(const char *path)
186 {
187         char *buffer, *type;
188         json_object *root_obj, *data_obj, *frame_obj, *frame_data_obj, *led_obj, *led_data_obj;
189         default_ani_info *ani_info = NULL;
190         int frame_id = 0, frame_len = 0, led_id = 0, led_len = 0;
191         int data_size = 0, i, j;
192
193         buffer = _read_json_file(path, &data_size);
194         ERROR_CHECK(buffer && data_size > 0, return EINA_FALSE, "File %s has no data\n", path);
195         root_obj = json_tokener_parse(buffer);
196         ERROR_CHECK(root_obj, goto error, "Failed to tokenize json object\n");
197
198         ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
199         ERROR_CHECK(ani_info, goto error, "Failed to alloc for animation info\n");
200
201         data_obj = json_object_object_get(root_obj, "type");
202         //printf("type: %s\n", json_object_get_string(data_obj));
203         type = (char *)json_object_get_string(data_obj);
204         ani_info->id = strndup(type, strlen(type));
205
206         data_obj = json_object_object_get(root_obj, "interval");
207         //printf("interval: %d\n", json_object_get_int(data_obj));
208         ani_info->interval = json_object_get_int(data_obj);
209
210         data_obj = json_object_object_get(root_obj, "frame");
211         frame_len = json_object_array_length(data_obj);
212
213         ani_info->num_key_frames = frame_len;
214         ani_info->frames = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), frame_len);
215         ERROR_CHECK(ani_info->frames, goto error, "Failed to alloc for default_frame_info_t\n");
216         
217         for (i = 0; i < frame_len; i++) {
218                 frame_obj = json_object_array_get_idx(data_obj, i);
219
220                 frame_data_obj = json_object_object_get(frame_obj, "frame_id");
221                 //printf("\tframe id: %d\n", json_object_get_int(frame_data_obj));
222                 frame_id = json_object_get_int(frame_data_obj);
223
224                 frame_data_obj = json_object_object_get(frame_obj, "led");
225                 led_len = json_object_array_length(frame_data_obj);
226                 
227                 ani_info->frames[frame_id - 1].num_led = led_len;
228                 ani_info->frames[frame_id - 1].leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), led_len);
229                 ERROR_CHECK(ani_info->frames[frame_id - 1].leds, goto error, "Failed to alloc for default_led_info_t\n");
230                 
231                 for (j = 0; j < led_len; j++) {
232                         led_obj = json_object_array_get_idx(frame_data_obj, j);
233
234                         led_data_obj = json_object_object_get(led_obj, "id");
235                         //printf("\t\tid: %2d  ", json_object_get_int(led_data_obj));
236                         led_id = json_object_get_int(led_data_obj);
237
238                         led_data_obj = json_object_object_get(led_obj, "color");
239                         //printf("color: %s\n", json_object_get_string(led_data_obj));
240                         ani_info->frames[frame_id - 1].leds[led_id - 1].color =
241                                 strtol(json_object_get_string(led_data_obj), NULL, 16);
242                 }
243         }
244
245         free(buffer);
246         return ani_info;
247
248 error:
249         free(buffer);
250         if (ani_info) {
251                 if (ani_info->frames) {
252                         for (i = 0; i < ani_info->num_key_frames; i++) {
253                                 if (ani_info->frames[i].leds)
254                                         free(ani_info->frames[i].leds);
255                         }
256                         free(ani_info->frames);
257                 }
258                 free(ani_info->id);
259                 free(ani_info);
260         }
261         return NULL;
262 }
263
264 static int
265 _scandir_filter(const struct dirent *dirent)
266 {
267         if (!strncmp(dirent->d_name, ".", sizeof(".")) ||
268                 !strncmp(dirent->d_name, "..", sizeof("..")))
269                 return 0;
270         if (!strstr(dirent->d_name, ".json"))
271                 return 0;
272
273         return 1;
274 }
275
276
277 pui_int_error
278 _create_ani_collection(void)
279 {
280         pui_int_error e = PUI_INT_ERROR_NONE;
281         default_ani_info *ani_info;
282         struct dirent **files;
283         int count, i;
284         char file_path[MAX_STR] = {0, };
285
286         // load and store all of animation data
287
288         if ((count = scandir(ANI_COLLECTION_DIR, &files, _scandir_filter, alphasort)) == -1) {
289                 printf("Failed to get %s directory (%s)\n", ANI_COLLECTION_DIR, strerror(errno));
290                 e = PUI_INT_ERROR_INVALID_RESOURCES;
291                 return e;
292         }
293
294         for (i = 0; i < count; i++) {
295                 snprintf(file_path, sizeof(file_path), "%s%s", ANI_COLLECTION_DIR, files[i]->d_name);
296
297                 ani_info = _read_json(file_path);
298                 if (ani_info) {
299                         eina_hash_add(_animations_hash, ani_info->id, ani_info);
300                         printf("Success to load %s animation\n", files[i]->d_name);
301                 }
302         }
303
304         for (i = 0; i < count; i++) {
305                 free(files[i]);
306         }
307         free(files);
308
309         //TODO
310
311         return e;
312 }
313
314 pui_int_error
315 _is_ani_supported(pui_id id)
316 {
317         pui_int_error e = PUI_INT_ERROR_NONE;
318         default_ani_info *ani_info;
319
320         //TODO
321         /* if the given id is not supported, return PUI_INT_ERROR_ID_NOT_SUPPORTED. */
322         if (!id) {
323                 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
324                 return e;
325         }
326         ani_info = eina_hash_find(_animations_hash, id);
327
328         if (!ani_info)
329                 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
330
331         return e;
332 }
333
334 static void
335 _ani_info_cleanup(default_ani_info *ani_info)
336 {
337         int i;
338
339         if (!ani_info)
340                 return;
341
342         if (ani_info->frames)
343         {
344                 for (i = 0; i < ani_info->num_key_frames; i++)
345                 {
346                         if (ani_info->frames[i].leds)
347                                 free(ani_info->frames[i].leds);
348                 }
349
350                 free(ani_info->frames);
351         }
352
353         free(ani_info->id);
354 }
355
356 pui_backend_ani_data *
357 _ani_create(pui_id id)
358 {
359         pui_backend_ani_data *ani_data = NULL;
360         pui_backend_ani_func *ani_func = NULL;
361
362         /* backend's animation specific info */
363         default_ani_info *ani_info = NULL;
364
365         //TODO : return NULL if the animation correspond to the given id dones't exist.
366         if (PUI_INT_ERROR_NONE != _is_ani_supported(id))
367         {
368                 pui_err("The animation(%s) doesn't supported !\n", id);
369                 return NULL;
370         }
371
372         /* allocation of the structure of function pointers that will be called from pui_ani_control() */
373         ani_func = pui_backend_ani_alloc_ani_func();
374
375         if (!ani_func)
376         {
377                 pui_err("Failed to allocate memory ! (pui backend ani func)\n");
378                 return NULL;
379         }
380
381         /* Assign each function pointer that corresponds to the given id if needed. */
382         ani_func->ani_start = _ani_start;
383         ani_func->ani_stop = _ani_stop;
384
385         /* get animation info associate with the given id from animation collection */
386         ani_info = get_ani_info_from_ani_collection(id);
387         
388         if (!ani_info)
389         {
390                 pui_err("Failed to get ani info from animation collection !\n");
391                 goto err;
392         }
393
394         /* allocate backend ani_data and return it to pui ani core */
395         ani_data = (pui_backend_ani_data *)calloc(1, sizeof(pui_backend_ani_data));
396         
397         if (!ani_data)
398         {
399                 pui_err("Failed to allocate memory for pui backend ani data !\n");
400                 goto err;
401         }
402         
403         ani_data->ani_func = ani_func;
404         ani_data->ani_info = (pui_backend_ani_info *)ani_info;
405
406         g_ani_data = ani_data;
407
408         return ani_data;
409
410 err:
411         if (ani_func)
412         {
413                 pui_backend_ani_free_ani_func(ani_func);
414                 ani_func = NULL;
415         }
416
417         return NULL;
418 }
419
420 void
421 _ani_destroy(pui_backend_ani_data *ani_data)
422 {
423         if (!ani_data)
424                 return;
425
426         if (ani_data->ani_func)
427         {
428                 pui_backend_ani_free_ani_func(ani_data->ani_func);
429                 ani_data->ani_func = NULL;
430         }
431
432         ani_data->ani_info = NULL;
433         g_ani_data = NULL;
434 }
435
436 static void
437 _animation_data_free_cb(void *data)
438 {
439         default_ani_info *ani_info = (default_ani_info *)data;
440
441         _ani_info_cleanup(ani_info);
442 }
443
444 static pui_backend_module_data *
445 pui_default_backend_init(void)
446 {
447         pui_backend_module_data *backend_data = NULL;
448
449         backend_data = (pui_backend_module_data *)calloc(1, sizeof(pui_backend_module_data));
450
451         if (!backend_data)
452         {
453                 pui_err("Failed to allocate memory for pui backend module data !\n");
454                 return NULL;
455         }
456
457         backend_data->create_ani_collection = _create_ani_collection;
458         backend_data->ani_create = _ani_create;
459         backend_data->ani_destroy = _ani_destroy;
460
461         /* Allocate backend specific data if needed. Now it will be empty. */
462         backend_data->data = NULL;
463         _animations_hash = eina_hash_string_superfast_new(NULL);
464
465         return backend_data;
466 }
467
468 static void
469 pui_default_backend_deinit(pui_backend_module_data *backend_data)
470 {
471         Eina_Iterator *it;
472         default_ani_info *ani_info = NULL;
473
474         if (!backend_data)
475                 return;
476
477         if (backend_data->data)
478         {
479                 //TODO : free variables of backend_data
480
481                 free(backend_data->data);
482         }
483
484         if (g_ani_data)
485         {
486                 if (g_ani_data->ani_func)
487                 {
488                         pui_backend_ani_free_ani_func(g_ani_data->ani_func);
489                         g_ani_data->ani_func = NULL;
490                 }
491
492                 g_ani_data->ani_info = NULL;
493         }
494
495         if (_animations_hash)
496         {
497                 it = eina_hash_iterator_data_new(_animations_hash);
498
499                 EINA_ITERATOR_FOREACH(it, ani_info)
500                 {
501                         _animation_data_free_cb(ani_info);
502                         free(ani_info);
503                 }
504
505                 eina_iterator_free(it);
506
507                 eina_hash_free(_animations_hash);
508                 _animations_hash = NULL;
509         }
510
511         backend_data->create_ani_collection = NULL;
512         backend_data->ani_create = NULL;
513         backend_data->ani_destroy = NULL;
514
515         free(backend_data);
516         backend_data = NULL;
517 }
518
519 pui_backend_module pui_backend_module_info = {
520         "Tizen Reference Speaker Backend",
521         "Samsung",
522         PUI_BACKEND_SET_ABI_VERSION(1, 0),
523         pui_default_backend_init,
524         pui_default_backend_deinit
525 };
526