/*
 * 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 "../../player/inc/camera-player-view.h"
#include "../../common/inc/main-app.h"

#include <player.h>
#include <camera.h>
#include <Elementary.h>

#define MAX_LABEL_LEN 256
#define STR_STOP "Stop"
#define STR_START "Start"

struct _camera_player_view
{
    app_data *app;
    Elm_Object_Item *frame_item;
    Evas_Object *navi;
    Evas_Object *layout;
    Evas_Object *toolbar;
    Evas_Object *video_rect;
    Evas_Object *camera_rect;

    player_h player;
    camera_h camera;
    bool play;

    Elm_Object_Item *toolbar_item;
};

static void _destroy(camera_player_view *this);
static void _push(camera_player_view *this);
static Evas_Object *_main_layout_add(camera_player_view *this, Evas_Object *parent);
static Evas_Object *_toolbar_add(camera_player_view *this, Evas_Object *parent);
static Evas_Object *_label_add(Evas_Object *parent, const char *text);
static void _register_app_cbs(camera_player_view *this);

static void _start(camera_player_view *this);
static void _stop(camera_player_view *this);
static void _pause(camera_player_view *this);
static void _resume(camera_player_view *this);

static player_h _create_player(camera_player_view *this);
static void _destroy_player(camera_player_view *this);
static void _start_player(camera_player_view *this);
static void _stop_player(camera_player_view *this);
static void _pause_player(camera_player_view *this);

static camera_h _create_camera(camera_player_view *this);
static void _destroy_camera(camera_player_view *this);
static void _start_camera(camera_player_view *this);
static void _stop_camera(camera_player_view *this);

static void _on_resume_cb(void *user_data);
static void _on_pause_cb(void *user_data);
static void _on_toolbar_btn_pressed_cb(void *data, Evas_Object *obj, void *event_info);
static void _on_main_layout_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);

camera_player_view *camera_player_view_add(app_data *app, Evas_Object *navi)
{
    if(!app)
    {
        return NULL;
    }

    camera_player_view *this = calloc(1, sizeof(camera_player_view));

    if(this)
    {
        this->navi = navi;
        this->app = app;
        this->layout = _main_layout_add(this, navi);

        if(this->layout)
        {
            _register_app_cbs(this);
            evas_object_event_callback_add(this->layout, EVAS_CALLBACK_DEL, _on_main_layout_del_cb, this);
            _push(this);
        }
        else
        {
            evas_object_del(this->layout);
            _destroy(this);
            return NULL;
        }
    }

    return this;
}

static void _register_app_cbs(camera_player_view *this)
{
    app_cbs cbs =
    {
       .pause = _on_pause_cb,
       .resume = _on_resume_cb
    };

    app_set_cbs(this->app, cbs, this);
}

static void _start(camera_player_view *this)
{
    this->play = true;
    _start_player(this);
    _start_camera(this);
    elm_object_item_text_set(this->toolbar_item, STR_STOP);
}

static void _stop(camera_player_view *this)
{
    this->play = false;
    _stop_player(this);
    _stop_camera(this);
    elm_object_item_text_set(this->toolbar_item, STR_START);
}

static void _pause(camera_player_view *this)
{
    _pause_player(this);
    _stop_camera(this);
}

static void _resume(camera_player_view *this)
{
    if(this->play)
    {
        _start_player(this);
        _start_camera(this);
    }
}

static player_h _create_player(camera_player_view *this)
{
    player_h player = NULL;

    if(player_create(&player) == PLAYER_ERROR_NONE)
    {
        player_set_sound_type(player, SOUND_TYPE_MEDIA);
        player_set_volume(player, 1.0, 1.0);
        player_set_looping(player, true);

        player_set_uri(player, get_resource_path(SAMPLEMPEG4));
        player_set_display(player, PLAYER_DISPLAY_TYPE_EVAS, GET_DISPLAY(this->video_rect));
        player_set_display_mode(player, PLAYER_DISPLAY_MODE_FULL_SCREEN);
        player_set_display_visible(player, true);
        player_prepare(player);
    }

    return player;
}

static void _destroy_player(camera_player_view *this)
{
    if(this->player)
    {
        player_stop(this->player);
        player_unprepare(this->player);
        player_destroy(this->player);
        this->player = NULL;
    }
}

static void _start_player(camera_player_view *this)
{
    if(!this->player)
    {
        this->player = _create_player(this);
    }

    if(this->player)
    {
        player_state_e state;
        player_get_state(this->player, &state);

        if(state != PLAYER_STATE_PLAYING)
        {
            player_set_display_visible(this->player, true);
            player_start(this->player);
        }
    }
}

static void _stop_player(camera_player_view *this)
{
    if(this->player)
    {
        player_state_e state;
        player_get_state(this->player, &state);

        if(state == PLAYER_STATE_PLAYING || state == PLAYER_STATE_PAUSED)
        {
            player_stop(this->player);
            player_set_display_visible(this->player, false);
        }
    }
}

static void _pause_player(camera_player_view *this)
{
    if(this->player)
    {
        player_state_e state;
        player_get_state(this->player, &state);

        if(state == PLAYER_STATE_PLAYING)
        {
            player_pause(this->player);
        }
    }
}

static camera_h _create_camera(camera_player_view *this)
{
    window_obj *win_obj = this->app->win;

    RETVM_IF(!win_obj, NULL, "win_obj is null");

    camera_h camera = NULL;

    if(camera_create(CAMERA_DEVICE_CAMERA0, &camera) == CAMERA_ERROR_NONE)
    {
        camera_set_display(camera, CAMERA_DISPLAY_TYPE_EVAS, GET_DISPLAY(this->camera_rect));
        camera_attr_set_preview_fps(camera, CAMERA_ATTR_FPS_30);
    }

    return camera;
}

static void _destroy_camera(camera_player_view *this)
{
    if(this->camera)
    {
        _stop_camera(this);
        camera_destroy(this->camera);
        this->camera = NULL;
    }
}

static void _start_camera(camera_player_view *this)
{
    if(!this->camera)
    {
        this->camera = _create_camera(this);
    }

    if(this->camera)
    {
        camera_state_e state;
        camera_get_state(this->camera, &state);

        if(state != CAMERA_STATE_PREVIEW)
        {
            camera_start_preview(this->camera);
        }
    }
}

static void _stop_camera(camera_player_view *this)
{
    if(this->camera)
    {
        camera_state_e state;
        camera_get_state(this->camera, &state);

        if(state == CAMERA_STATE_PREVIEW)
        {
            camera_stop_preview(this->camera);
        }
    }
}

static void _destroy(camera_player_view *this)
{
    app_reset_cbs(this->app);
    _destroy_player(this);
    _destroy_camera(this);
    free(this);
}

static void _push(camera_player_view *this)
{
    this->frame_item = elm_naviframe_item_push(this->navi, "Camera and player", NULL, NULL, this->layout, NULL);

    this->toolbar = _toolbar_add(this, this->navi);
    elm_object_item_part_content_set(this->frame_item, "toolbar", this->toolbar);
}

static Evas_Object *_main_layout_add(camera_player_view *this, Evas_Object *parent)
{
    Evas_Object *layout = elm_layout_add(parent);
    this->layout = layout;

    elm_layout_file_set(layout, CAMERAPLAYEREDJ, "camera_player");

    evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_show(layout);

    Evas_Object * cam_label = _label_add(layout, "Camera preview");
    Evas_Object * vedeo_label = _label_add(layout, "Video player");

    Evas *evas = evas_object_evas_get(parent);
    this->video_rect = evas_object_image_filled_add(evas);
    evas_object_show(this->video_rect);

    this->camera_rect = evas_object_image_filled_add(evas);
    evas_object_show(this->camera_rect);

    elm_object_part_content_set(layout, "camera_text", cam_label);
    elm_object_part_content_set(layout, "video_text", vedeo_label);

    elm_object_part_content_set(layout, "camera_view", this->camera_rect );
    elm_object_part_content_set(layout, "video_view", this->video_rect);

    return layout;
}

static Evas_Object *_label_add(Evas_Object *parent, const char *text)
{
    char buf[MAX_LABEL_LEN] = {'\0'};

    Evas_Object *obj = elm_label_add(parent);
    evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    evas_object_size_hint_align_set(obj, 0.5, 0.5);
    evas_object_show(obj);

    snprintf(buf, MAX_LABEL_LEN, "<p align=center >%s</p>", text);
    elm_object_text_set(obj, buf);

    return obj;
}

static Evas_Object *_toolbar_add(camera_player_view *this, Evas_Object *parent)
{
    Evas_Object *toolbar = elm_toolbar_add(parent);

    evas_object_size_hint_weight_set(toolbar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    evas_object_size_hint_align_set(toolbar, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_show(toolbar);

    elm_toolbar_select_mode_set(toolbar, ELM_OBJECT_SELECT_MODE_NONE);
    elm_toolbar_shrink_mode_set(toolbar, ELM_TOOLBAR_SHRINK_EXPAND);
    elm_toolbar_transverse_expanded_set(toolbar, EINA_TRUE);

    this->toolbar_item = elm_toolbar_item_append(toolbar, NULL, STR_START, _on_toolbar_btn_pressed_cb, this);

    return toolbar;
}

static void _on_toolbar_btn_pressed_cb(void *data, Evas_Object *obj, void *event_info)
{
    camera_player_view *this = data;

    if(this)
    {
        if(this->play)
        {
            _stop(this);
        }
        else
        {
            _start(this);
        }
    }
}

static void _on_pause_cb(void *user_data)
{
    camera_player_view *this = user_data;

    if(this)
    {
        _pause(this);
    }
}

static void _on_resume_cb(void *user_data)
{
    camera_player_view *this = user_data;

    if(this)
    {
        _resume(this);
    }
}

static void _on_main_layout_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
    camera_player_view *this = data;

    if(this)
    {
        _destroy(this);
    }
}
