/*===========================================================================
FUNCTION    ulp_msg_forward_quipc_coarse_position_request

DESCRIPTION
   This function is called when libulp module need to forward coarse
   position request from ULP named pipe to message queue. This is done
   so that all ULP state transition is done in one thread.

DEPENDENCIES
   None

RETURN VALUE
   0: success
   -1: failure

SIDE EFFECTS
   N/A

===========================================================================*/
int ulp_msg_forward_quipc_coarse_position_request ()
{
   int ret_val = -1;

   ENTRY_LOG_CALLFLOW();
   do
   {
      // Forward the coarse position request in ULP named pipe to ULP message queue
      // so that all state transition is done in one thread
      ulp_msg *msg(new ulp_msg(&ulp_data, ULP_MSG_REQUEST_COARSE_POSITION));
      if (msg == NULL)
      {
         LOC_LOGE ("%s, failed to create message: ULP_MSG_REQUEST_COARSE_POSITION \n", __func__);
         break;
      }

      msg_q_snd(ulp_data.loc_proxy->mQ, msg, ulp_msg_free);

     ret_val = 0;

   } while (0);

   EXIT_LOG(%d, ret_val);
   return ret_val;
}
/*===========================================================================
FUNCTION    ulp_msg_send_monitor_request

DESCRIPTION
   This function is called when ulp monitor thread need to send a message
   to ULP main thread to request ULP to re-evaluate its subsystems.

DEPENDENCIES
   None

RETURN VALUE
   0: success
   -1: failure

SIDE EFFECTS
   N/A

===========================================================================*/
int ulp_msg_send_monitor_request ()
{
   int ret_val = -1;

   ENTRY_LOG_CALLFLOW();
   do
   {
      //Pass the start messgage to ULP if present & activated
      ulp_msg *ulpMonitorMsg(new ulp_msg(&ulp_data, ULP_MSG_MONITOR));

      if (ulpMonitorMsg == NULL)
      {
         LOC_LOGE ("%s, failed to create message: ULP_MSG_MONITOR \n", __func__);
         break;
      }

      msg_q_snd(ulp_data.loc_proxy->mQ,
                ulpMonitorMsg,
                ulp_msg_free);

     ret_val = 0;

   } while (0);

   EXIT_LOG(%d, ret_val);
   return ret_val;
}
/*===========================================================================
FUNCTION    ulp_msg_forward_quipc_position_report

DESCRIPTION
   This function is called when libulp module need to forward a position report
   from ULP named pipe to message queue. This is done so that all ULP
   state transition is done in one thread.

DEPENDENCIES
   None

RETURN VALUE
   0: success
   -1: failure

SIDE EFFECTS
   N/A

===========================================================================*/
int ulp_msg_forward_quipc_position_report (int                    error_code,
                                           const UlpLocation*     quipc_location_ptr,
                                           int                    debug_info_length,
                                           char*                  debug_info_ptr)
{
   int ret_val = -1;
   UlpLocation quipc_location;
   char* debug_info = NULL;

   ENTRY_LOG_CALLFLOW();
   do
   {
      if (quipc_location_ptr == NULL)
      {
         break;
      }

      quipc_location = *quipc_location_ptr;

      LOC_LOGI ("%s, Debug Info = %s, Length = %d\n", __func__, debug_info_ptr, debug_info_length);

      // Make a copy of the debug info received. Needs to be freed by ulp_brain.
      if (debug_info_length != 0) {
        debug_info = new char[debug_info_length];
        if (debug_info != NULL)
        {
          strlcpy((char*)debug_info, debug_info_ptr, debug_info_length);
          quipc_location.rawData = (void*) debug_info;
          quipc_location.rawDataSize = debug_info_length;
        }
      }

      ulp_msg_report_quipc_position *ulpPositionMsg(
            new ulp_msg_report_quipc_position(&ulp_data,
                                              quipc_location,
                                              error_code));
      if (ulpPositionMsg == NULL)
      {
         LOC_LOGE ("%s, failed to create message: ulp_msg_report_quipc_position \n", __func__);

         // Free the allocated memory
         delete [] debug_info;
         debug_info = NULL;
         quipc_location.rawData = NULL;
         quipc_location.rawDataSize = 0;
         break;
      }

     msg_q_snd(ulp_data.loc_proxy->mQ,
               ulpPositionMsg,
               ulp_msg_free);

     ret_val = 0;

   } while (0);

   EXIT_LOG(%d, ret_val);
   return ret_val;
}
static void* ulp_zpp_thread_proc(void *args)
{
   ENTRY_LOG();

   ulp_data_s_type* ulp_data_p = (ulp_data_s_type*)args;
   zpp_provider_info_s_type* zpp_provider_info_p = &ulp_data_p->zpp_provider_info;
   int rc = 0;          /* return code from pthread calls */

   struct timeval present_time;
   struct timespec expire_time;

   LOC_LOGD("Starting ulp_zpp thread...\n");
   pthread_mutex_lock(&zpp_provider_info_p->tLock);
   while (zpp_provider_info_p->periodic_session_active)
   {
      /* Calculate absolute expire time */
      gettimeofday(&present_time, NULL);
      expire_time.tv_sec  = present_time.tv_sec + (zpp_provider_info_p->zpp_trigger_threshold/1000);
      expire_time.tv_nsec = present_time.tv_usec * 1000;
      LOC_LOGD("%s,ulp_zpp_thread_proc-Present time %ld, Time out set for abs time %ld with delay %d msec\n",
               __func__,(long) present_time.tv_sec,
               (long) expire_time.tv_sec, zpp_provider_info_p->zpp_trigger_threshold );

      rc = pthread_cond_timedwait(&zpp_provider_info_p->tCond,
                                  &zpp_provider_info_p->tLock,
                                  &expire_time);
      if (rc == ETIMEDOUT)
      {
         LOC_LOGD("%s,ulp_zpp_thread_proc-Thread waking up. Ret Val %d\n",__func__, rc );
         ulp_msg_system_update *msg(new ulp_msg_system_update(&ulp_data, ULP_LOC_ZPP_PERIODIC_WAKEUP));
         msg_q_snd(ulp_data.loc_proxy->mQ, msg,ulp_msg_free);
      }
   }
   pthread_mutex_unlock(&zpp_provider_info_p->tLock);
   if (ETIMEDOUT != rc)
   {
      LOC_LOGD("ulp_zpp thread was signalled to exit. pthread_cond_timedwait = %d\n",rc );
   }

   EXIT_LOG(%s, VOID_RET);
   return NULL;
}
/**
@brief Adds messages to daemon message queue

Function adds messages to daemon message queue

@param  msg_obj: message.
@param  msg_sz: message size.
*/
bool ClientListener::CLMsgQSnd(void* msg_obj, uint32_t msg_sz)
{
    ENTRY_LOG();
    void (*dealloc)(void*) = free;

    void* msg_obj_cpy = malloc(msg_sz);
    if( msg_obj_cpy == NULL )
    {
        LOC_LOGE("%s: Memory allocation failure", __FUNCTION__);
        return false;
    }

    memcpy(msg_obj_cpy, msg_obj, msg_sz);

    msq_q_err_type rv = msg_q_snd(mMsgQ, msg_obj_cpy, dealloc);
    if ( rv != eMSG_Q_SUCCESS )
    {
        LOC_LOGE("%s: Invalid Msg Queue send!", __FUNCTION__);
        dealloc(msg_obj_cpy);
        return false;
    }
    EXIT_LOG(%d, rv);
    return true;
}
void loc_ulp_msg_sender(void* loc_eng_data_p, void* msg)
{
    LocEngContext* loc_eng_context = (LocEngContext*)((loc_eng_data_s_type*)loc_eng_data_p)->context;
    msg_q_snd((void*)loc_eng_context->ulp_q, msg, loc_free_msg);
}