/*
 * 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/video-recorder-view.h"
#include "../../player/inc/video-player-view.h"
#include "../../common/inc/ui-utils.h"
#include "../../common/inc/main-app.h"
#include "../../common/inc/list-popup.h"
#include "../../common/inc/radio-popup.h"
#include "../../common/inc/slider-popup.h"
#include "camera_recorder_settings.h"
#include <player.h>
#include <camera.h>
#include <recorder.h>
#include <Elementary.h>

#define LABEL_LEN 64

static const int limit_seconds = 20;

static const char *frame_label_str = "Video recorder";
static const char *start_str = "Start";
static const char *stop_str = "Stop";
static const char *settings_str = "Settings";

static const char *time_label_template = "<p font_size=20 color=#0000DDFF>%02u:%02u</p>";
static const char *bytes_label_template = "<p font_size=20 color=#0000DDFF>%2llu KB</p>";

typedef void (*process_func)(video_recorder_view *view, int val);

struct _video_recorder_view
{
    app_data *app;
    Elm_Object_Item *frame_item;
    Evas_Object *navi;
    Evas_Object *layout;
    Evas_Object *toolbar;
    Evas_Object *camera_rect;
    Evas_Object *progress_bar;
    Evas_Object *label_time;
    Evas_Object *label_bytes;

    Evas_Object *settings_popup;
    camera_h camera;
    recorder_h recorder;

    app_device_orientation_e rotation;

    Elm_Object_Item *settings_item;
    Elm_Object_Item *record_item;

    Eina_Bool recording;
    char file_path[PATH_MAX];

    Eina_List *resolution_list;
    process_func popup_proc_func;

    preprocessing_state pre_processing;
};

typedef enum
{
    ST_BRIGHTNESS,
    ST_FOCUSMODE,
    ST_ISOLEVEL,
    ST_WHITEBALANCE,
    ST_SCENEMODE,
    ST_EFFECT,
    ST_ZOOMLEVEL,
    ST_FRAMERATE,
    ST_ROTATETYPE,
    ST_RECRESOLUTION,
    ST_RECQUALITY,
    ST_VIDEOCODEC,
    ST_AUDIOCODEC,
    ST_FILEFORMAT,
    ST_PREVIEWFORMAT,
    ST_EXPOSURE,
    ST_PREPROCESSING,
    ST_MAX
}settings_type;

static const char * settings[ST_MAX] =
{
    "Brightness",
    "Focus Mode",
    "IsoLevel",
    "WhiteBalance",
    "Scene Mode",
    "Effect",
    "ZoomLevel",
    "Frame Rate",
    "Rotation",
    "Recording Resolution",
    "Recording Quality",
    "Video Codec",
    "Audio Codec",
    "File Format",
    "Preview Format",
    "Exposure",
    "Video Pre-Processing"
};

static const char *result_template_str = "video_record.%s";

static const char *video_file_extension[] =
{
    "3gp",
    "mp4"
};

static void _destroy(video_recorder_view *view);
static void _push(video_recorder_view *view);
static Evas_Object *_main_layout_add(video_recorder_view *view, Evas_Object *parent);
static Evas_Object *_toolbar_add(video_recorder_view *view, Evas_Object *parent);
static Evas_Object *_add_progress_bar(Evas_Object *parent);
static void _register_app_cbs(video_recorder_view *view);
static void _unregister_app_cbs(video_recorder_view *view);
static void _process_settings(video_recorder_view *view, settings_type type);
static void _create_video_resolution_settings(video_recorder_view *view);
static void _create_brightness_settings(video_recorder_view *view);
static void _create_zoom_settings(video_recorder_view *view);

static void _prepare(video_recorder_view *view);
static void _start(video_recorder_view *view);
static void _stop(video_recorder_view *view);
static void _pause(video_recorder_view *view);
static void _resume(video_recorder_view *view);

static void _create_camera(video_recorder_view *view);
static void _destroy_camera(video_recorder_view *view);

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

static void _on_radio_popup_closed_cb(radio_popup *obj, bool result, void *user_data);
static void _on_list_popup_closed_cb(list_popup *obj, bool result, void *user_data);
static void _on_slider_popup_closed_cb(slider_popup *obj, bool result, void *user_data);
static void _on_list_popup_selected_item_cb(list_popup *obj, void *user_data);
static void _on_resolution_popup_selected_item_cb(radio_popup *obj, void *user_data);
static void _on_spec_settings_popup_selected_item_cb(radio_popup *obj, void *user_data);

static void _on_resume_cb(void *user_data);
static void _on_pause_cb(void *user_data);
static void _on_rotate_cb(app_event_info_h event_info, void *user_data);
static void _on_toolbar_settings_cb(void *data, Evas_Object *obj, void *event_info);
static void _on_toolbar_record_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 _on_transition_finished(void *data, Evas_Object *obj, void *event_info);
static void _label_time_set(Evas_Object *label, unsigned int seconds);
static void _label_bytes_set(Evas_Object *label, unsigned long long bytes);
static void _set_rotation_theme(video_recorder_view *view);

static void _get_supported_resolution_list(video_recorder_view *view);
static void _destroy_supported_resolution_list(video_recorder_view *view);
static void _camera_preview_preprocess_cb(camera_preview_data_s *frame, void *user_data);

static void _player_cb(player_state state, void *user_data);

video_recorder_view *video_recorder_view_add(app_data *app, Evas_Object *navi)
{
    if(!app)
    {
        return NULL;
    }

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

    if(view)
    {
        view->navi = navi;
        view->app = app;
        view->rotation = app_get_device_orientation();
        win_set_rotation(app->win, (int)view->rotation);
        view->layout = _main_layout_add(view, navi);
        view->pre_processing = PREPROCESSING_OFF;
        view->resolution_list = NULL;
        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_view *view)
{
    app_cbs cbs =
    {
       .pause = _on_pause_cb,
       .resume = _on_resume_cb
    };

    ui_app_add_event_handler(&cbs.event_handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED],
                             APP_EVENT_DEVICE_ORIENTATION_CHANGED, _on_rotate_cb, view);

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

static void _unregister_app_cbs(video_recorder_view *view)
{
    ui_app_remove_event_handler(view->app->cb.event_handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED]);
    app_reset_cbs(view->app);
}

static void _prepare(video_recorder_view *view)
{
    _create_camera(view);
    if(view->camera)
    {
        _create_video_recorder(view);
    }
}

static void _start(video_recorder_view *view)
{
    view->recording = EINA_TRUE;
    _start_video_recorder(view);
    elm_object_item_text_set(view->record_item, stop_str);
    elm_object_item_disabled_set(view->settings_item, EINA_TRUE);
}

static void _stop(video_recorder_view *view)
{
    view->recording = EINA_FALSE;
    elm_object_item_disabled_set(view->record_item, EINA_TRUE);
    elm_object_item_disabled_set(view->settings_item, EINA_FALSE);
    _stop_video_recorder(view);
    _destroy_camera(view);
    _label_bytes_set(view->label_bytes, 0);
    _label_time_set(view->label_time, 0);
    elm_progressbar_value_set(view->progress_bar, 0.0);
    elm_object_item_text_set(view->record_item, start_str);

    _on_record_completed(view);
}

static void _pause(video_recorder_view *view)
{
    view->recording = EINA_FALSE;
    _destroy_video_recorder(view);
    _destroy_camera(view);

    _label_bytes_set(view->label_bytes, 0);
    _label_time_set(view->label_time, 0);
    elm_progressbar_value_set(view->progress_bar, 0.0);
    elm_object_item_text_set(view->record_item, start_str);
    elm_object_item_disabled_set(view->settings_item, EINA_FALSE);
}

static void _resume(video_recorder_view *view)
{
    _prepare(view);
}

static void _on_pause_cb(void *user_data)
{
    video_recorder_view *view = (video_recorder_view *)user_data;
    if(view)
    {
        _pause(view);
    }
}

static void _on_resume_cb(void *user_data)
{
    video_recorder_view *view = (video_recorder_view *)user_data;
    if(view)
    {
        _resume(view);
    }
}

static void _limit_reached_cb(recorder_recording_limit_type_e type, void *user_data)
{
    video_recorder_view *view = (video_recorder_view *)user_data;
    if(view)
    {
        _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_view *view = (video_recorder_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);

        _label_bytes_set(view->label_bytes, file_size);
        _label_time_set(view->label_time, elapsed_seconds);
    }
}

static void _on_record_completed(video_recorder_view *view)
{
    _unregister_app_cbs(view);
    win_set_view_style(view->app->win, STYLE_DEFAULT_WINDOW);
    video_player_view_add(view->app, view->navi, view->file_path, _player_cb, view);
}

static void _on_rotate_cb(app_event_info_h event_info, void *user_data)
{
    video_recorder_view *view = (video_recorder_view *)user_data;
    if(view)
    {
        app_event_get_device_orientation(event_info, &view->rotation);
        win_set_rotation(view->app->win, (int)view->rotation);
        _set_rotation_theme(view);
    }
}

static void _recorder_file_format_set(video_recorder_view *view, recorder_file_format_e format)
{
    char file_name[NAME_MAX] = {'\0'};

    char *data_path = app_get_data_path();
    snprintf(file_name, NAME_MAX, result_template_str, video_file_extension[format]);
    snprintf(view->file_path, PATH_MAX, "%s%s", data_path, file_name);
    free(data_path);

    recorder_set_file_format(view->recorder, format);
    recorder_set_filename(view->recorder, view->file_path);
}

static void _create_video_recorder(video_recorder_view *view)
{
    if(view->recorder)
    {
        _destroy_video_recorder(view);
    }
    recorder_create_videorecorder(view->camera, &view->recorder);
    if(view->recorder)
    {
        _recorder_file_format_set(view, RECORDER_FILE_FORMAT_3GP);
        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 _start_video_recorder(video_recorder_view *view)
{
    if(view->recorder)
    {
        recorder_start(view->recorder);
    }
}

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

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

static void _destroy_video_recorder(video_recorder_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;
    }
}

static void _create_camera(video_recorder_view *view)
{
     if(view->camera)
     {
         _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));
         camera_set_display_mode(view->camera, CAMERA_DISPLAY_MODE_FULL);
         if(view->pre_processing == PREPROCESSING_ON)
         {
             camera_set_preview_cb(view->camera, _camera_preview_preprocess_cb, view);
         }
     }
     else
     {
         view->camera = NULL;
     }
}

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

static void _destroy(video_recorder_view *view)
{
    _unregister_app_cbs(view);
    _destroy_supported_resolution_list(view);
    _destroy_video_recorder(view);
    _destroy_camera(view);
    free(view);
}

static void _push(video_recorder_view *view)
{
    evas_object_smart_callback_add(view->navi, "transition,finished", _on_transition_finished, 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 void _on_transition_finished(void *data, Evas_Object *obj, void *event_info)
{
    video_recorder_view *view = (video_recorder_view *)data;
    if(view)
    {
        _prepare(view);
        evas_object_smart_callback_del(view->navi, "transition,finished", _on_transition_finished);
    }
}

static void _label_time_set(Evas_Object *label, unsigned int seconds)
{
    char buf[LABEL_LEN] = {'\0'};

    snprintf(buf, LABEL_LEN, time_label_template, seconds / 60, seconds % 60);
    elm_object_text_set(label, buf);
}

static void _label_bytes_set(Evas_Object *label, unsigned long long bytes)
{
    char buf[LABEL_LEN] = {'\0'};

    snprintf(buf, LABEL_LEN, bytes_label_template, bytes);
    elm_object_text_set(label, buf);
}

static Evas_Object *_add_label(Evas_Object *parent)
{
    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, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_show(obj);

    return obj;
}

static void _set_rotation_theme(video_recorder_view *view)
{
    if(APP_DEVICE_ORIENTATION_90 == view->rotation || APP_DEVICE_ORIENTATION_270 == view->rotation)
    {
        elm_layout_file_set(view->layout, VIDEO_RECORDER_PLAYER_EDJ, "recorder_landscape");
        win_show_indicator(view->app->win, EINA_FALSE);
    }
    else
    {
        elm_layout_file_set(view->layout, VIDEO_RECORDER_PLAYER_EDJ, "recorder_portrait");
        win_show_indicator(view->app->win, EINA_TRUE);
    }
}

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

    _set_rotation_theme(view);
    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 *evas = evas_object_evas_get(parent);
    view->camera_rect = evas_object_image_filled_add(evas);
    elm_object_part_content_set(layout, "swallow.render", view->camera_rect );

    view->label_time = _add_label(layout);
    view->label_bytes = _add_label(layout);

    _label_bytes_set(view->label_bytes, 0);
    _label_time_set(view->label_time, 0);

    elm_object_part_content_set(layout, "swallow.label.time", view->label_time);
    elm_object_part_content_set(layout, "swallow.label.bytes", view->label_bytes);

    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 *_toolbar_add(video_recorder_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->settings_item = elm_toolbar_item_append(toolbar, NULL, settings_str, _on_toolbar_settings_cb, view);
    view->record_item = elm_toolbar_item_append(toolbar, NULL, start_str, _on_toolbar_record_cb, view);

    return toolbar;
}

static void _on_toolbar_settings_cb(void *data, Evas_Object *obj, void *event_info)
{
    video_recorder_view *view = (video_recorder_view *)data;
    list_popup *popup = list_popup_add(view->app->win->win, ELM_POPUP_ORIENT_CENTER, settings_str);
    list_popup_callback_set(popup, _on_list_popup_selected_item_cb, _on_list_popup_closed_cb, view);

    int i = 0;
    for (; i<ST_MAX; i++)
    {
        list_popup_item_add(popup, settings[i], i);
    }
    list_popup_show(popup);
}

static void _on_toolbar_record_cb(void *data, Evas_Object *obj, void *event_info)
{
    video_recorder_view *view = (video_recorder_view *)data;

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

static void _player_cb(player_state state, void *user_data)
{
    video_recorder_view *view = (video_recorder_view *)user_data;
    if(view)
    {
        switch (state)
        {
            case STATE_DESTROYED:
                _register_app_cbs(view);
                _prepare(view);
                break;
            case STATE_FINISHED:
                view->rotation = app_get_device_orientation();
                win_set_rotation(view->app->win, (int)view->rotation);
                elm_object_item_disabled_set(view->record_item, EINA_FALSE);
                _set_rotation_theme(view);
                break;
            default:
                break;
        }
    }
}

static void _on_main_layout_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
    video_recorder_view *view = (video_recorder_view *)data;
    if(view)
    {
        win_set_view_style(view->app->win, STYLE_DEFAULT_WINDOW);
        _destroy(view);
    }
}

//Settings
static void _process_focus_mode_settings(video_recorder_view *view, int val)
{
    camera_attr_set_af_mode(view->camera, (camera_attr_af_mode_e)val);
}

static void _process_iso_level_settings(video_recorder_view *view, int val)
{
    camera_attr_set_iso(view->camera, (camera_attr_iso_e)val);
}

static void _process_white_balance_settings(video_recorder_view *view, int val)
{
    camera_attr_set_whitebalance(view->camera, (camera_attr_whitebalance_e)val);
}

static void _process_scene_mode_settings(video_recorder_view *view, int val)
{
    camera_attr_set_scene_mode(view->camera, (camera_attr_scene_mode_e)val);
}

static void _process_effect_settings(video_recorder_view *view, int val)
{
    camera_attr_set_effect(view->camera, (camera_attr_effect_mode_e)val);
}

static void _process_fps_settings(video_recorder_view *view, int val)
{
    camera_stop_preview(view->camera);
    int ret = camera_attr_set_preview_fps(view->camera, (camera_attr_fps_e)val);
    INF("Frame rate result = %d\n", ret);
    camera_start_preview(view->camera);
}

static void _process_rotation_settings(video_recorder_view *view, int val)
{
    camera_stop_preview(view->camera);
    camera_set_display_rotation(view->camera, (camera_rotation_e)val);
    recorder_attr_set_orientation_tag(view->recorder, (recorder_rotation_e)val);
    camera_start_preview(view->camera);
}

static void _process_quality_settings(video_recorder_view *view, int val)
{
    int current_width = 0;
    int current_height = 0;
    camera_get_preview_resolution(view->camera, &current_width, &current_height);
    int video_bitrate = camera_settings_quality_bitrate_get(current_width, current_height, val);

    if(video_bitrate > 0)
    {
        int ret = recorder_attr_set_video_encoder_bitrate(view->recorder, video_bitrate);
        INF("Bitrate result = %d\n", ret);
    }
}

static void _process_video_codec_settings(video_recorder_view *view, int val)
{
    int ret = recorder_set_video_encoder(view->recorder, (recorder_video_codec_e)val);
    INF("Video encoder result = %d\n", ret);
}

static void _process_audio_codec_settings(video_recorder_view *view, int val)
{
    recorder_set_audio_encoder(view->recorder, (recorder_audio_codec_e)val);
}

static void _process_file_format_settings(video_recorder_view *view, int val)
{
    recorder_unprepare(view->recorder);
    _recorder_file_format_set(view, (recorder_file_format_e)val);
    recorder_prepare(view->recorder);
}

static void _process_preview_settings(video_recorder_view *view, int val)
{
    camera_stop_preview(view->camera);
    camera_set_preview_format(view->camera, (camera_pixel_format_e)val);
    camera_start_preview(view->camera);
}

static void _process_exposure_mode_settings(video_recorder_view *view, int val)
{
    camera_attr_set_exposure_mode(view->camera, (camera_attr_exposure_mode_e)val);
}

static void _camera_preview_preprocess_cb(camera_preview_data_s *frame, void *user_data)
{
    if(frame)
    {
        if(frame->num_of_planes == 1)
        {
            int v = 0;
            int u;
            for(u = 0; u < frame->data.single_plane.size; u += 4)//UYVY format: U0 Y0 V0 Y1, U1 Y2 V1 Y3, ... . U-i swap with V-i;
            {
                v = u + 2;
                if(v < frame->data.single_plane.size)
                {
                    frame->data.single_plane.yuv[u] ^= frame->data.single_plane.yuv[v];
                    frame->data.single_plane.yuv[v] ^= frame->data.single_plane.yuv[u];
                    frame->data.single_plane.yuv[u] ^= frame->data.single_plane.yuv[v];
                }
            }
        }
        else if(frame->num_of_planes == 2)
        {
            int i;
            for(i = 0; i < frame->data.double_plane.uv_size; i++)
            {
                frame->data.double_plane.uv[i] = rand()%256;
            }
        }
        else if(frame->num_of_planes == 3)
        {
            int i;
            for(i = 0; i < frame->data.triple_plane.u_size; i++)
            {
                if(i < frame->data.triple_plane.v_size)
                {
                    frame->data.triple_plane.u[i] ^= frame->data.triple_plane.v[i];
                    frame->data.triple_plane.v[i] ^= frame->data.triple_plane.u[i];
                    frame->data.triple_plane.u[i] ^= frame->data.triple_plane.v[i];
                }
           }
        }
    }
}

static void _preprocessing_mode_settings(video_recorder_view *view, int val)
{
    view->pre_processing = val;
    if(val == PREPROCESSING_ON)
    {
        camera_stop_preview(view->camera);
        camera_set_preview_cb(view->camera, _camera_preview_preprocess_cb, view);
        camera_start_preview(view->camera);
    }
    else if(val == PREPROCESSING_OFF)
    {
        camera_stop_preview(view->camera);
        camera_unset_preview_cb(view->camera);
        camera_start_preview(view->camera);
    }
}


static bool _settings_supported(int supported_type, void *user_data)
{
    settings_supported_data *supported_data = (settings_supported_data *)user_data;
    int i = camera_settings_item_number_get(supported_data, supported_type);
    supported_data->supported[i] = true;

    return true;
}

static void _create_spec_settings( void *view
                                 , Evas_Object *parent
                                 , settings_type type
                                 , const int max_type
                                 , const settings_data *data
                                 , void *media_device
                                 , register_supported_func supported_func
                                 , int default_val)
{
    bool *supported = calloc(max_type, sizeof(bool));
    settings_supported_data supported_data;
    supported_data.data = data;
    supported_data.max_data_type = max_type;
    supported_data.supported = supported;

    radio_popup *popup = radio_popup_add(parent, ELM_POPUP_ORIENT_CENTER, settings[type]);
    radio_popup_callback_set(popup, _on_spec_settings_popup_selected_item_cb, _on_radio_popup_closed_cb, view);

    if(supported_func)
    {
        supported_func(media_device, _settings_supported, &supported_data);
    }

    int i = 0;
    Elm_Object_Item *item = NULL;
    for(; i < max_type; i++)
    {
        item = radio_popup_item_add(popup, data[i].label, data[i].mode);
        if(supported_func && !supported[i] && i>0)
        {
            elm_object_item_disabled_set(item, EINA_TRUE);
        }
    }
    free(supported);
    radio_popup_select_item(popup, data[default_val].mode);
    radio_popup_show(popup);
}

static void _process_settings(video_recorder_view *view, settings_type type)
{
    int array_max = 0;
    const settings_data *data = NULL;
    void *media_device = view->camera;
    register_supported_func register_func = NULL;
    process_func proc_func = NULL;
    int val = 0;

    switch(type)
    {
        case ST_BRIGHTNESS:
            return _create_brightness_settings(view);
        break;
        case ST_FOCUSMODE:
            array_max = focus_mode_max;
            data = focus_mode;
            register_func = (register_supported_func)camera_attr_foreach_supported_af_mode;
            proc_func = _process_focus_mode_settings;
        break;
        case ST_ISOLEVEL:
            array_max = iso_level_max_type;
            data = iso_level;
            register_func = (register_supported_func)camera_attr_foreach_supported_iso;
            proc_func = _process_iso_level_settings;
        break;
        case ST_WHITEBALANCE:
            array_max = white_balance_max_type;
            data = white_balance;
            register_func = (register_supported_func)camera_attr_foreach_supported_whitebalance;
            proc_func = _process_white_balance_settings;
        break;
        case ST_SCENEMODE:
            array_max = scene_mode_max_type;
            data = scene_mode;
            register_func = (register_supported_func)camera_attr_foreach_supported_scene_mode;
            proc_func = _process_scene_mode_settings;
        break;
        case ST_EFFECT:
            array_max = effect_max_type;
            data = effect;
            register_func = (register_supported_func)camera_attr_foreach_supported_effect;
            proc_func = _process_effect_settings;
        break;
        case ST_ZOOMLEVEL:
            return _create_zoom_settings(view);
        break;
        case ST_FRAMERATE:
            array_max = fps_max_type;
            data = fps;
            register_func = (register_supported_func)camera_attr_foreach_supported_fps;
            proc_func = _process_fps_settings;
        break;
        case ST_ROTATETYPE:
            array_max = rotation_max_type;
            data = rotation;
            proc_func = _process_rotation_settings;
        break;
        case ST_RECRESOLUTION:
            return _create_video_resolution_settings(view);
        break;
        case ST_RECQUALITY:
            array_max = quality_max_type;
            data = quality;
            proc_func = _process_quality_settings;
        break;
        case ST_VIDEOCODEC:
            array_max = video_codec_max_type;
            data = video_codec;
            media_device = view->recorder;
            register_func = (register_supported_func)recorder_foreach_supported_video_encoder;
            proc_func = _process_video_codec_settings;
        break;
        case ST_AUDIOCODEC:
            array_max = audio_codec_max_type;
            data = audio_codec;
            media_device = view->recorder;
            register_func = (register_supported_func)recorder_foreach_supported_audio_encoder;
            proc_func = _process_audio_codec_settings;
        break;
        case ST_FILEFORMAT:
            array_max = file_format_max_type;
            data = file_format;
            media_device = view->recorder;
            register_func = (register_supported_func)recorder_foreach_supported_file_format;
            proc_func = _process_file_format_settings;
        break;
        case ST_PREVIEWFORMAT:
            array_max = preview_format_max_type;
            data = preview_format;
            register_func = (register_supported_func)camera_foreach_supported_preview_format;
            proc_func = _process_preview_settings;
        break;
        case ST_EXPOSURE:
            array_max = exposure_mode_max_type;
            data = exposure_mode;
            register_func = (register_supported_func)camera_attr_foreach_supported_exposure_mode;
            proc_func = _process_exposure_mode_settings;
        break;
        case ST_PREPROCESSING:
            array_max = preprocessing_max_type;
            data = preprocessing_mode;
            proc_func = _preprocessing_mode_settings;
            val = view->pre_processing;
        break;
        default:
            return;
        break;
    }
    _create_spec_settings(view, view->app->win->win, type, array_max, data, media_device, register_func, val);
    view->popup_proc_func = proc_func;
}

//Video Resolution Settings
static bool _supported_resolution(int width, int height, void *user_data)
{
    video_recorder_view *view = (video_recorder_view *)user_data;
    resolution_item *item = calloc(1, sizeof(resolution_item));
    if(item)
    {
        item->width = width;
        item->height = height;
        view->resolution_list = eina_list_append(view->resolution_list, item);
    }

    return true;
}

static void _get_supported_resolution_list(video_recorder_view *view)
{
    if(!view->resolution_list)
    {
        camera_foreach_supported_preview_resolution(view->camera, _supported_resolution, view);
    }
}

static void _destroy_supported_resolution_list(video_recorder_view *view)
{
    if(view->resolution_list)
    {
        resolution_item *item = NULL;
        EINA_LIST_FREE(view->resolution_list, item)
        {
            free(item);
        }
        view->resolution_list = NULL;
    }
}

static void _create_video_resolution_settings(video_recorder_view *view)
{
    _get_supported_resolution_list(view);

    int current_width = 0;
    int current_height = 0;
    int currrent_resolution = -1;
    camera_get_preview_resolution(view->camera, &current_width, &current_height);

    char resol_name[LABEL_LEN] = {'\0'};

    radio_popup *popup = radio_popup_add(view->app->win->win, ELM_POPUP_ORIENT_CENTER, settings[ST_RECRESOLUTION]);
    radio_popup_callback_set(popup, _on_resolution_popup_selected_item_cb, _on_radio_popup_closed_cb, view);

    int index = 0;
    Eina_List *list = NULL;
    resolution_item *item = NULL;
    EINA_LIST_FOREACH(view->resolution_list, list, item)
    {
        if(currrent_resolution < 0 && current_width == item->width && current_height == item->height)
        {
            currrent_resolution = index;
        }
        snprintf(resol_name, LABEL_LEN, "%dx%d", item->width, item->height);
        radio_popup_item_add(popup, resol_name, index);
        index++;
    }

    radio_popup_select_item(popup, currrent_resolution);
    radio_popup_show(popup);
}

static void _on_radio_popup_closed_cb(radio_popup *obj, bool result, void *user_data)
{
    radio_popup_del(obj);
}

static void _on_list_popup_closed_cb(list_popup *obj, bool result, void *user_data)
{
    list_popup_del(obj);
}

static void _on_slider_popup_closed_cb(slider_popup *obj, bool result, void *user_data)
{
    slider_popup_del(obj);
}

static void _on_list_popup_selected_item_cb(list_popup *obj, void *user_data)
{
    video_recorder_view *view = user_data;
    int value = list_popup_selected_item_value_get(obj);
    _process_settings(view, value);
    list_popup_del(obj);
}

static void _on_resolution_popup_selected_item_cb(radio_popup *obj, void *user_data)
{
    video_recorder_view *view = user_data;
    int index = radio_popup_selected_item_value_get(obj);
    resolution_item *item = (resolution_item *)eina_list_nth(view->resolution_list, index);
    camera_stop_preview(view->camera);
    int ret = camera_set_preview_resolution(view->camera, item->width, item->height);
    INF("Record resolution result = %d\n", ret);
    camera_start_preview(view->camera);
}

static void _on_spec_settings_popup_selected_item_cb(radio_popup *obj, void *user_data)
{
    video_recorder_view *view = user_data;
    if(view->popup_proc_func)
    {
        int index = radio_popup_selected_item_value_get(obj);
        view->popup_proc_func(view, index);
    }
}

static void _slider_brightness_cb(slider_popup *popup, void *user_data)
{
    video_recorder_view *view = user_data;
    int value = slider_popup_value_get(popup);
    camera_attr_set_brightness(view->camera, value);
}

static void _create_brightness_settings(video_recorder_view *view)
{
    slider_popup *popup = slider_popup_add(view->app, view->app->win->win, ELM_POPUP_ORIENT_CENTER, settings[ST_BRIGHTNESS]);
    slider_popup_label_set(popup, settings[ST_BRIGHTNESS]);

    int max = 0, min = 0, level = 0;
    camera_attr_get_brightness_range(view->camera, &min, &max);
    slider_popup_min_max_set(popup, min, max);

    camera_attr_get_brightness(view->camera, &level);
    slider_popup_value_set(popup, level);

    slider_popup_callback_set(popup, _slider_brightness_cb, _on_slider_popup_closed_cb, view);
    slider_popup_show(popup);
}

static void _slider_zoom_cb(slider_popup *popup, void *user_data)
{
    video_recorder_view *view = user_data;
    int value = slider_popup_value_get(popup);
    camera_attr_set_zoom(view->camera, value);
}

static void _create_zoom_settings(video_recorder_view *view)
{
    slider_popup *popup = slider_popup_add(view->app, view->app->win->win, ELM_POPUP_ORIENT_CENTER, settings[ST_ZOOMLEVEL]);
    slider_popup_label_set(popup, settings[ST_ZOOMLEVEL]);

    int max = 0, min = 0, level = 0;
    camera_attr_get_zoom_range(view->camera, &min, &max);
    slider_popup_min_max_set(popup, min, max);

    camera_attr_get_zoom(view->camera, &level);
    slider_popup_value_set(popup, level);

    slider_popup_callback_set(popup, _slider_zoom_cb, _on_slider_popup_closed_cb, view);
    slider_popup_show(popup);
}
