/* B01902062 藍ĉŒşç‘‹ */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "common.h"
#include "server.h"
#include "proc.h"

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>

static volatile sig_atomic_t proc_message_request;
static volatile sig_atomic_t proc_quit_request;

static void proc_quit_request_setter (int signo) {
	proc_quit_request = 1;
}

static void proc_message_request_setter (int signo) {
	proc_message_request = 1;
}

static void proc_message_print (server* svr, request* req, int maxfd) {
	putchar ('\n');

	printf (
		"Dump server information ...\n"
#ifdef READ_SERVER
		"  This is read_server\n"
#endif
#ifdef WRITE_SERVER
		"  This is write_server\n"
#endif
		"  Server hostname: %s\n"
		"  Server port: %hu\n"
		"  Server maxfd: %d\n"
		"  Server is listening on fd %d\n",
		svr->hostname, svr->port, maxfd, svr->listen_fd);

	puts ("Dump request table ...");
	for (int i = 0; i < maxfd; i++) {
		if (req[i].active) {
			printf (
				"  Client %d hostname: %s\n"
				"  Client %d filename: %s\n"
				"  Client %d filename done: %s\n"
				"  Client %d transfer started: %s\n",
				i, req[i].host,
				i, req[i].filename,
				i, req[i].header_done ? "true" : "false",
				i, req[i].header_accept ? "true" : "false");
		}
	}

	puts ("Dump file table ...");
	for (int i = 0; i < maxfd; i++) {
		if (svr->file_table->flist[i].active) {
			printf (
				"  Entry %d reference count: %d\n"
				"  Entry %d device: %llu\n"
				"  Entry %d inode: %llu\n"
				"  Entry %d file descriptors:",
				i, svr->file_table->flist[i].ref_count,
				i, (unsigned long long)svr->file_table->flist[i].fdev,
				i, (unsigned long long)svr->file_table->flist[i].fino, i);
			for (int j = 0; j < maxfd; j++) {
				if (FD_ISSET (j, &svr->file_table->flist[i].fset))
					printf (" %d", j);
			}
			putchar ('\n');
		}
	}

	puts ("Type Ctrl-\\ to terminate the server\n");
	proc_message_request = 0;
}

#ifndef HAVE_GETDTABLESIZE
static int my_getdtablesize (void) {
	long rval = sysconf (_SC_OPEN_MAX);
	if (rval < 0) {
# ifdef _POSIX_OPEN_MAX
		rval = _POSIX_OPEN_MAX
# else
		rval = 20;
# endif
	}
	return rval;
}
#endif

int main (int argc, char** argv) {
	if (argc != 2) {
		fprintf(stderr, "usage: %s [port]\n", argv[0]);
		exit(1);
	}

	// Setup signal handlers
	struct sigaction signal_action = {
		.sa_handler = SIG_IGN,
		.sa_flags = 0
	};
	sigemptyset (&signal_action.sa_mask);
	sigaction (SIGPIPE, &signal_action, NULL);
	signal_action.sa_handler = proc_message_request_setter;
	sigaction (SIGINT, &signal_action, NULL);
	signal_action.sa_handler = proc_quit_request_setter;
	sigaction (SIGQUIT, &signal_action, NULL);

	// Get file descripter table size
#ifdef HAVE_GETDTABLESIZE
	int maxfd = getdtablesize();
#else
	int maxfd = my_getdtablesize();
#endif
	if (maxfd < 0)
		e_err_exit ("getdtablesize");

	// Initialize server
	server svr;  // server
	server_init(&svr, (unsigned short) atoi(argv[1]), maxfd);

	// Initialize request table
	request* requestP = NULL;  // point to a list of requests
	requestP = (request*) e_malloc(sizeof(request) * maxfd);

	for (int i = 0; i < maxfd; i++)
		request_init(&requestP[i]);

	requestP[svr.listen_fd].conn_fd = svr.listen_fd;
	strcpy(requestP[svr.listen_fd].host, svr.hostname);

	// Loop for handling connections
	printf("\nstarting on %.80s, port %d, fd %d, maxfd %d ...\n",
		svr.hostname, svr.port, svr.listen_fd, maxfd);

	while (!proc_quit_request) {
		procconn (&svr, requestP, maxfd, (struct timeval) { 1, 0 });
		if (proc_message_request) {
			proc_message_print (&svr, requestP, maxfd);
		}
	}

	printf("\nquitting...\n");

	for (int i = 0; i < maxfd; i++) {
		if (requestP[i].filename != NULL) {
			free (requestP[i].filename);
			requestP[i].filename = NULL;
		}
	}

	free(requestP);
	server_free(&svr);

	return 0;
}