#include "hdhomerun_os.h"
#include "hdhomerun_pkt.h"
#include "hdhomerun_debug.h"
#include "hdhomerun_discover.h"
#include "hdhomerun_control.h"
#include "hdhomerun_video.h"
#include "hdhomerun_device.h"


#define WEBSERVER_PORT 8080 

struct sockets {
	int local;
	FILE *in, *out;
};

struct sockets *get_sockets(int);
int socket_setup(void);

void spawn(struct sockets *);


void do_404(FILE *out) {
		fprintf(out, "HTTP/1.1 404 Not Found\r\n");
		fprintf(out, "Content-Type: text/html\r\n");
		fprintf(out, "Content-Length: 5\r\n");
		fprintf(out, "\r\n");
		fprintf(out, "404\r\n");
		fflush(out);

}

void * session(void *v) {
	struct sockets *s = v;
	char inbuf[512];
	char deviceid[32], channel[32], program[32];
	int tunerid = 0;

	int valid = 0;
	struct hdhomerun_device_t *hd;

	/* think globally, program defensively */
	if (!s || !s->out || !s->in)
		return NULL;

	while (fgets(inbuf, sizeof(inbuf), s->in) != 0) {
		printf("-> %s", inbuf);
		if (strncmp(inbuf,"GET /", 5) == 0) {
			printf("GET request\n");
			if (sscanf(inbuf, "GET /%[^/]/%d/%[^/]/%[^/]", deviceid, &tunerid, channel, program) == 4) {
				printf("device: %s\n", deviceid);
				printf("tuner: %d\n", tunerid);
				printf("channel: %s\n", channel);
				printf("program: %s\n", program);

				hd = hdhomerun_device_create_from_str(deviceid);
				hdhomerun_device_set_tuner(hd, tunerid);
				hdhomerun_device_set_tuner_channel(hd, channel);
				hdhomerun_device_set_tuner_program(hd, program);
				hdhomerun_device_set_tuner_target_to_local(hd);
				hdhomerun_device_stream_start(hd);
				
				valid = 1;
			}
		}

		if (strcmp(inbuf, "\r\n") == 0) {
			if (!valid) {
				printf("<- 404\n");
				do_404(s->out);
			} else {
				fprintf(s->out, "HTTP/1.1 200 OK\r\n");
				fprintf(s->out, "Content-Type: video/mpeg\r\n");
				fprintf(s->out, "Transfer-Encoding: chunked\r\n");
				fprintf(s->out, "\r\n");

				size_t size = 1;

				while (size) {
					sleep(1);

					char *ptr = hdhomerun_device_stream_recv(hd, VIDEO_DATA_BUFFER_SIZE_1S * 2, &size);
					printf("%d\n", size);
					fprintf(s->out, "%d\r\n", size);
					if (fwrite(ptr, size, 1, s->out) < 0) {
						break;
					}
				}

				printf("stop\n");

				hdhomerun_device_stream_stop(hd);
				hdhomerun_device_destroy(hd);
			}

			valid = 0;
		}
	}
	return 0;
}

int socket_setup(void) {
	struct sockaddr_in local;
	int r, s, one;

	s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (s == -1) {
		printf("error %d\n", s);
		exit(1);
	}

	one = 1;
	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));

	memset(&local, 0, sizeof(struct sockaddr_in));
	local.sin_family = AF_INET;
	local.sin_port = htons(WEBSERVER_PORT);

	r = bind(s, (struct sockaddr *) &local, sizeof(struct sockaddr_in));
	if (r == -1) {
		printf("bind error\n");
		exit(1);
	}

	r = listen(s, 5);
	if (r == -1) {
		printf("listen error\n");
		exit(1);
	}
	return s;
}

struct sockets * get_sockets(int sock) {
	int conn;
	if ((conn = accept(sock, NULL, NULL)) < 0) {
		printf("accept error\n");
		return 0;
	} else {
		struct sockets *s;
		s = malloc(sizeof(struct sockets));
		if (s == NULL) {
			printf("malloc failed.\n");
			return 0;
		}
		s->local = 0;
		s->in = fdopen(conn, "r");
		s->out = fdopen(conn, "w");
		setlinebuf(s->in);
		setlinebuf(s->out);
		return s;
	}
}

void spawn(struct sockets *s) {
	pthread_t p;
	pthread_create(&p, NULL, session, (void *) s);
}

int main(int argc, char **argv) {
	int sock;

	sock = socket_setup();

	while (1) {
		struct sockets *s = get_sockets(sock);
		if (s) {
printf("connection\n");
			spawn(s);
		}
	}
	return 0;
}


