static da_result_t __cancel_download_with_slot_id(int slot_id)
{
	da_result_t ret = DA_RESULT_OK;
	download_state_t download_state;
	stage_info *stage = DA_NULL;

	DA_LOG_FUNC_START(Default);

	_da_thread_mutex_lock (&mutex_download_state[slot_id]);
	download_state = GET_DL_STATE_ON_ID(slot_id);
	DA_LOG(Default, "download_state = %d", GET_DL_STATE_ON_ID(slot_id));

	if (download_state == DOWNLOAD_STATE_FINISH ||
			download_state == DOWNLOAD_STATE_CANCELED) {
		DA_LOG_CRITICAL(Default, "Already download is finished. Do not send cancel request");
		_da_thread_mutex_unlock (&mutex_download_state[slot_id]);
		return ret;
	}
	_da_thread_mutex_unlock (&mutex_download_state[slot_id]);

	stage = GET_DL_CURRENT_STAGE(slot_id);
	if (!stage)
		return DA_RESULT_OK;

	ret = request_to_cancel_http_download(stage);
	if (ret != DA_RESULT_OK)
		goto ERR;
	DA_LOG(Default, "Download cancel Successful for download id - %d", slot_id);
ERR:
	return ret;
}
da_result_t dereg_client_app(void)
{
	client_noti_t *client_noti = DA_NULL;

	DA_LOG_FUNC_START(ClientNoti);

	client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
	if (!client_noti) {
		DA_LOG_ERR(ClientNoti, "calloc fail");
		return DA_ERR_FAIL_TO_MEMALLOC;
	}

	client_noti->download_id = DA_INVALID_ID;
	client_noti->noti_type = Q_CLIENT_NOTI_TYPE_TERMINATE;
	client_noti->next = DA_NULL;

	_da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
	if (client_app_mgr.is_thread_init != DA_TRUE) {
		DA_LOG_CRITICAL(ClientNoti, "try to cancel client mgr thread id[%lu]", client_app_mgr.thread_id);
		if (pthread_cancel(client_app_mgr.thread_id) < 0) {
			DA_LOG_ERR(ClientNoti, "cancel thread is failed!!!");
		}
	} else {
		void *t_return = NULL;
		DA_LOG_VERBOSE(ClientNoti, "pushing Q_CLIENT_NOTI_TYPE_TERMINATE");
		push_client_noti(client_noti);
		DA_LOG_CRITICAL(Thread, "===try to join client mgr thread id[%lu]===", client_app_mgr.thread_id);
		if (pthread_join(client_app_mgr.thread_id, &t_return) < 0) {
			DA_LOG_ERR(Thread, "join client thread is failed!!!");
		}
		DA_LOG_CRITICAL(Thread, "===thread join return[%d]===", (char*)t_return);
	}
	_da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));

	/* ToDo: This clean up should be done at the end of client_thread. */
	client_app_mgr.client_app_info.is_using= DA_FALSE;
	client_app_mgr.client_app_info.is_manual_download = DA_FALSE;
	if(client_app_mgr.client_app_info.client_user_agent) {
		free(client_app_mgr.client_app_info.client_user_agent);
		client_app_mgr.client_app_info.client_user_agent = DA_NULL;
	}
	_da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
	client_app_mgr.is_thread_init = DA_FALSE;
	_da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));
	_da_thread_mutex_destroy(&(client_app_mgr.mutex_client_mgr));
	return DA_RESULT_OK;
}
void push_client_noti(client_noti_t *client_noti)
{
	client_queue_t *queue = DA_NULL;
	client_noti_t *head = DA_NULL;
	client_noti_t *pre = DA_NULL;
	client_noti_t *cur = DA_NULL;

	/* DA_LOG_FUNC_START(ClientNoti); */

	if(!is_this_client_available())	{
		DA_LOG_ERR(ClientNoti, "invalid client");
		return;
	}
	queue = &(client_app_mgr.client_queue);
	_da_thread_mutex_lock (&(queue->mutex_client_queue));

	head = queue->client_q_head;
	if (!head) {
		queue->client_q_head = client_noti;
	} else {
		cur = head;
		while (cur->next) {
			pre = cur;
			cur = pre->next;
		}

		if (DA_TRUE == is_this_client_manual_download_type()) {
			cur->next = client_noti;
		} else if (client_noti->noti_type == Q_CLIENT_NOTI_TYPE_SEND_STATE) {
			cur->next = client_noti;
		} else {
			if (cur->noti_type == Q_CLIENT_NOTI_TYPE_SEND_STATE) {
				cur->next = client_noti;
			} else if (cur->noti_type == Q_CLIENT_NOTI_TYPE_UPDATE_DOWNLOADING_INFO) {
				/* For UI performance. If the update noti info is existed at queue,
				   replace it with new update noti info */
				if (cur->download_id == client_noti->download_id) {
					/* DA_LOG(ClientNoti, "exchange queue's tail and pushing item"); */
					if (pre == DA_NULL)
						queue->client_q_head = client_noti;
					else
						pre->next = client_noti;
					destroy_client_noti(cur);
				} else {
					cur->next = client_noti;
				}
			}
		}
	}

	queue->having_data = DA_TRUE;

	__client_q_wake_up_without_lock();

	_da_thread_mutex_unlock (&(queue->mutex_client_queue));
}
da_result_t send_user_noti_and_finish_download_flow(
		int slot_id, char *installed_path, char *etag)
{
	da_result_t ret = DA_RESULT_OK;
	download_state_t download_state = DA_NULL;
	da_bool_t need_destroy_download_info = DA_FALSE;

	DA_LOG_FUNC_START(Default);

	_da_thread_mutex_lock (&mutex_download_state[slot_id]);
	download_state = GET_DL_STATE_ON_ID(slot_id);
	DA_LOG(Default, "state = %d", download_state);
	_da_thread_mutex_unlock (&mutex_download_state[slot_id]);

	switch (download_state) {
	case DOWNLOAD_STATE_FINISH:
		send_client_finished_info(slot_id, GET_DL_ID(slot_id),
		        installed_path, DA_NULL, DA_RESULT_OK,
		        get_http_status(slot_id));
		need_destroy_download_info = DA_TRUE;
		break;
	case DOWNLOAD_STATE_CANCELED:
		send_client_finished_info(slot_id, GET_DL_ID(slot_id),
				installed_path, etag, DA_RESULT_USER_CANCELED,
				get_http_status(slot_id));
		need_destroy_download_info = DA_TRUE;
		break;
#ifdef PAUSE_EXIT
	case DOWNLOAD_STATE_PAUSED:
		need_destroy_download_info = DA_TRUE;
		break;
#endif
	default:
		DA_LOG(Default, "download state = %d", download_state);
		break;
	}

	if (need_destroy_download_info == DA_TRUE) {
		destroy_download_info(slot_id);
	} else {
		DA_LOG_CRITICAL(Default, "download info is not destroyed");
	}

	return ret;
}
static da_result_t __resume_download_with_slot_id(int slot_id)
{
	da_result_t ret = DA_RESULT_OK;
	download_state_t download_state;
	stage_info *stage = DA_NULL;

	DA_LOG_FUNC_START(Default);

	_da_thread_mutex_lock (&mutex_download_state[slot_id]);
	download_state = GET_DL_STATE_ON_ID(slot_id);
	DA_LOG(Default, "download_state = %d", GET_DL_STATE_ON_ID(slot_id));
	_da_thread_mutex_unlock (&mutex_download_state[slot_id]);

	stage = GET_DL_CURRENT_STAGE(slot_id);

	ret = request_to_resume_http_download(stage);
	if (ret != DA_RESULT_OK)
		goto ERR;
	DA_LOG(Default, "Download Resume Successful for download id-%d", slot_id);
ERR:
	return ret;
}
void __pop_client_noti(client_noti_t **out_client_noti)
{
	client_queue_t *queue = DA_NULL;

	/* DA_LOG_FUNC_START(ClientNoti); */

	queue = &(client_app_mgr.client_queue);

	_da_thread_mutex_lock (&(queue->mutex_client_queue));

	if (queue->client_q_head) {
		*out_client_noti = queue->client_q_head;
		queue->client_q_head = queue->client_q_head->next;
	} else {
		*out_client_noti = DA_NULL;
	}

	if (queue->client_q_head == DA_NULL) {
		queue->having_data = DA_FALSE;
	}

	_da_thread_mutex_unlock (&(queue->mutex_client_queue));
}
static void *__thread_for_client_noti(void *data)
{
	da_result_t  ret = DA_RESULT_OK;
	da_bool_t need_wait = DA_TRUE;
	client_queue_t *queue = DA_NULL;
	client_noti_t *client_noti = DA_NULL;

	DA_LOG_FUNC_START(Thread);

	_da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
	client_app_mgr.is_thread_init = DA_TRUE;
	_da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));

	queue = &(client_app_mgr.client_queue);
	DA_LOG(ClientNoti, "client queue = %p", queue);

	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, DA_NULL);
	pthread_cleanup_push(__thread_clean_up_handler_for_client_thread, (void *)DA_NULL);

	do {
		_da_thread_mutex_lock(&(queue->mutex_client_queue));
		if (DA_FALSE == IS_CLIENT_Q_HAVING_DATA(queue)) {
			DA_LOG(Thread, "Sleep @ thread_for_client_noti!");
			__client_q_goto_sleep_without_lock();
			DA_LOG(Thread, "Woke up @ thread_for_client_noti");
		}
		_da_thread_mutex_unlock(&(queue->mutex_client_queue));

		do {
			__pop_client_noti(&client_noti);
			if (client_noti == DA_NULL) {
				DA_LOG_ERR(ClientNoti, "There is no data on client queue!");
				ret = DA_ERR_INVALID_STATE;
				need_wait = DA_FALSE;
			} else {
				switch (client_noti->noti_type) {
				case Q_CLIENT_NOTI_TYPE_UPDATE_DL_INFO:
				{
					user_download_info_t *update_dl_info = DA_NULL;;
					update_dl_info = (user_download_info_t*)(&(client_noti->type.update_dl_info));
					if (client_app_mgr.client_app_info.client_callback.update_dl_info_cb) {
						client_app_mgr.client_app_info.client_callback.update_dl_info_cb(update_dl_info, client_noti->user_data);
						DA_LOG(ClientNoti, "Update download info for download_id=%d, dl_req_id=%d, received size=%lu- DONE",
								client_noti->download_id,
								update_dl_info->da_dl_req_id,
								update_dl_info->file_size
								);
					}
				}
				break;
				case Q_CLIENT_NOTI_TYPE_UPDATE_DOWNLOADING_INFO:
				{
					user_downloading_info_t *downloading_info = DA_NULL;;
					downloading_info = (user_downloading_info_t*)(&(client_noti->type.update_downloading_info));
					if (client_app_mgr.client_app_info.client_callback.update_progress_info_cb) {
						client_app_mgr.client_app_info.client_callback.update_progress_info_cb(downloading_info, client_noti->user_data);
						DA_LOG(ClientNoti, "Update downloading info for download_id=%d, dl_req_id=%d, received size=%lu - DONE",
								client_noti->download_id,
								downloading_info->da_dl_req_id,
								downloading_info->total_received_size);
					}
				}
				break;
				case Q_CLIENT_NOTI_TYPE_SEND_STATE:
				{
					user_notify_info_t *da_state_info = DA_NULL;
					da_state_info = (user_notify_info_t *)(&(client_noti->type.da_state_info));

					if (client_app_mgr.client_app_info.client_callback.user_noti_cb) {
						DA_LOG(ClientNoti, "User Noti info for download_id=%d, dl_req_id=%d, da_state=%d, err=%d",
								client_noti->download_id,
								da_state_info->da_dl_req_id, da_state_info->state,
								da_state_info->err);
						client_app_mgr.client_app_info.client_callback.user_noti_cb(da_state_info, client_noti->user_data);
						DA_LOG(ClientNoti, "User Noti info for download_id=%d, dl_req_id=%d, da_state=%d, err=%d - DONE",
								client_noti->download_id,
								da_state_info->da_dl_req_id,
								da_state_info->state, da_state_info->err);
					}
				}
				break;
				case Q_CLIENT_NOTI_TYPE_TERMINATE:
					DA_LOG_CRITICAL(ClientNoti, "Q_CLIENT_NOTI_TYPE_TERMINATE");
					need_wait = DA_FALSE;
					break;
				}
				destroy_client_noti(client_noti);
			}

			if(DA_TRUE == need_wait) {
				_da_thread_mutex_lock(&(queue->mutex_client_queue));
				if (DA_FALSE == IS_CLIENT_Q_HAVING_DATA(queue)) {
					_da_thread_mutex_unlock (&(queue->mutex_client_queue));
					break;
				} else {
					_da_thread_mutex_unlock (&(queue->mutex_client_queue));
				}
			} else {
				break;
			}
		} while (1);
	} while (DA_TRUE == need_wait);

	_da_thread_mutex_destroy(&(queue->mutex_client_queue));
	_da_thread_cond_destroy(&(queue->cond_client_queue));

	pthread_cleanup_pop(0);
	DA_LOG_CRITICAL(Thread, "=====thread_for_client_noti- EXIT=====");
	pthread_exit((void *)NULL);
	return DA_NULL;
}