/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the License);
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "config.h"
#include "../inc/gif-viewer-view.h"
#include "../inc/image-sample-utils.h"
#include "../inc/image-common.h"
#include "../../common/inc/ui-utils.h"
#include "../../common/inc/main-app.h"


#include <Elementary.h>
#include <image_util.h>

// *_X_POS, *_Y_POS, *_WIDTH, *_HEIGHT are virtual (relative) coords of grid widget
#define MAX_WIDTH 100
#define MAX_HEIGHT 100

#define IMAGE_X_POS 0
#define IMAGE_Y_POS 0
#define IMAGE_WIDTH MAX_WIDTH
#define IMAGE_HEIGHT 40

#define LABEL_X_POS 0
#define LABEL_Y_POS IMAGE_HEIGHT
#define LABEL_WIDTH MAX_WIDTH
#define LABEL_HEIGHT MAX_WIDTH-IMAGE_HEIGHT

#define COLORSPACE_INDEX_DEFAULT 0
#define COLOSPACE_NAME_LEN 6

#define LABEL_TEXT_TEMPLATE "%s%s<br/>FrameCount: %u<br/>Dim = %u x %u<br/>PixelFormat:%s<br/>"\
    "Average time to get frame: %ums<br/>Result:E_SUCCESS"

enum
{
    TOOLBAR_ITEM_INDEX_PIXFMT = 0,
    TOOLBAR_ITEM_INDEX_PREV,
    TOOLBAR_ITEM_INDEX_NEXT,
    TOOLBAR_ITEM_INDEX_COUNT
} TOOLBAR_ITEM_INDEXS;

typedef struct _colorspace_config
{
    image_util_colorspace_e format;
    const char name[COLOSPACE_NAME_LEN];
} colorspace_config;

struct _gif_viewer_view
{
    Elm_Object_Item *frame_item;
    Evas_Object *navi;
    Evas_Object *layout;
    app_data *app;
    Evas_Object *grid;
    Evas_Object *toolbar;
    Evas_Object *image;
    Evas_Object *label;
    Elm_Object_Item* toolbar_items[TOOLBAR_ITEM_INDEX_COUNT];
    unsigned int image_id;
    bool colorspace_index;
    unsigned char *image_buffer;
    int result;
};

static const int toolbar_item_ids[TOOLBAR_ITEM_INDEX_COUNT] = {TOOLBAR_ITEM_INDEX_PIXFMT, TOOLBAR_ITEM_INDEX_PREV, TOOLBAR_ITEM_INDEX_NEXT};
static const char *toolbar_item_names[TOOLBAR_ITEM_INDEX_COUNT] = { "RGB16", "Prev", "Next" };

static const colorspace_config colorspace_configs[] =
{
    {IMAGE_UTIL_COLORSPACE_BGRA8888, "RGB32"},
    {IMAGE_UTIL_COLORSPACE_RGB565, "RGB16"}
};

static const char *title_view = "Gif viewer";

static const char *image_file_names[] = { "squee.gif", "AGIF/animated.gif" };
#define IMAGES_COUNT (sizeof(image_file_names) / sizeof(*image_file_names))

static void _push(gif_viewer_view *this);

static Evas_Object *_create_toolbar(gif_viewer_view *view);
static void _toolbar_button_clicked_cb(void *data, Evas_Object *obj,
        void *event_info);
static  bool _add_main_content(gif_viewer_view *view);
static void _main_layout_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);


static void _change_image(gif_viewer_view *this, bool to_next);
static bool _process_colorspace_convert(gif_viewer_view *view);
static void _update_view_controls(gif_viewer_view *this);
static void _update_label(gif_viewer_view *view);
static void _update_title(gif_viewer_view *view);
static void _update_toolbar_buttons(gif_viewer_view *view);


gif_viewer_view *gif_viewer_view_add(app_data *app, Evas_Object *navi)
{
    gif_viewer_view *view = calloc(1, sizeof(gif_viewer_view));

    if (NULL != view)
    {
        view->navi = navi;
        view->app = app;
        view->layout = ui_utils_layout_add(navi, _main_layout_del_cb, view);
        view->colorspace_index = COLORSPACE_INDEX_DEFAULT;
        view->image_buffer = NULL;

        if (NULL == view->layout)
        {
            free(view);
            return NULL;
        }

        if (!_add_main_content(view))
        {
            evas_object_del(view->layout);
            return NULL;
        }

        _push(view);
    }

    return view;
}

static void _push(gif_viewer_view *this)
{
    Elm_Object_Item *item = elm_naviframe_item_push(this->navi, NULL,
            NULL, NULL, this->layout, NULL);
    this->frame_item = item;
    elm_object_item_part_content_set(this->frame_item, "toolbar",
            this->toolbar);
    _update_view_controls(this);
}

static Evas_Object *_create_toolbar(gif_viewer_view *view)
{
    Evas_Object *obj = elm_toolbar_add(view->navi);
    RETVM_IF(!obj, NULL, "error on elm_toolbar_add call");

    elm_object_style_set(obj, "default");
    elm_toolbar_shrink_mode_set(obj, ELM_TOOLBAR_SHRINK_EXPAND);
    elm_toolbar_transverse_expanded_set(obj, EINA_TRUE);
    elm_toolbar_select_mode_set(obj, ELM_OBJECT_SELECT_MODE_NONE);
    evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);

    unsigned int i;
    for (i = 0; i < TOOLBAR_ITEM_INDEX_COUNT; ++i)
    {
        view->toolbar_items[i] = elm_toolbar_item_append(obj, NULL, toolbar_item_names[i], _toolbar_button_clicked_cb, view);
        evas_object_data_set(elm_toolbar_item_object_get(view->toolbar_items[i]), TOOLBAR_BUTTON_DATA_KEY, (void*)(&toolbar_item_ids[i]));
    }

    return obj;
}

static void _toolbar_button_clicked_cb(void *data, Evas_Object *obj,
        void *event_info)
{
    RETM_IF(NULL == data, "error: data passed as NULL");
    RETM_IF(NULL == event_info, "event info is NULL");
    gif_viewer_view *view = data;
    void *toolbar_item_data = evas_object_data_get(elm_toolbar_item_object_get(event_info), TOOLBAR_BUTTON_DATA_KEY);

    RETM_IF(NULL == toolbar_item_data, "Toolbar item data is NULL");
    int i = *((int*)toolbar_item_data);
    switch (i)
    {
        case TOOLBAR_ITEM_INDEX_PIXFMT:
            view->result = !_process_colorspace_convert(view);
            _update_view_controls(view);
            break;
        case TOOLBAR_ITEM_INDEX_PREV:
            _change_image(view, false);
            break;
        case TOOLBAR_ITEM_INDEX_NEXT:
            _change_image(view, true);
            break;
        default:
            ERR("Not supported button");
            break;
    }

}

static bool _add_main_content(gif_viewer_view *view)
{
    RETVM_IF(NULL == view, false, "create of layout elements failed");

    Evas_Object *grid = ic_create_grid(view->layout, MAX_WIDTH, MAX_HEIGHT);
    RETVM_IF(NULL == grid, false, "create of layout elements failed");
    view->grid = grid;

    Evas_Object *image = ic_create_image(grid, image_file_names[0]);
    RETVM_IF(NULL == image, false, "create of layout elements failed");
    view->image = image;
    ic_image_set_animated(image);
    elm_grid_pack(grid, image, IMAGE_X_POS, IMAGE_Y_POS, IMAGE_WIDTH, IMAGE_HEIGHT);

    Evas_Object *label = ic_create_label(grid);
    RETVM_IF(NULL == label, false, "create of layout elements failed");
    view->label = label;
    elm_grid_pack(grid, label, LABEL_X_POS, LABEL_Y_POS, LABEL_WIDTH, LABEL_HEIGHT);

    Evas_Object *toolbar = _create_toolbar(view);
    RETVM_IF(NULL == toolbar, false, "create of layout elements failed");
    view->toolbar = toolbar;

    return true;
}

static void _update_label(gif_viewer_view *view)
{
    RETM_IF(NULL == view, "this as NULL is passed to method");
    RETM_IF(NULL == view->image, "image is NULL");

    int w = 0, h = 0;
    Evas_Object* obj_img = elm_image_object_get(view->image);
    evas_object_image_size_get(obj_img, &w, &h);

    const char *image_name = image_file_names[view->image_id];
    int gif_frame_count = evas_object_image_animated_frame_count_get(obj_img);

    char buff[LABEL_MAX_LEN] = {'\0'};
    snprintf(buff, LABEL_MAX_LEN, LABEL_TEXT_TEMPLATE, LABEL_REL_PATH, image_name, gif_frame_count,
            w, h, colorspace_configs[view->colorspace_index].name, 0);
    elm_object_text_set(view->label, buff);
}

static void _change_image(gif_viewer_view *this, bool to_next)
{
    RETM_IF(NULL == this, "this is NULL");
    unsigned int image_id = this->image_id;
    RETM_IF((to_next && image_id + 1 >= IMAGES_COUNT), "Out of image container");
    RETM_IF((!to_next && image_id == 0), "Out of image container");

    if (to_next)
    {
        ++image_id;
    }
    else
    {
        --image_id;
    }

    if (!ic_load_image(this->image,  image_file_names[image_id]))
    {
        ERR("ic_load_image failed");
    }
    ic_image_set_animated(this->image);
    this->image_id = image_id;
    this->colorspace_index = COLORSPACE_INDEX_DEFAULT;
    free(this->image_buffer);
    this->image_buffer = NULL;

    _update_view_controls(this);
}

static void _update_view_controls(gif_viewer_view *view)
{
    RETM_IF(NULL == view, "view is NULL");
    _update_title(view);
    _update_toolbar_buttons(view);
    _update_label(view);
}

static void _update_title(gif_viewer_view *view)
{
    RETM_IF(NULL == view, "view is NULL");
    char buf[TITLE_MAX_LEN] = {'\0'};
    snprintf(buf, sizeof(buf), "%s (%d/%d)", title_view, view->image_id + 1, IMAGES_COUNT);
    elm_object_item_text_set(view->frame_item, buf);
}

static void _update_toolbar_buttons(gif_viewer_view *view)
{
    RETM_IF(NULL == view, "view is NULL");
    Eina_Bool prev_button_dis = (view->image_id == 0);
    Eina_Bool next_button_dis = (view->image_id + 1 >= IMAGES_COUNT);
    elm_object_item_text_set(view->toolbar_items[TOOLBAR_ITEM_INDEX_PIXFMT], colorspace_configs[!view->colorspace_index].name);
    elm_object_item_disabled_set(view->toolbar_items[TOOLBAR_ITEM_INDEX_PREV], prev_button_dis);
    elm_object_item_disabled_set(view->toolbar_items[TOOLBAR_ITEM_INDEX_NEXT], next_button_dis);
}

static bool _process_colorspace_convert(gif_viewer_view *view)
{
    RETVM_IF(NULL == view, false, "view is NULL");
    RETVM_IF(NULL == view->image, false, "image is NULL");
    Evas_Object* evas_image = elm_image_object_get(view->image);
    RETVM_IF(NULL == evas_image, false, "evas image is NULL");

    int w = 0, h = 0;
    evas_object_image_size_get(evas_image, &w, &h);
    RETVM_IF(0 == w * h, false, "wrong size of image: %d x %d", w, h);

    void* src_buff = evas_object_image_data_get(evas_image, EINA_FALSE);
    RETVM_IF(NULL == src_buff, false, "image source buffer is NULL");

    image_util_colorspace_e src_colorspace = IMAGE_UTIL_COLORSPACE_BGRA8888;
    image_util_colorspace_e dest_colorspace = colorspace_configs[!view->colorspace_index].format;
    int error = IMAGE_UTIL_ERROR_NONE;
    unsigned int dest_size = 0;
    error = image_util_calculate_buffer_size(w , h, dest_colorspace, &dest_size);
    RETVM_IF(IMAGE_UTIL_ERROR_NONE != error, false, "image_util_calculate_buffer_size error");

    unsigned char* dest_buff = malloc(dest_size);
    RETVM_IF(NULL == dest_buff, false, "malloc destination buffer error %d", dest_size);

    error = image_sample_util_convert_colorspace(dest_buff, dest_colorspace,
                                          src_buff, w, h, src_colorspace);

    if (IMAGE_UTIL_ERROR_NONE != error)
    {
        ERR("image_sample_util_convert_colorspace error");
        free(dest_buff);
        return false;
    }

    free(view->image_buffer);
    view->image_buffer = dest_buff;
    view->colorspace_index = !view->colorspace_index;

    return true;
}

static void _main_layout_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
    gif_viewer_view *view = data;
    if (view)
    {
        free(view->image_buffer);
        free(view);
    }
}
