/**
 * Puts the device into deep sleep mode and disconnects from host.
 *
 * @param client The diagnostics_relay client
 *
 * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
 *  DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL,
 *  DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the
 *  request
 */
diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
{
	if (!client)
		return DIAGNOSTICS_RELAY_E_INVALID_ARG;

	diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();

	plist_dict_insert_item(dict,"Request", plist_new_string("Sleep"));
	ret = diagnostics_relay_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = diagnostics_relay_receive(client, &dict);
	if (!dict) {
		return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
	}

	int check = diagnostics_relay_check_result(dict);
	if (check == RESULT_SUCCESS) {
		ret = DIAGNOSTICS_RELAY_E_SUCCESS;
	} else if (check == RESULT_UNKNOWN_REQUEST) {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
	} else {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
	}

	plist_free(dict);
	return ret;
}
LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
{
	if (!client)
		return DIAGNOSTICS_RELAY_E_INVALID_ARG;

	diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	plist_dict_set_item(dict, "Request", plist_new_string("Goodbye"));

	ret = diagnostics_relay_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = diagnostics_relay_receive(client, &dict);
	if (!dict) {
		debug_info("did not get goodbye response back");
		return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
	}

	int check = diagnostics_relay_check_result(dict);
	if (check == RESULT_SUCCESS) {
		ret = DIAGNOSTICS_RELAY_E_SUCCESS;
	} else if (check == RESULT_UNKNOWN_REQUEST) {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
	} else {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
	}

	plist_free(dict);
	dict = NULL;
	return ret;
}
diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* name, const char* _class, plist_t* result)
{
	if (!client || (name == NULL && _class == NULL) || result == NULL)
		return DIAGNOSTICS_RELAY_E_INVALID_ARG;

	diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	if (name)
		plist_dict_insert_item(dict,"EntryName", plist_new_string(name));
	if (_class)
		plist_dict_insert_item(dict,"EntryClass", plist_new_string(_class));
	plist_dict_insert_item(dict,"Request", plist_new_string("IORegistry"));
	ret = diagnostics_relay_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = diagnostics_relay_receive(client, &dict);
	if (!dict) {
		return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
	}

	int check = diagnostics_relay_check_result(dict);
	if (check == RESULT_SUCCESS) {
		ret = DIAGNOSTICS_RELAY_E_SUCCESS;
	} else if (check == RESULT_UNKNOWN_REQUEST) {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
	} else {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
	}

	if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
		plist_free(dict);
		return ret;
	}

	plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
	if (value_node) {
		*result = plist_copy(value_node);
	}

	plist_free(dict);
	return ret;
}
static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, int flags)
{
	if (!client)
		return DIAGNOSTICS_RELAY_E_INVALID_ARG;

	diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	plist_dict_insert_item(dict,"Request", plist_new_string(name));

	if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) {
		plist_dict_insert_item(dict, "WaitForDisconnect", plist_new_bool(1));
	}

	if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS) {
		plist_dict_insert_item(dict, "DisplayPass", plist_new_bool(1));
	}

	if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL) {
		plist_dict_insert_item(dict, "DisplayFail", plist_new_bool(1));
	}

	ret = diagnostics_relay_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = diagnostics_relay_receive(client, &dict);
	if (!dict) {
		return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
	}

	int check = diagnostics_relay_check_result(dict);
	if (check == RESULT_SUCCESS) {
		ret = DIAGNOSTICS_RELAY_E_SUCCESS;
	} else if (check == RESULT_UNKNOWN_REQUEST) {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
	} else {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
	}

	plist_free(dict);
	return ret;
}
diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result)
{
	if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL)
		return DIAGNOSTICS_RELAY_E_INVALID_ARG;

	diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	plist_dict_insert_item(dict,"MobileGestaltKeys", plist_copy(keys));
	plist_dict_insert_item(dict,"Request", plist_new_string("MobileGestalt"));
	ret = diagnostics_relay_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = diagnostics_relay_receive(client, &dict);
	if (!dict) {
		return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
	}

	int check = diagnostics_relay_check_result(dict);
	if (check == RESULT_SUCCESS) {
		ret = DIAGNOSTICS_RELAY_E_SUCCESS;
	} else if (check == RESULT_UNKNOWN_REQUEST) {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
	} else {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
	}

	if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
		plist_free(dict);
		return ret;
	}

	plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
	if (value_node) {
		*result = plist_copy(value_node);
	}

	plist_free(dict);
	return ret;
}
LIBIMOBILEDEVICE_API diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result)
{
	if (!client || plane == NULL || result == NULL)
		return DIAGNOSTICS_RELAY_E_INVALID_ARG;

	diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	plist_dict_set_item(dict,"CurrentPlane", plist_new_string(plane));
	plist_dict_set_item(dict,"Request", plist_new_string("IORegistry"));
	ret = diagnostics_relay_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = diagnostics_relay_receive(client, &dict);
	if (!dict) {
		return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
	}

	int check = diagnostics_relay_check_result(dict);
	if (check == RESULT_SUCCESS) {
		ret = DIAGNOSTICS_RELAY_E_SUCCESS;
	} else if (check == RESULT_UNKNOWN_REQUEST) {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
	} else {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
	}

	if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
		plist_free(dict);
		return ret;
	}

	plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
	if (value_node) {
		*result = plist_copy(value_node);
	}

	plist_free(dict);
	return ret;
}
diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics)
{
	if (!client || diagnostics == NULL)
		return DIAGNOSTICS_RELAY_E_INVALID_ARG;

	diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	plist_dict_insert_item(dict,"Request", plist_new_string(type));
	ret = diagnostics_relay_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = diagnostics_relay_receive(client, &dict);
	if (!dict) {
		return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
	}

	int check = diagnostics_relay_check_result(dict);
	if (check == RESULT_SUCCESS) {
		ret = DIAGNOSTICS_RELAY_E_SUCCESS;
	} else if (check == RESULT_UNKNOWN_REQUEST) {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
	} else {
		ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
	}

	if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
		plist_free(dict);
		return ret;
	}

	plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
	if (value_node) {
		*diagnostics = plist_copy(value_node);
	}

	plist_free(dict);
	return ret;
}