/*
 * ice_streamer.cpp
 *
 *  Created on: Jul 2, 2012
 *      Author: ergino
 */

#include "ice_streamer.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "utilities_debug/cabot_assert.h"
#include "utilities_debug/trace.h"
#include "frost_mem.h"

TRACE_IMPLEMENT("ice/ice_streamer");

ice_streamer_handler_t g_ice_streamer_handle ;
static ice_streamer_main_t *mainobj;
static frost_long g_packet_size = 0 ;


frost_long get_packet_size()
{
    if(g_packet_size)
    {
       return (g_packet_size<CURRENT_MAX_PACKET_SIZE) ? g_packet_size : CURRENT_MAX_PACKET_SIZE;

    }
    else
    {
        return CURRENT_MAX_PACKET_SIZE ;
    }
}

void set_packet_size(frost_long size)
{
    g_packet_size = size ;

}

void
ice_streamer_output_list_free_elem (frost_pointer data, frost_pointer user_data)
{
    ice_streamer_output_t *f;

    frost_return_if_fail (data);

    f = (ice_streamer_output_t *)data;

    ice_streamer_object_unref (f);
}

void
ice_streamer_output_list_clear(ice_streamer_main_t *main_object)
{
    if (main_object->output_list == NULL)
        return;

    frost_list_foreach (main_object->output_list,
                    ice_streamer_output_list_free_elem,
                    NULL);

    frost_list_free (main_object->output_list);
    main_object->output_list = NULL;
}

static void
ice_streamer_main_destroy (ice_streamer_object_t *object)
{
    ice_streamer_main_t *mainobj = (ice_streamer_main_t *) object;
    
    ice_streamer_output_list_clear(mainobj);

    ice_streamer_object_unref (mainobj->xform_obj);
}

ice_streamer_main_t *
ice_streamer_init(ICE_IceStreamerStatusCallback callback_function, void* user_data,void * handle)
{
    TRACE_VERBOSE(("\n\n"));

    ice_streamer_config_init();

    if (!ice_streamer_plugin_init ())
    {
        return NULL;
    }

    mainobj = ice_streamer_object_new (ice_streamer_main_t, ice_streamer_main_destroy);

    mainobj->xform_obj = ice_streamer_handler_object_init ();

    mainobj->playlist = frost_new( ice_streamer_playlist_t,1);
    
//    ice_streamer_status_callback_set(callback_function, user_data);

    return mainobj;

}


void
ice_streamer_register_need_data(ICE_IceStreamerNeedDataCallback need_data_callback,
                                void *user_data)
{
    TRACE_INFO(("In %s(): Need data callback is registered\n", __FUNCTION__));
    ice_streamer_need_data_callback_set(need_data_callback, user_data);
}


void
ice_streamer_destroy(ice_streamer_object_t * output)
{
    TRACE_VERBOSE(("\n\n"));
    ice_streamer_main_destroy(output);
}

void
ice_streamer_start_priv (frost_pointer data, frost_pointer user_data)
{
    ice_streamer_output_t *f;

    frost_return_if_fail (data);

    f = (ice_streamer_output_t *)data;
    
    ice_playback_client_start(f , (ice_error_code_t *)user_data);
}

frost_bool
ice_streamer_start(ice_streamer_main_t *ice_streamer,
        const char * filename)
{
    TRACE_VERBOSE(("\n\n"));
    
    frost_return_val_if_fail (ice_streamer->output_list, frost_false);
    
    ice_error_code_t err = ICE_ERROR_NONE ;
    
    ice_streamer->playlist->url = (char *)filename;
    
    frost_list_foreach (ice_streamer->output_list,
                    ice_streamer_start_priv,
                    &err);

    return frost_true;
}

void
ice_streamer_stop_priv (frost_pointer data, frost_pointer user_data)
{
    ice_streamer_output_t *f;

    frost_return_if_fail (data);

    f = (ice_streamer_output_t *)data;
    
    ice_playback_client_stop(f , (ice_error_code_t *)user_data);
}

frost_bool
ice_streamer_stop(ice_streamer_main_t *ice_streamer)
{
    TRACE_VERBOSE(("\n\n"));

    frost_return_val_if_fail (ice_streamer->output_list, frost_false);
    
    ice_error_code_t err = ICE_ERROR_NONE ;

    frost_list_foreach (ice_streamer->output_list,
                    ice_streamer_stop_priv,
                    &err);

    return frost_true;
}

void
ice_streamer_pause_priv (frost_pointer data, frost_pointer user_data)
{
    ice_streamer_output_t *f;

    frost_return_if_fail (data);

    f = (ice_streamer_output_t *)data;
    
    ice_playback_client_pause(f , (ice_error_code_t *)user_data);
}

frost_bool
ice_streamer_pause(ice_streamer_main_t *ice_streamer)
{
    TRACE_VERBOSE(("\n\n"));

    ice_error_code_t err = ICE_ERROR_NONE ;

    frost_list_foreach (ice_streamer->output_list,
                    ice_streamer_pause_priv,
                    &err);

    return frost_true;
}

frost_uint32
ice_streamer_playtime(ice_streamer_main_t *ice_streamer)
{
    TRACE_VERBOSE(("\n\n"));

    ice_error_code_t err = ICE_ERROR_NONE ;
    frost_uint32 ret;

    if(ice_streamer->output_list->data == NULL)
    {
        return 0;
    }
    
    //playtime is captured from vdplayer, 
    //so it is ok to get that value through one of the outputs (in case there is more than one)
    ret = ice_playback_client_playtime((ice_streamer_output_t *)ice_streamer->output_list->data , &err);

    return ret;
}

void
ice_streamer_play_priv (frost_pointer data, frost_pointer user_data)
{
    ice_streamer_output_t *f;

    frost_return_if_fail (data);

    f = (ice_streamer_output_t *)data;
    
    ice_playback_client_play(f , (ice_error_code_t *)user_data);
}

frost_bool
ice_streamer_play(ice_streamer_main_t *ice_streamer)
{
    TRACE_VERBOSE(("\n\n"));

    frost_return_val_if_fail (ice_streamer->output_list, frost_false);
    
    ice_error_code_t err = ICE_ERROR_NONE ;

    frost_list_foreach (ice_streamer->output_list,
                    ice_streamer_play_priv,
                    &err);

    return frost_true;
}

frost_bool
ice_streamer_trick_mode(ice_streamer_main_t *ice_streamer, frost_int step, frost_int mili_seconds, ice_streamer_output_filler_state_t state)
{
    TRACE_VERBOSE(("======================> ice_streamer_trick_mode step=%d  seconds=%d state=%d\n", step, mili_seconds, state));
    FROST_List* list = frost_list_first(ice_streamer->output_list);
    
    while (list){
        ice_playback_client_trick_mode((ice_streamer_output_t *)list->data, step, mili_seconds, state);
        list = list->next;
    }

    return frost_true;
}

frost_bool
ice_streamer_error_iserror (ice_error_code_t *err)
{
    CABOT_ASSERT(err);

    return (*err == ICE_ERROR_NONE) ? frost_false : frost_true;
}

void
ice_streamer_error_reset (ice_error_code_t *err)
{
    CABOT_ASSERT(err);

    *err = ICE_ERROR_NONE;
}

void
ice_streamer_error_set (ice_error_code_t *err, ice_error_code_t code, const char *message)
{
    frost_return_if_fail (err);

    *err = code;
}

void *
ice_streamer_private_data_get(ice_streamer_handler_t * handle)
{
    return handle->priv ;
}

void
ice_streamer_private_data_set(ice_streamer_handler_t * handle, void *data )
{
    handle->priv = data ;
}

frost_bool
ice_streamer_write_data(ice_streamer_main_t *ice_streamer, frost_uint8 *buffer,
                        frost_uint length, frost_bool end_of_data)
{
    // ice streamer handler is accessible like this: mainobj->xform_obj

    return ice_streamer_handler_write_data(buffer, length, end_of_data);
}

frost_bool
ice_streamer_attach_source(ice_streamer_main_t *ice_streamer, unsigned int source_id)
{
    ice_streamer_config_property_t *prop = ice_streamer_config_lookup ("output.plugin");
    if(!prop)
    {
        TRACE_ERROR((">>> Output plugin is not set ...!!!\n"));
        return frost_false;
    }
    
    int plugin_index = ice_streamer_config_property_get_int(prop);

    ice_streamer_plugin_t* plugin = (ice_streamer_plugin_t *)frost_list_nth_data(ice_streamer_plugin_get_list(), plugin_index);

    ice_streamer_output_plugin_t * o_plugin = 
            (ice_streamer_output_plugin_t *)ice_streamer_plugin_find (ICE_PLUGIN_TYPE_OUTPUT, ice_streamer_plugin_shortname_get(plugin));
    
    if (!o_plugin) {
        
        frost_bool multiple_output_is_supported = frost_false;
        prop = ice_streamer_config_lookup ("multiple.output");
        if(prop)
        {
            multiple_output_is_supported = (ice_streamer_config_property_get_int(prop)) ? frost_true : frost_false;
        }
        
        if(multiple_output_is_supported)
        {
            //It is not possible to create second output for output plugins except ICE_PLUGIN_EXTERNAL
            if(plugin_index != ICE_PLUGIN_EXTERNAL)
            {
                plugin_index = ICE_PLUGIN_DISKWRITE;
            }
            
            o_plugin = (ice_streamer_output_plugin_t *)ice_streamer_plugin_load((ice_plugin_id_t)plugin_index);
        }
        
        if(!o_plugin)
        {
            return frost_false;
        }
    }
   
    ice_streamer_output_t *output = ice_streamer_output_new (o_plugin, ice_streamer->playlist, source_id);
    
    if(frost_list_length(ice_streamer->output_list) == 0)
    {
        output->first_in_list = frost_true;
    }

    ice_streamer->output_list = frost_list_append(ice_streamer->output_list, output);

    return frost_true;    
}

frost_bool
ice_streamer_remove_source(ice_streamer_main_t *ice_streamer, unsigned int source_id)
{
    frost_bool removed = frost_false;

    ice_streamer->output_list = frost_list_first(ice_streamer->output_list);
    
    while (ice_streamer->output_list){
        if(((ice_streamer_output_t *)ice_streamer->output_list->data)->source_id == source_id)
        {
            ice_streamer_object_unref (((ice_streamer_output_t *)ice_streamer->output_list->data));
            ice_streamer->output_list = frost_list_delete_link(ice_streamer->output_list, ice_streamer->output_list);
            removed = frost_true;
            break;
        }
        
        if(ice_streamer->output_list->next)
        {
            ice_streamer->output_list = ice_streamer->output_list->next;
        }
        else
        {
            break;
        }
    }
    
    if(removed && (ice_streamer->output_list->prev == NULL) && (((ice_streamer_output_t *)ice_streamer->output_list->data)->first_in_list == frost_false))
    {
        TRACE_VERBOSE(("Make it first : list data[0x%x]\n",ice_streamer->output_list->data));
        ((ice_streamer_output_t *)ice_streamer->output_list->data)->first_in_list = frost_true;
    }

    return removed;
}

