/*
 * service.c
 * generic service implementation.
 *
 * Copyright (c) 2013 Nikias Bassen. All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>

#include "service.h"
#include "idevice.h"
#include "common/debug.h"

/**
 * Convert an idevice_error_t value to an service_error_t value.
 * Used internally to get correct error codes.
 *
 * @param err An idevice_error_t error code
 *
 * @return A matching service_error_t error code,
 *     SERVICE_E_UNKNOWN_ERROR otherwise.
 */
static service_error_t idevice_to_service_error(idevice_error_t err)
{
	switch (err) {
		case IDEVICE_E_SUCCESS:
			return SERVICE_E_SUCCESS;
		case IDEVICE_E_INVALID_ARG:
			return SERVICE_E_INVALID_ARG;
		case IDEVICE_E_SSL_ERROR:
			return SERVICE_E_SSL_ERROR;
		case IDEVICE_E_NOT_ENOUGH_DATA:
			return SERVICE_E_NOT_ENOUGH_DATA;
		case IDEVICE_E_TIMEOUT:
			return SERVICE_E_TIMEOUT;
		default:
			break;
	}
	return SERVICE_E_UNKNOWN_ERROR;
}

LIBIMOBILEDEVICE_API service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client)
{
	if (!device || !service || service->port == 0 || !client || *client)
		return SERVICE_E_INVALID_ARG;

	/* Attempt connection */
	idevice_connection_t connection = NULL;
	if (idevice_connect(device, service->port, &connection) != IDEVICE_E_SUCCESS) {
		return SERVICE_E_MUX_ERROR;
	}

	/* create client object */
	service_client_t client_loc = (service_client_t)malloc(sizeof(struct service_client_private));
	client_loc->connection = connection;

	/* enable SSL if requested */
	if (service->ssl_enabled == 1)
		service_enable_ssl(client_loc);

	/* all done, return success */
	*client = client_loc;
	return SERVICE_E_SUCCESS;
}

LIBIMOBILEDEVICE_API service_error_t service_client_factory_start_service(idevice_t device, const char* service_name, void **client, const char* label, int32_t (*constructor_func)(idevice_t, lockdownd_service_descriptor_t, void**), int32_t *error_code)
{
	*client = NULL;

	lockdownd_client_t lckd = NULL;
	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &lckd, label)) {
		debug_info("Could not create a lockdown client.");
		return SERVICE_E_START_SERVICE_ERROR;
	}

	lockdownd_service_descriptor_t service = NULL;
	lockdownd_start_service(lckd, service_name, &service);
	lockdownd_client_free(lckd);

	if (!service || service->port == 0) {
		debug_info("Could not start service %s!", service_name);
		return SERVICE_E_START_SERVICE_ERROR;
	}

	int32_t ec;
	if (constructor_func) {
		ec = (int32_t)constructor_func(device, service, client);
	} else {
		ec = service_client_new(device, service, (service_client_t*)client);
	}
	if (error_code) {
		*error_code = ec;
	}

	if (ec != SERVICE_E_SUCCESS) {
		debug_info("Could not connect to service %s! Port: %i, error: %i", service_name, service->port, ec);
	}

	lockdownd_service_descriptor_free(service);
	service = NULL;

	return (ec == SERVICE_E_SUCCESS) ? SERVICE_E_SUCCESS : SERVICE_E_START_SERVICE_ERROR;
}

LIBIMOBILEDEVICE_API service_error_t service_client_free(service_client_t client)
{
	if (!client)
		return SERVICE_E_INVALID_ARG;

	service_error_t err = idevice_to_service_error(idevice_disconnect(client->connection));

	free(client);
	client = NULL;

	return err;
}

LIBIMOBILEDEVICE_API service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent)
{
	service_error_t res = SERVICE_E_UNKNOWN_ERROR;
	uint32_t bytes = 0;

	if (!client || (client && !client->connection) || !data || (size == 0)) {
		return SERVICE_E_INVALID_ARG;
	}

	debug_info("sending %d bytes", size);
	res = idevice_to_service_error(idevice_connection_send(client->connection, data, size, &bytes));
	if (res != SERVICE_E_SUCCESS) {
		debug_info("ERROR: sending to device failed.");
	}
	if (sent) {
		*sent = bytes;
	}

	return res;
}

LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
{
	service_error_t res = SERVICE_E_UNKNOWN_ERROR;
	uint32_t bytes = 0;

	if (!client || (client && !client->connection) || !data || (size == 0)) {
		return SERVICE_E_INVALID_ARG;
	}

	res = idevice_to_service_error(idevice_connection_receive_timeout(client->connection, data, size, &bytes, timeout));
	if (res != SERVICE_E_SUCCESS && res != SERVICE_E_TIMEOUT) {
		debug_info("could not read data");
		return res;
	}
	if (received) {
		*received = bytes;
	}

	return res;
}

LIBIMOBILEDEVICE_API service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received)
{
	return service_receive_with_timeout(client, data, size, received, 30000);
}

LIBIMOBILEDEVICE_API service_error_t service_enable_ssl(service_client_t client)
{
	if (!client || !client->connection)
		return SERVICE_E_INVALID_ARG;
	return idevice_to_service_error(idevice_connection_enable_ssl(client->connection));
}

LIBIMOBILEDEVICE_API service_error_t service_disable_ssl(service_client_t client)
{
	return service_disable_bypass_ssl(client, 0);
}

LIBIMOBILEDEVICE_API service_error_t service_disable_bypass_ssl(service_client_t client, uint8_t sslBypass)
{
	if (!client || !client->connection)
		return SERVICE_E_INVALID_ARG;
	return idevice_to_service_error(idevice_connection_disable_bypass_ssl(client->connection, sslBypass));
}

