#include "rtp-member-list.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

#define N_SOURCE 2 // unicast(1S + 1R)

struct rtp_member_list
{
	struct rtp_member *members[N_SOURCE];
	struct rtp_member **ptr;
	int count;
	int capacity;
};

void* rtp_member_list_create()
{
	return (struct rtp_member_list *)calloc(1, sizeof(struct rtp_member_list));
}

void rtp_member_list_destroy(void* members)
{
	int i;
	struct rtp_member_list *p;
	p = (struct rtp_member_list *)members;

	for(i = 0; i < p->count; i++)
	{
		rtp_member_release(i >= N_SOURCE ? p->ptr[i-N_SOURCE] : p->members[i]);
	}

	if(p->ptr)
	{
		assert(p->capacity > 0);
		free(p->ptr);
	}

	free(p);
}

int rtp_member_list_count(void* members)
{
	struct rtp_member_list *p;
	p = (struct rtp_member_list *)members;
	return p->count;
}

struct rtp_member* rtp_member_list_get(void* members, int index)
{
	struct rtp_member_list *p;
	p = (struct rtp_member_list *)members;
	if(index >= p->count || index < 0)
		return NULL;

	return index >= N_SOURCE ? p->ptr[index-N_SOURCE] : p->members[index];
}

struct rtp_member* rtp_member_list_find(void* members, uint32_t ssrc)
{
	int i;
	struct rtp_member *s;
	struct rtp_member_list *p;
	p = (struct rtp_member_list *)members;

	for(i = 0; i < p->count; i++)
	{
		s = i < N_SOURCE ? p->members[i] : p->ptr[i-N_SOURCE];
		if(s->ssrc == ssrc)
			return s;
	}
	return NULL;
}

int rtp_member_list_add(void* members, struct rtp_member* s)
{
	struct rtp_member_list *p;
	p = (struct rtp_member_list *)members;

	if(p->count >= N_SOURCE)
	{
		if(p->count - N_SOURCE >= p->capacity)
		{
			void* ptr;
			ptr = (struct rtp_member **)realloc(p->ptr, (p->capacity+8)*sizeof(struct rtp_member*));
			if(!ptr)
				return -ENOMEM;
			p->ptr = ptr;
			p->capacity += 8;
		}
		p->ptr[p->count - N_SOURCE] = s;
	}
	else
	{
		p->members[p->count] = s;
	}

	rtp_member_addref(s);
	p->count++;
	return 0;
}

int rtp_member_list_delete(void* members, uint32_t ssrc)
{
	int i;
	struct rtp_member *s;
	struct rtp_member_list *p;
	p = (struct rtp_member_list *)members;

	for(i = 0; i < p->count; i++)
	{
		s = i < N_SOURCE ? p->members[i] : p->ptr[i-N_SOURCE];
		if(s->ssrc != ssrc)
			continue;

		if(i < N_SOURCE)
		{
			if(i+1 < N_SOURCE)
			{
				memmove(p->members + i, p->members+i+1, (N_SOURCE-i-1) * sizeof(struct rtp_member*));
			}

			if(p->count > N_SOURCE)
			{
				p->members[N_SOURCE-1] = p->ptr[0];
				memmove(p->ptr, p->ptr + 1, (p->count-N_SOURCE-1) * sizeof(struct rtp_member*));
			}
		}
		else
		{
			if(i + 1 < p->count)
			{
				memmove(p->ptr + i - N_SOURCE, p->ptr + i + 1 - N_SOURCE, (p->count-i-1) * sizeof(struct rtp_member*));
			}
		}

		rtp_member_release(s);
		p->count--;
		return 0;
	}

	return -1; // NOT_FOUND
}
