#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>

#include <time.h>

static sdp_record_t  *record;
static sdp_session_t *session;

#define TIMESERVER_UUID "2c3ef0c8-4367-4369-b1df-b7315e76332a"
static uint128_t* timeserver_uuid_data = NULL;
static uuid_t timeserver_uuid;

static uint16_t timeserver_psm = 0xcc33;

uint128_t *timeserver_create_base_uuid(void)
{
        char baseStr[128];
        int delim = '-';
        unsigned long dataLongValue;
        char *delimPtr;
        char *dataPtr;
        char temp[10];
        int toBeCopied;
        char *data;

        if (timeserver_uuid_data == NULL) {
                strcpy(baseStr, TIMESERVER_UUID);
                timeserver_uuid_data = (uint128_t *)malloc(sizeof(uint128_t));
                data = timeserver_uuid_data->data;
                memset(data, '\0', sizeof(uint128_t));
                memset(temp, '\0', 10);
                dataPtr = baseStr;
                delimPtr = NULL;
                delimPtr = strchr(dataPtr, delim);
                toBeCopied = delimPtr - dataPtr;
                if (toBeCopied != 8) {
                        printf("To be copied(1) : %d\n", toBeCopied);
                        return NULL;
                }
                strncpy(temp, dataPtr, toBeCopied);
                dataLongValue = htonl(strtoul(temp, NULL, 16));
                memcpy(&data[0], &dataLongValue, 4);

                /*
                 * Get the next 4 bytes (note that there is a "-"
                 * between them now)
                 */
                memset(temp, '\0', 10);
                dataPtr = delimPtr + 1;
                delimPtr = strchr(dataPtr, delim);
                toBeCopied = delimPtr - dataPtr;
                if (toBeCopied != 4) {
                        printf("To be copied(2) : %d\n", toBeCopied);
                        return NULL;
                }
                strncpy(temp, dataPtr, toBeCopied);
                dataPtr = delimPtr + 1;
                delimPtr = strchr(dataPtr, delim);
                toBeCopied = delimPtr - dataPtr;
                if (toBeCopied != 4) {
                        printf("To be copied(3) : %d\n", toBeCopied);
                        return NULL;
                }
                strncat(temp, dataPtr, toBeCopied);
                dataLongValue = htonl(strtoul(temp, NULL, 16));
                memcpy(&data[4], &dataLongValue, 4);

                /*
                 * Get the last 4 bytes (note that there are 6 bytes
                 * after the last separator, which is truncated (2+4)
                 */
                memset(temp, '\0', 10);
                dataPtr = delimPtr + 1;
                dataPtr = delimPtr + 1;
                delimPtr = strchr(dataPtr, delim);
                toBeCopied = delimPtr - dataPtr;
                if (toBeCopied != 4) {
                        printf("To be copied(4) : %d\n", toBeCopied);
                        return NULL;
                }
                strncpy(temp, dataPtr, toBeCopied);
                strncat(temp, (delimPtr + 1), 4);
                dataLongValue = htonl(strtoul(temp, NULL, 16));
                memcpy(&data[8], &dataLongValue, 4);
                dataLongValue = htonl(strtoul(delimPtr + 5, NULL, 16));
                memcpy(&data[12], &dataLongValue, 4);
        }
        return timeserver_uuid_data;
}


void timeserver_initialize(void) 
{
	timeserver_create_base_uuid();
	sdp_uuid128_create(&timeserver_uuid, timeserver_uuid_data);
}


void timeserver_sdp_unregister(void) 
{
	if (record && sdp_record_unregister(session, record))
		fprintf (2, "Service record unregistration failed.");

	sdp_close(session);

	printf("Unregistered\n");
}

int timeserver_sdp_register()
{
	sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
	uuid_t root_uuid, l2cap;
	sdp_profile_desc_t profile[1];
	sdp_list_t *proto;
	uint16_t version = 0x0100;

	session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
	record = sdp_record_alloc();
	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
	root = sdp_list_append(NULL, &root_uuid);
	sdp_set_browse_groups(record, root);

	sdp_uuid16_create(&l2cap, L2CAP_UUID);
	proto = sdp_list_append(NULL, &l2cap);
	proto = sdp_list_append(proto, sdp_data_alloc(SDP_UINT16, &timeserver_psm));
	apseq = sdp_list_append(NULL, proto);
	aproto   = sdp_list_append(NULL, apseq);
	sdp_set_access_protos(record, aproto);

	svclass = sdp_list_append(NULL, &timeserver_uuid);
	sdp_set_service_classes(record, svclass);

	sdp_uuid128_create(&profile[0].uuid, timeserver_uuid_data);
	profile[0].version = 0x0100;
	pfseq = sdp_list_append(NULL, &profile[0]);
	sdp_set_profile_descs(record, pfseq);

	sdp_set_info_attr(record, "Time server example", NULL, NULL);

	sdp_record_register(session, record, 0);
	return 0;
}

void timeserver_serve() {
	int sock, client;
	struct sockaddr_l2 addr;
	int addrlen;
	struct hci_dev_info di;
	unsigned char buff[256];
	struct tm* heure;
	time_t seconds;

	addr.l2_family = AF_BLUETOOTH;
	bacpy(&addr.l2_bdaddr, BDADDR_ANY);
	addr.l2_psm    = htobs(0x4433);

	sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
	bind(sock, (struct sockaddr *)&addr, sizeof(addr));
	listen(sock, 10);
	addrlen = sizeof(addr);
	client = accept (sock, (struct sockaddr *)&addr, &addrlen);
	read (sock, buff, 1);
	printf ("Received: %02x\n", buff[0]);
	seconds = time(NULL);
	heure = localtime(&seconds);
	buff[0] = 2;
	buff[1] = heure->tm_hour;
	buff[2] = heure->tm_min;
	buff[3] = heure->tm_sec;
	buff[4] = 2 + buff[1] + buff[2] + buff[3];
	write (sock, buff, 5);
	printf ("Sent: 02:%02x:%02x:%02x:%02x\n", buff[1], buff[2], buff[3], buff[4]);
	close (client);
	close (sock);
}

int main(void) {
	printf("\nStage 1\n");
	timeserver_initialize();

	printf("\nStage 2\n");
	if (timeserver_sdp_register()) return 1;

	printf("\nStage 3\n");
	timeserver_serve();

	printf("\nStage 4\n");
	timeserver_sdp_unregister();

	printf("\nEnd\n");

	return 0;
}
