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

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

static const int limit_seconds = 20;

static const char *frame_label_str = "Video recorder & player";
static const char *video_recorder_str = "Video Recorder";
static const char *video_player_str = "Video player";
static const char *label_template = "<p font_size=20 align=left >%s</p>";

struct _video_recorder_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;
    Evas_Object *progress_bar;

    player_h player;
    camera_h camera;
    recorder_h recorder;
    bool play;

    Elm_Object_Item *toolbar_item;
};

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

static void _start(video_recorder_player_view *view);
static void _stop(video_recorder_player_view *view);
static void _pause(video_recorder_player_view *view);
static void _resume(video_recorder_player_view *view);

static player_h _create_player(video_recorder_player_view *view);
static void _destroy_player(video_recorder_player_view *view);
static void _start_player(video_recorder_player_view *view);
static void _stop_player(video_recorder_player_view *view);
static void _pause_player(video_recorder_player_view *view);

static void _create_video_recorder(video_recorder_player_view *view);
static void _destroy_video_recorder(video_recorder_player_view *view);
static void _destroy_camera(video_recorder_player_view *view);
static void _start_video_recorder(video_recorder_player_view *view);
static void _stop_video_recorder(video_recorder_player_view *view);
static void _on_record_completed(video_recorder_player_view *view);

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);
static void _player_cb(player_state state, void *user_data);
static Evas_Object *_add_progress_bar(Evas_Object *parent);

video_recorder_player_view *video_recorder_player_view_add(app_data *app, Evas_Object *navi)
{
    if(!app)
    {
        return NULL;
    }

    video_recorder_player_view *view = calloc(1, sizeof(video_recorder_player_view));

    if(view)
    {
        view->navi = navi;
        view->app = app;
        win_set_view_style(app->win, STYLE_VIDEO_RECORDER_PLAYER);
        view->layout = _main_layout_add(view, navi);

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

    return view;
}

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

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

static void _start(video_recorder_player_view *view)
{
    view->play = true;
    _start_player(view);
    _start_video_recorder(view);
    elm_object_item_text_set(view->toolbar_item, STR_STOP);
}

static void _stop(video_recorder_player_view *view)
{
    view->play = false;
    elm_object_item_disabled_set(view->toolbar_item, EINA_TRUE);
    _stop_player(view);
    _stop_video_recorder(view);
    _on_record_completed(view);
    elm_object_item_text_set(view->toolbar_item, STR_START);
}

static void _pause(video_recorder_player_view *view)
{
    _pause_player(view);
    _stop_video_recorder(view);
}

static void _resume(video_recorder_player_view *view)
{
    if(view->play)
    {
        _start_player(view);
        _start_video_recorder(view);
    }
}

static player_h _create_player(video_recorder_player_view *view)
{
    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(view->video_rect));
        player_prepare(player);
    }

    return player;
}

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

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

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

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

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

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

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

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

static void _limit_reached_cb(recorder_recording_limit_type_e type, void *user_data)
{
    if(user_data)
    {
        video_recorder_player_view *view = (video_recorder_player_view *)user_data;
        _stop(view);
    }
}

static void _record_status_cb(unsigned long long elapsed_time, unsigned long long file_size, void *user_data)
{
    if(user_data)
    {
        video_recorder_player_view *view = (video_recorder_player_view *)user_data;
        int elapsed_seconds = (int)elapsed_time/1000;
        double progress = (double)elapsed_seconds/limit_seconds;
        elm_progressbar_value_set(view->progress_bar, progress);
    }
}

static void _on_record_completed(video_recorder_player_view *view)
{
    elm_progressbar_value_set(view->progress_bar, 0.0);

    elm_object_item_content_unset(view->frame_item);
    evas_object_hide(view->layout);

    win_set_view_style(view->app->win, STYLE_DEFAULT_WINDOW);
    video_player_view_add(view->app, view->navi, get_data_path(RECORDERED_3GP_VIDEO), _player_cb, view);
}

static void _player_cb(player_state state, void *user_data)
{
    video_recorder_player_view *view = (video_recorder_player_view *)user_data;
    if(view)
    {
        switch (state)
        {
            case STATE_DESTROYED:
                _register_app_cbs(view);
                break;
            case STATE_FINISHED:
                win_set_view_style(view->app->win, STYLE_VIDEO_RECORDER_PLAYER);
                elm_object_item_content_set(view->frame_item, view->layout);
                elm_object_item_disabled_set(view->toolbar_item, EINA_FALSE);
                break;
            default:
                break;
        }
    }
}

static void _create_video_recorder(video_recorder_player_view *view)
{
    _destroy_camera(view);

    if(camera_create(CAMERA_DEVICE_CAMERA0, &view->camera) == CAMERA_ERROR_NONE)
    {
        camera_set_display(view->camera, CAMERA_DISPLAY_TYPE_EVAS, GET_DISPLAY(view->camera_rect));
        recorder_create_videorecorder(view->camera, &view->recorder);
        if(view->recorder)
        {
            recorder_set_file_format(view->recorder, RECORDER_FILE_FORMAT_3GP);
            recorder_set_filename(view->recorder, get_data_path(RECORDERED_3GP_VIDEO));
            recorder_attr_set_time_limit(view->recorder, limit_seconds);
            recorder_set_recording_limit_reached_cb(view->recorder, _limit_reached_cb, view);
            recorder_set_recording_status_cb(view->recorder, _record_status_cb, view);
            recorder_prepare(view->recorder);
        }
    }
}

static void _destroy_camera(video_recorder_player_view *view)
{
    if(view->camera)
    {
        camera_stop_preview(view->camera);
        camera_destroy(view->camera);
        view->camera = NULL;
    }
}

static void _destroy_video_recorder(video_recorder_player_view *view)
{
    if(view->recorder)
    {
        recorder_state_e state = RECORDER_STATE_NONE;
        recorder_get_state(view->recorder, &state);
        if(state == RECORDER_STATE_RECORDING || state == RECORDER_STATE_PAUSED)
        {
            recorder_cancel(view->recorder);
        }
        recorder_unprepare(view->recorder);
        recorder_destroy(view->recorder);
        view->recorder = NULL;
    }
    _destroy_camera(view);
}

static void _start_video_recorder(video_recorder_player_view *view)
{
    if(!view->recorder)
    {
        _create_video_recorder(view);
    }
    if(view->recorder)
    {
        recorder_start(view->recorder);
    }
}

static void _job_recorder_destroy(void *data)
{
    video_recorder_player_view *view = (video_recorder_player_view *)data;
    if(view)
    {
        recorder_destroy(view->recorder);
        view->recorder = NULL;
    }
}

static void _stop_video_recorder(video_recorder_player_view *view)
{
    if(view->recorder)
    {
        recorder_commit(view->recorder);
        recorder_unprepare(view->recorder);
        ecore_job_add(_job_recorder_destroy, view);
    }
    _destroy_camera(view);
}

static void _destroy(video_recorder_player_view *view)
{
    app_reset_cbs(view->app);
    _destroy_player(view);
    _destroy_video_recorder(view);
    free(view);
}

static void _push(video_recorder_player_view *view)
{
    view->frame_item = elm_naviframe_item_push(view->navi, frame_label_str, NULL, NULL, view->layout, NULL);

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

static Evas_Object *_main_layout_add(video_recorder_player_view *view, Evas_Object *parent)
{
    Evas_Object *layout = elm_layout_add(parent);
    view->layout = layout;

    elm_layout_file_set(layout, VIDEO_RECORDER_PLAYER_EDJ, "video_recorder_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, video_recorder_str);
    Evas_Object *video_label = _label_add(layout, video_player_str);

    Evas *evas = evas_object_evas_get(parent);
    view->video_rect = evas_object_image_filled_add(evas);
    view->camera_rect = evas_object_image_filled_add(evas);

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

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

    view->progress_bar = _add_progress_bar(layout);
    elm_object_part_content_set(layout, "swallow.progressbar", view->progress_bar);

    return layout;
}

static Evas_Object *_add_progress_bar(Evas_Object *parent)
{
    Evas_Object *progressbar = NULL;
    if(parent)
    {
        progressbar = elm_progressbar_add(parent);
        elm_object_style_set(progressbar, "list_progress");
        evas_object_size_hint_align_set(progressbar, EVAS_HINT_FILL, 0.5);
        evas_object_size_hint_weight_set(progressbar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
        elm_progressbar_value_set(progressbar, 0.0);
        evas_object_show(progressbar);
    }
    return progressbar;
}

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, label_template, text);
    elm_object_text_set(obj, buf);

    return obj;
}

static Evas_Object *_toolbar_add(video_recorder_player_view *view, 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);

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

    return toolbar;
}

static void _on_toolbar_btn_pressed_cb(void *data, Evas_Object *obj, void *event_info)
{
    video_recorder_player_view *view = data;

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

static void _on_pause_cb(void *user_data)
{
    video_recorder_player_view *view = user_data;

    if(view)
    {
        _pause(view);
    }
}

static void _on_resume_cb(void *user_data)
{
    video_recorder_player_view *view = user_data;

    if(view)
    {
        _resume(view);
    }
}

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

    if(view)
    {
        win_set_view_style(view->app->win, STYLE_DEFAULT_WINDOW);
        _destroy(view);
    }
}
