/*
 * Copyright (C) 2018 "IoT.bzh"
 * Author : Thierry Bultel <thierry.bultel@iot.bzh>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <malloc.h>

#include "hal-bluealsa-transports.h"


static bool halBlueAlsaTransportMatch(
	const struct ba_msg_transport * transport1,
	const struct ba_msg_transport * transport2);

int  halBlueAlsaTransportsInit(bluealsa_transport_t * list) {
	CDS_INIT_LIST_HEAD(&list->list);
	return 0;
}

bluealsa_transport_t *  halBlueAlsaTransportsAdd(
	const bluealsa_watch * watch,
	bluealsa_transport_t * list,
	const struct ba_msg_transport * transport) {

	bluealsa_transport_t  * newTransport = (bluealsa_transport_t*) calloc(1, sizeof(bluealsa_transport_t));
	if (newTransport == NULL)
		goto fail;

	memcpy(&newTransport->transport, transport, sizeof(struct ba_msg_transport));

	newTransport->watch = watch;

	CDS_INIT_LIST_HEAD(&newTransport->list);
	cds_list_add(&newTransport->list, &list->list);

	return newTransport;
fail:
	return NULL;

}

bool halBlueAlsaTransportFind(
	const bluealsa_watch * watch,
	bluealsa_transport_t * list,
	const struct ba_msg_transport * transport) {

	bluealsa_transport_t *tmp;
	bool found = false;
	cds_list_for_each_entry(tmp, &list->list, list) {
		struct ba_msg_transport * _transport = &tmp->transport;

		if (watch != tmp->watch)
			continue;

		if (!halBlueAlsaTransportMatch(_transport, transport))
			continue;

		found = true;
		break;
	}
	return found;
}


int halBlueAlsaTransportUpdate(
	const bluealsa_watch * watch,
	bluealsa_transport_t * list,
	const struct ba_msg_transport *transports,
	size_t nb,
	transport_destructor destructor) {

	bluealsa_transport_t *transport, *sav;

	cds_list_for_each_entry_safe(transport, sav, &list->list, list) {
		struct ba_msg_transport * ba_transport1 = &transport->transport;

		if (watch != transport->watch)
			continue;

		bool found = false;

		for (int ix = 0; ix<nb; ix++) {
			const struct ba_msg_transport * ba_transport2 = &transports[ix];

			if (halBlueAlsaTransportMatch(ba_transport1, ba_transport2)) {
				found = true;
				break;
			}
		}

		if (found)
			continue;

		char transportS[HAL_BLUEALSA_TRANSPORT_LEN_MAX];

		AFB_API_INFO(watch->plugin->api,
				    "Unregister transport %s",
					halBlueAlsaTransportAsString(transportS, HAL_BLUEALSA_TRANSPORT_LEN_MAX, &transport->transport));

		cds_list_del(&transport->list);
		if (destructor) {
			destructor(transport);
		}

		free(transport->transactionUidS);
		free(transport);

	}

	return 0;
}


static bool halBlueAlsaTransportMatch(const struct ba_msg_transport * transport1, const struct ba_msg_transport * transport2) {
	bool ret = false;

	if (transport1->type != transport2->type)
		goto done;

	if (transport1->stream != transport2->stream)
		goto done;

	if (bacmp(&transport1->addr, &transport2->addr) != 0) {
		goto done;
	}
	ret = true;
done:
	return ret;
}


char * halBlueAlsaTransportAsString(char * buff, size_t len, const struct ba_msg_transport * transport) {
	char addr[18];

	ba2str(&transport->addr, addr);
	snprintf(buff, len, "%s,%s,%s", addr,
			transport->type == BA_PCM_TYPE_A2DP?"a2dp":"sco",
			transport->stream == BA_PCM_STREAM_PLAYBACK?"playback":"capture");

	return buff;
}