da_result_t  send_client_da_state (int download_id, da_state state, int err)
{
	client_noti_t *client_noti = DA_NULL;
	user_notify_info_t *send_state_info = DA_NULL;
	da_state cur_da_state;

	DA_LOG_FUNC_START(ClientNoti);

	DA_LOG_VERBOSE(ClientNoti, "da_state[%s], download_id[%d]", print_dl_state(state), download_id);

	if (!is_valid_dl_ID(download_id)) {
		DA_LOG_ERR(ClientNoti, "Download ID is not valid");
		/* Returning DA_RESULT_OK if download_id is not valid,
		 * because sending da_state should not effect to download flow. */
		return DA_RESULT_OK;
	}

	if (state_watcher_need_redirect_Q(download_id)) {
		state_watcher_redirect_state(download_id, state, err);
		return DA_RESULT_OK;
	}

	cur_da_state = GET_DL_DA_STATE(download_id);

	if ((DA_STATE_SUSPENDED != state) && (cur_da_state == state)) {
		DA_LOG(ClientNoti, "inserting da_state is same with current da_state! Not inserting! inserting: %d, cur : %d", state, cur_da_state);
		return DA_RESULT_OK;
	}

	GET_DL_DA_STATE(download_id) = state;
	DA_LOG_VERBOSE(ClientNoti, "change da_state to %d", state);

	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 = download_id;
	client_noti->user_data = GET_DL_USER_DATA(download_id);
	client_noti->noti_type = Q_CLIENT_NOTI_TYPE_SEND_STATE;
	client_noti->next = DA_NULL;

	send_state_info = (user_notify_info_t *)&(client_noti->type.da_state_info);
	send_state_info->da_dl_req_id = GET_DL_REQ_ID(download_id);
	send_state_info->state = state;
	send_state_info->err = err;

	DA_LOG(ClientNoti, "pushing da_state=%d, download_id=%d, err=%d, dl_req_id=%d",
			state, download_id, err, GET_DL_REQ_ID(download_id));

	push_client_noti(client_noti);

	return DA_RESULT_OK;
}
da_bool_t is_valid_download_id(int dl_id)
{

	da_bool_t ret = DA_TRUE;
	int slot_id = DA_INVALID_ID;

	DA_LOG_VERBOSE(Default, "[is_valid_download_id]download_id : %d", dl_id);

	ret = get_slot_id_for_dl_id(dl_id, &slot_id);
	if (ret != DA_RESULT_OK) {
		DA_LOG_ERR(Default, "dl req ID is not Valid");
		ret = DA_FALSE;
		goto ERR;
	} else {
		ret = DA_TRUE;
	}

	if (DA_FALSE == is_valid_slot_id(slot_id)) {
		DA_LOG_ERR(Default, "Download ID is not Valid");
		ret = DA_FALSE;
		goto ERR;
	}
	if (GET_DL_THREAD_ID(slot_id) < 1) {
		DA_LOG_ERR(Default, "Download thread is not alive");
		ret = DA_FALSE;
		goto ERR;
	}

ERR:
	return ret;
}
da_result_t  get_client_download_path(char **out_path)
{
	if (!out_path) {
		DA_LOG_ERR(ClientNoti, "DA_ERR_INVALID_ARGUMENT");
		return DA_ERR_INVALID_ARGUMENT;
	}

	/* change the directory policy. it doesn't clean the temp direcoty when deinitializing */
	*out_path = strdup(DA_DEFAULT_TMP_FILE_DIR_PATH);
	DA_LOG_VERBOSE(ClientNoti, "client download path = [%s]", *out_path);

	return DA_RESULT_OK;
}
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;
}
da_result_t reg_client_app(
		da_client_cb_t *da_client_callback,
		da_download_managing_method download_method
		)
{
	da_result_t ret = DA_RESULT_OK;
	client_queue_t *queue = DA_NULL;
	client_noti_t *client_noti = DA_NULL;

	DA_LOG_FUNC_START(ClientNoti);

	if (client_app_mgr.client_app_info.is_using)
		return DA_ERR_CLIENT_IS_ALREADY_REGISTERED;

	client_app_mgr.client_app_info.is_using = DA_TRUE;
	if (download_method == DA_DOWNLOAD_MANAGING_METHOD_MANUAL)
		client_app_mgr.client_app_info.is_manual_download = DA_TRUE;
	else
		client_app_mgr.client_app_info.is_manual_download = DA_FALSE;

	memset(&(client_app_mgr.client_app_info.client_callback),
			0, sizeof(da_client_cb_t));
	memcpy(&(client_app_mgr.client_app_info.client_callback),
			da_client_callback, sizeof(da_client_cb_t));

	_da_thread_mutex_init(&(client_app_mgr.mutex_client_mgr), DA_NULL);

	/* If some noti is existed at queue, delete all */
	do {
		__pop_client_noti(&client_noti);
		destroy_client_noti(client_noti);
	} while(client_noti != DA_NULL);

	queue = &(client_app_mgr.client_queue);
	DA_LOG_VERBOSE(ClientNoti, "client queue = %p", queue);
	_da_thread_mutex_init(&(queue->mutex_client_queue), DA_NULL);
	_da_thread_cond_init(&(queue->cond_client_queue), DA_NULL);

	ret = __launch_client_thread();

	return ret;
}
da_result_t da_mime_get_ext_name(char *mime, char **ext)
{
	da_result_t ret = DA_RESULT_OK;
	const char **extlist = DA_NULL;
	const char *unaliased_mimetype = DA_NULL;
	char ext_temp[DA_MAX_STR_LEN] = {0,};
	char *temp = NULL;

	DA_LOG_FUNC_START(Default);

	if (DA_NULL == mime || DA_NULL == ext) {
		ret = DA_ERR_INVALID_ARGUMENT;
		DA_LOG_ERR(Default,"Invalid mime type");
		goto ERR;
	}
	DA_LOG_VERBOSE(Default,"mime str[%s]ptr[%p]len[%d]",mime,mime,strlen(mime));
	/* unaliased_mimetype means representative mime among similar types */
	unaliased_mimetype = xdg_mime_unalias_mime_type(mime);

	if (unaliased_mimetype == DA_NULL) {
		ret = DA_ERR_INVALID_MIME_TYPE;
		DA_LOG_ERR(Default,"Invalid mime type : No unsaliased mime type");
		goto ERR;
	}
	DA_LOG(Default,"unaliased_mimetype[%s]\n",unaliased_mimetype);

	/* Get extension name from shared-mime-info */
	extlist = xdg_mime_get_file_names_from_mime_type(unaliased_mimetype);
	if (extlist == DA_NULL || *extlist == DA_NULL) {
		int i = 0;
		ret = DA_ERR_INVALID_MIME_TYPE;
		DA_LOG(Default,"No extension list");
#ifdef _SAMSUNG_MIME_POLICY
		for (i = 0; i < MAX_SEC_MIME_TABLE_INDEX; i++)
		{
			if (strncmp(sec_mime_table[i].mime, mime, strlen(mime)) == 0) {
				strncpy(ext_temp, sec_mime_table[i].ext, DA_MAX_STR_LEN-1);
				ret = DA_RESULT_OK;
				break;
			}
		}
#endif
	} else { /* For drm case, this else statement is needed */
		DA_LOG(Default,"extlist[%s]\n",*extlist);
		strncpy(ext_temp, *extlist, DA_MAX_STR_LEN);
		/* If only one extension name is existed, don't enter here */
		while (*extlist != NULL) {
			int i = 0;
			/* If there are existed many extension names,
			 *  try to search common extension name from table
			 *  with first mime type at extension list*/
			for (i = 0; i < MAX_EXT_TABLE_INDEX; i++)
			{
				if (strncmp(ext_trans_table[i].standard,*extlist,
						strlen(*extlist)) == 0) {
					memset(ext_temp, 0x00, DA_MAX_STR_LEN);
					strncpy(ext_temp,ext_trans_table[i].normal, DA_MAX_STR_LEN-1);
					break;
				}
			}
			DA_LOG(Default,"index[%d]\n",i);
			/* If there is a mime at extension transform table */
			if (i < MAX_EXT_TABLE_INDEX) {
				break;
			}
			DA_LOG(Default,"extlist[%s]\n",*extlist);
			extlist++;
		}
		DA_LOG(Default,"extension from shared mime info[%s]",ext_temp);
	}

	if (strlen(ext_temp) < 1) {
		/* If there is no mime string for OMD descriptor mime type */
		if (strncmp(DD_MIME_STR,mime,strlen(DD_MIME_STR)) == 0) {
			strncpy(ext_temp, DD_EXT_STR, DA_MAX_STR_LEN-1);
			ret = DA_RESULT_OK;
			/* If there is no extension name for "applicaion/vnd.oma.drm.messeages"
			 *  at shared-mime-info*/
		} else if (strncmp(DRM_MIME_STR,mime,strlen(DD_MIME_STR)) == 0) {
			strncpy(ext_temp, DRM_EXT_STR, DA_MAX_STR_LEN-1);
			/* If there is extension name at extlist, the return value can have an error.*/
			ret = DA_RESULT_OK;
		} else {
			ret = DA_ERR_INVALID_MIME_TYPE;
			DA_LOG_ERR(Default,"Invalid mime type : no extension name at list");
		}
	}
	if (ret != DA_RESULT_OK)
		goto ERR;

	temp = strchr(ext_temp,'.');
	if (temp == NULL)
		temp = ext_temp;
	else
		temp++;

	DA_LOG(Default,"final extension name:[%s]",temp);
	*ext = (char*)calloc(1, strlen(temp) + 1);
	if (*ext != DA_NULL) {
		strncpy(*ext, temp,strlen(temp));
	} else	{
		ret = DA_ERR_FAIL_TO_MEMALLOC ;
		goto ERR ;
	}
ERR:
	return ret;
}