#include "test_set_up.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

// Extern definitions
char display_name[5];
int aswm_pid;
Display* test_display;
Window test_root;
zlog_category_t *test_log;

// Local variables
unsigned int display_count = 100;
char display_fd[128];
int xephyr_pid;

void run_xephyr() {
	FILE* displayfd = fopen(display_fd, "w"); // Used to store the name of the
											  // display on which Xephyr is
											  // running once it's ready.
	char dfd[256]; // File descriptor of the opened temporary file.
	sprintf(dfd, "%i", displayfd->_fileno);
	char* args[] = {"Xephyr", display_name, "-br", "-ac", "-screen", "1440x810", "-displayfd", dfd, "-nopn", NULL};
	execvp(args[0], args);
}

void set_up_test_logger(void) {
	int rc;

	rc = zlog_init(ASWM_TEST_DIR "/log.conf");
	if (rc) {
		printf("Init test zlog failed\n");
	}

	test_log = zlog_get_category("test");
	if (!test_log) {
		printf("Get zlog test_log category failed\n");
	}
}

void tear_down_test_logger(void) {
	zlog_fini();
}

void setUp(void) {
	tmpnam(display_fd); // Creates a temporary file name
	sprintf(display_name, ":%u", display_count); // Loads initial display count
												 // in display name
	// Tries to create the first xephyr instance
	xephyr_pid = fork();
	if(xephyr_pid == 0) {
		run_xephyr();
	} else {
		zlog_info(test_log, "Trying to run Xephyr instance on :%u...", display_count);
	}

	// The following loop waits for one of those two things:
	// 1. The display name on which Xephyr is running is loaded into content,
	// what indicates that the X server is ready.
	// 2. The Xephyr process as stopped, what indicates that the proposed
	// display count was already in use. In that case, try again after
	// incrementing display count, until valid Xephyr display is running.
	char content[256];
	while(strlen(content) == 0) {
		FILE* displayfd = fopen(display_fd, "r");
		if(displayfd != NULL) {
			fgets(content, 256, displayfd);
			fseek(displayfd, 0, SEEK_SET);
			fclose(displayfd);
		}

		int stat_loc;
		if(waitpid(xephyr_pid, &stat_loc, WNOHANG) < 0) {
			display_count++;
			sprintf(display_name, ":%u", display_count);
			xephyr_pid = fork();
			if(xephyr_pid == 0) {
				run_xephyr();
			} else {
				zlog_info(test_log, "Trying to run Xephyr instance on :%u...", display_count);
			}
		}
	}
	sscanf(content, "%i", &display_count);

	aswm_pid = fork();
	if(aswm_pid == 0) {
		zlog_info(test_log, "Running aswm instance on %s...", display_name);
		char* args[] = {"./aswm", "--log", ASWM_TEST_DIR "/aswm_log.conf", NULL};
		char display_env[256];
		sprintf(display_env, "DISPLAY=%s", display_name);
		char* envp[] = {display_env, NULL};
		execve(args[0], args, envp);
	}
	// TODO: condition in aswm to ensure it is running
	sleep(2);

	test_display = XOpenDisplay(display_name);
	test_root = DefaultRootWindow(test_display);
}

void tearDown(void) {
	XCloseDisplay(test_display);

	kill(aswm_pid, SIGTERM);
	kill(xephyr_pid, SIGTERM);
}