#include "rtsp-client.h"
#include "rtsp-client-internal.h"
#include "rtp-profile.h"
#include "sdp.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#if defined(OS_WINDOWS)
	#define strncasecmp	_strnicmp
#endif

struct rtsp_client_t* rtsp_client_create(const char* uri, const char* usr, const char* pwd, const struct rtsp_client_handler_t *handler, void* param)
{
	struct rtsp_client_t *rtsp;
	rtsp = (struct rtsp_client_t*)calloc(1, sizeof(*rtsp));
	if(NULL == rtsp)
		return NULL;

	snprintf(rtsp->uri, sizeof(rtsp->uri) - 1, "%s", uri);
	snprintf(rtsp->usr, sizeof(rtsp->usr) - 1, "%s", usr ? usr : "");
	snprintf(rtsp->pwd, sizeof(rtsp->pwd) - 1, "%s", pwd ? pwd : "");
	
	rtsp->parser = http_parser_create(HTTP_PARSER_RESPONSE, NULL, NULL);
	memcpy(&rtsp->handler, handler, sizeof(rtsp->handler));
	rtsp->rtp.onrtp = rtsp->handler.onrtp;
	rtsp->rtp.param = param;
	rtsp->state = RTSP_INIT;
	rtsp->param = param;
	rtsp->cseq = 1;
	rtsp->auth_failed = 0;

	return rtsp;
}

void rtsp_client_destroy(struct rtsp_client_t *rtsp)
{
	if (rtsp->parser)
	{
		http_parser_destroy(rtsp->parser);
		rtsp->parser = NULL;
	}

	if (rtsp->rtp.data)
	{
		assert(rtsp->rtp.capacity > 0);
		free(rtsp->rtp.data);
		rtsp->rtp.data = NULL;
		rtsp->rtp.capacity = 0;
	}

	free(rtsp);
}

static int rtsp_client_handle(struct rtsp_client_t* rtsp, http_parser_t* parser)
{
	switch (rtsp->state)
	{
	case RTSP_DESCRIBE: return rtsp_client_describe_onreply(rtsp, parser);
	case RTSP_SETUP:	return rtsp_client_setup_onreply(rtsp, parser);
	case RTSP_PLAY:		return rtsp_client_play_onreply(rtsp, parser);
	case RTSP_PAUSE:	return rtsp_client_pause_onreply(rtsp, parser);
	case RTSP_TEARDWON: return rtsp_client_teardown_onreply(rtsp, parser);
	case RTSP_OPTIONS:	return rtsp_client_options_onreply(rtsp, parser);
	case RTSP_GET_PARAMETER: return rtsp_client_get_parameter_onreply(rtsp, parser);
	case RTSP_SET_PARAMETER: return rtsp_client_set_parameter_onreply(rtsp, parser);
	case RTSP_ANNOUNCE:	return rtsp_client_announce_onreply(rtsp, parser);
	case RTSP_RECORD:	return rtsp_client_record_onreply(rtsp, parser);
	default: assert(0); return -1;
	}
}

static int rtsp_check_response_line(const char* data, size_t bytes)
{
	const char* line = "RTSP/1.0 ";
	assert(bytes > 0);
	if (bytes >= 9)
		bytes = 9;
	return strncasecmp(line, data, 9);
}

int rtsp_client_input(struct rtsp_client_t *rtsp, const void* data, size_t bytes)
{
	int r;
	size_t remain;
	const uint8_t* p, *end;

	r = 0;
	p = (const uint8_t*)data;
	end = p + bytes;

	do
	{
		if(rtsp->parser_need_more_data || 0 == rtsp_check_response_line((const char*)p, (size_t)(end - p)))
		{
			// TODO: server->client Announce (update sdp)

			remain = (size_t)(end - p);
			r = http_parser_input(rtsp->parser, p, &remain);
			rtsp->parser_need_more_data = r;
			assert(r <= 2); // 1-need more data
			if (0 == r)
			{
				r = rtsp_client_handle(rtsp, rtsp->parser);
				http_parser_clear(rtsp->parser); // reset parser
				assert((size_t)remain < bytes);
			}
			p = end - remain;
		}
		else
		{
			//if (0 == rtsp->parser_need_more_data && (*p == '$' || 0 != rtsp->rtp.state))

			p = rtp_over_rtsp(&rtsp->rtp, p, end);
		}
	} while (p < end && r >= 0);

	assert(r <= 2);
	return r >= 0 ? 0 : r;
}

const char* rtsp_client_get_header(struct rtsp_client_t* rtsp, const char* name)
{
	return http_get_header_by_name(rtsp->parser, name);
}

int rtsp_client_media_count(struct rtsp_client_t *rtsp)
{
	return rtsp->media_count;
}

const struct rtsp_header_transport_t* rtsp_client_get_media_transport(struct rtsp_client_t *rtsp, int media)
{
	if(media < 0 || media >= rtsp->media_count)
		return NULL;
	return rtsp->transport + media;
}

const struct rtsp_media_t* rtsp_client_get_media(struct rtsp_client_t* rtsp, int media)
{
	if (media < 0 || media >= rtsp->media_count)
		return NULL;
	return rtsp->media + media;
}

const char* rtsp_client_get_media_encoding(struct rtsp_client_t *rtsp, int media)
{
	if (media < 0 || media >= rtsp->media_count)
		return NULL;
	return rtsp->media[media].avformats[0].encoding;
}

const char* rtsp_client_get_media_fmtp(struct rtsp_client_t *rtsp, int media)
{
	if (media < 0 || media >= rtsp->media_count)
		return NULL;
	return rtsp->media[media].avformats[0].fmtp;
}

int rtsp_client_get_media_payload(struct rtsp_client_t *rtsp, int media)
{
	if (media < 0 || media >= rtsp->media_count)
		return -1;
	return rtsp->media[media].avformats[0].fmt;
}

int rtsp_client_get_media_rate(struct rtsp_client_t *rtsp, int media)
{
	int rate;
	if (media < 0 || media >= rtsp->media_count)
		return -1;
	
	rate = rtsp->media[media].avformats[0].rate;
	if (0 == rate)
	{
		const struct rtp_profile_t* profile;
		profile = rtp_profile_find(rtsp->media[media].avformats[0].fmt);
		rate = profile ? profile->frequency : 0;
	}
	return rate;
}

int rtsp_client_get_media_type(struct rtsp_client_t* rtsp, int media)
{
	if (media < 0 || media >= rtsp->media_count)
		return -1;
	return sdp_option_media_from(rtsp->media[media].media);
}
