/*
#  $Id$
# -----------------------------------------------------------------------------
#  The part of 'VideoNEXT MediaClient SDK'
# -----------------------------------------------------------------------------
#  Author: Petrov Maxim, 08/20/2010
#  Edited by:
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
*/

#include <string.h>
#include <stdlib.h>
#include "vn_player_stream_handler.h"
#include "vn_malloc.h"

using namespace videonext::media;

VN_Media_Stream_Handler::VN_Media_Stream_Handler(vn_player_context_t *ctx)
   : ctx_(ctx), callbacks_(ctx->callbacks)
   , callbacks_enabled_(true)
   , client_data_(ctx->config.client_data)
{}
  
/*virtual*/ VN_Media_Stream_Handler::~VN_Media_Stream_Handler() 
{
   callbacks_enabled_ = false; // HACK
}    

/*virtual*/ void VN_Media_Stream_Handler::newFrame(const Frame &frame, const CacheBoundaries &bounds, int buf_num)
{
   if (!callbacks_enabled_) return;

   MutexGuard g(ctx_->callback_mutex);

   if (callbacks_enabled_ && callbacks_.new_frame)
   {
      struct vn_player_stream_info_t vn_stream_info = {};
      vn_stream_info.type             = (VN_PLAYER_STREAM_TYPE)frame.streamInfo->type;
      vn_stream_info.stream_id        = frame.streamInfo->streamId;
      vn_stream_info.RTP_Codec_Str    = frame.streamInfo->RTPCodecStr.c_str();
      vn_stream_info.sampling_freq    = frame.streamInfo->samplingFreq;
      vn_stream_info.bits_per_sample  = frame.streamInfo->bitsPerSample;
      vn_stream_info.num_channels     = frame.streamInfo->numChannels;
      vn_stream_info.config_data      = frame.streamInfo->configData;
      vn_stream_info.config_data_size = frame.streamInfo->configDataSize;

      struct vn_player_frame_t vn_frame = {};
      vn_frame.stream_info       = &vn_stream_info;
      vn_frame.data[0]           = frame.data[0];
      vn_frame.data[1]           = frame.data[1];
      vn_frame.data[2]           = frame.data[2];
      vn_frame.data[3]           = frame.data[3];
      vn_frame.data_size[0]      = frame.dataSize[0];
      vn_frame.data_size[1]      = frame.dataSize[1];
      vn_frame.data_size[2]      = frame.dataSize[2];
      vn_frame.data_size[3]      = frame.dataSize[3];
      vn_frame.width             = frame.width;
      vn_frame.height            = frame.height;
      vn_frame.captured_time     = frame.capturedTime;
      vn_frame.objects_data_size = frame.objectsData.size();
      vn_frame.objects_data      = vn_frame.objects_data_size ? (const unsigned char*)frame.objectsData.data() : 0;
      vn_frame.dar               = frame.dar;

      struct vn_player_cache_boundaries_t vn_bounds = {};
      vn_bounds.begin = bounds.begin;
      vn_bounds.end   = bounds.end;

      callbacks_.new_frame(&vn_frame, &vn_bounds, buf_num, client_data_);
   }
}

/*virtual*/ void VN_Media_Stream_Handler::newReport(const Report &)
{
}

/*virtual*/ void VN_Media_Stream_Handler::bufferChanged(const CacheBoundaries &bounds)
{
   if (!callbacks_enabled_) return;
   MutexGuard g(ctx_->callback_mutex);

   if (callbacks_enabled_ && callbacks_.buffer_changed)
   {
      struct vn_player_cache_boundaries_t vn_bounds;
      vn_bounds.begin = bounds.begin;
      vn_bounds.end   = bounds.end;

      callbacks_.buffer_changed(&vn_bounds, client_data_);
   }
}
        
/*virtual*/ void VN_Media_Stream_Handler::stateChanged(STREAM_STATE state, const ResultStatus &status)
{
   if (!callbacks_enabled_) return;
   MutexGuard g(ctx_->callback_mutex);

   if (callbacks_enabled_ && callbacks_.state_changed)
   {
      VN_PLAYER_STREAM_STATE vn_state = (VN_PLAYER_STREAM_STATE)state;
      
      struct vn_player_result_status_t vn_result_status;
      bool error_str_allocated(false);

      vn_result_status.error_code = status.errorCode;
      if (strstr(status.errorString.c_str(), "liveMedia") == status.errorString.c_str())
      {
         vn_result_status.error_str = (const char*)calloc(1, 1); 
         error_str_allocated = true;
      }
      else
      {
         vn_result_status.error_str  = status.errorString.c_str();
      }
      
      callbacks_.state_changed(vn_state, &vn_result_status, client_data_);

      if (error_str_allocated)
      {
         free((void*)vn_result_status.error_str);
      }
      
   }
}
        
/*virtual*/ void VN_Media_Stream_Handler::newStream(const StreamInfo &streamInfo)
{
   if (!callbacks_enabled_) return;

   MutexGuard g(ctx_->callback_mutex);

   if (callbacks_enabled_ && callbacks_.new_stream)
   {
      struct vn_player_stream_info_t vn_stream_info;
      vn_stream_info.type             = (VN_PLAYER_STREAM_TYPE)streamInfo.type;
      vn_stream_info.stream_id        = streamInfo.streamId;
      vn_stream_info.duration         = streamInfo.duration;
      vn_stream_info.RTP_Codec_Str    = streamInfo.RTPCodecStr.c_str();
      vn_stream_info.sampling_freq    = streamInfo.samplingFreq;
      vn_stream_info.bits_per_sample  = streamInfo.bitsPerSample;
      vn_stream_info.num_channels     = streamInfo.numChannels;
      vn_stream_info.config_data      = streamInfo.configData;
      vn_stream_info.config_data_size = streamInfo.configDataSize;
	  vn_stream_info.metadata		  = NULL;

	  if (!streamInfo.metadata.empty())
	  {
		  vn_stream_info.metadata = vn_kv_list_create(streamInfo.metadata.size());
		  int i = 0;
		  std::map<std::string, std::string>::const_iterator it;
		  for (it = streamInfo.metadata.begin(); it != streamInfo.metadata.end(); ++it)
		  {
			  const char* key = it->first.c_str();
			  const char* value = it->second.c_str();
			  vn_stream_info.metadata[i]->key = vn_malloc(strlen(key) + 1, NULL);
			  strcpy((char*)vn_stream_info.metadata[i]->key, key);
			  vn_stream_info.metadata[i]->value = vn_malloc(strlen(value) + 1, NULL);
			  strcpy((char*)vn_stream_info.metadata[i]->value, value);
			  i++;
		  }
	  }

	  callbacks_.new_stream(&vn_stream_info, client_data_);

	  if (vn_stream_info.metadata)
	  {
		  vn_kv_list_destroy(vn_stream_info.metadata);
	  }
   }
}
        
/*virtual*/ void VN_Media_Stream_Handler::removeStream(const StreamInfo &streamInfo) 
{
   if (!callbacks_enabled_) return;

   MutexGuard g(ctx_->callback_mutex);

   if (callbacks_enabled_ && callbacks_.stream_removed)
   {
      struct vn_player_stream_info_t vn_stream_info;
      vn_stream_info.type             = (VN_PLAYER_STREAM_TYPE)streamInfo.type;
      vn_stream_info.stream_id        = streamInfo.streamId;
      vn_stream_info.RTP_Codec_Str    = streamInfo.RTPCodecStr.c_str();
      vn_stream_info.sampling_freq    = streamInfo.samplingFreq;
      vn_stream_info.bits_per_sample  = streamInfo.bitsPerSample;
      vn_stream_info.num_channels     = streamInfo.numChannels;
      vn_stream_info.config_data      = streamInfo.configData;
      vn_stream_info.config_data_size = streamInfo.configDataSize;
	  vn_stream_info.metadata		  = NULL;

      callbacks_.stream_removed(&vn_stream_info, client_data_);

   }
}

/*virtual*/ void* VN_Media_Stream_Handler::createImageBuffer(int width, int height, float dar, FRAME_BUFFERS_NUM& buf_num)
{
   if (!callbacks_enabled_) return 0;

   MutexGuard g(ctx_->callback_mutex);

   if (callbacks_enabled_ && callbacks_.create_image_buffer)
   {
       VN_PLAYER_FRAME_BUFFERS_NUM b_num = (VN_PLAYER_FRAME_BUFFERS_NUM)buf_num;
       void* ret = callbacks_.create_image_buffer(width, height, dar, b_num, client_data_);
       buf_num = (FRAME_BUFFERS_NUM)b_num;
       return ret;
   }

   return 0;
}

/*virtual*/ int VN_Media_Stream_Handler::lockImageBuffer(int buf_num)
{
    if (!callbacks_enabled_)
        return buf_num;

    MutexGuard g(ctx_->callback_mutex);

    if (callbacks_enabled_ && callbacks_.lock_image_buffer)
    {
        return callbacks_.lock_image_buffer(buf_num, client_data_);
    }

    return buf_num;
}
        
/*virtual*/ void VN_Media_Stream_Handler::unlockImageBuffer(int buf_num)
{
    if (!callbacks_enabled_)
        return;
    
    MutexGuard g(ctx_->callback_mutex);

    if (callbacks_enabled_ && callbacks_.unlock_image_buffer)
    {
        callbacks_.unlock_image_buffer(buf_num, client_data_);
    }
}

/*virtual*/ void VN_Media_Stream_Handler::recordingStatusChanged(const vn_player_recording_status_t &status)
{
   if (!callbacks_enabled_) return;

   MutexGuard g(ctx_->callback_mutex);

   if (callbacks_enabled_ && callbacks_.recording_status_changed)
   {
      callbacks_.recording_status_changed(&status, client_data_);
   }
}

/*virtual*/ void VN_Media_Stream_Handler::log(const char *msg)
{
   if (!callbacks_enabled_) return;

   MutexGuard g(ctx_->callback_mutex);

   if (callbacks_enabled_ && callbacks_.msg_log)
   {
      callbacks_.msg_log(msg, client_data_);
   }
}


