/*
 * Revised by maxxe <maxxe@rpblc.net>,
 * 18 Dec 2023.
 */

#include "stdinclude.h"
#include "common.h"

#include "command.h"
#include "network.h"
#include "playerdb.h"
#include "shutdown.h"
#include "utils.h"

#if __linux__
#include <bsd/string.h>
#endif

PRIVATE char	 downer[1024];
PRIVATE char	 reason[1024];

PRIVATE time_t	 lastTimeLeft;
PRIVATE time_t	 shutdownStartTime;
PRIVATE time_t	 shutdownTime = 0;

PUBLIC void
output_shut_mess(void)
{
	time_t shuttime = time(NULL);

	fprintf(stderr, "FICS: Shutting down at %s\n", strltime(&shuttime));
}

PUBLIC __dead void
ShutDown(void)
{
	time_t shuttime = time(NULL);

	for (int p1 = 0; p1 < p_num; p1++) {
		if (parray[p1].status != PLAYER_PROMPT)
			continue;

		pprintf(p1, "\n\n    **** Server shutdown ordered by %s. "
		    "****\n", downer);

		if (reason[0] != '\0') {
			pprintf(p1, "\n    **** We are going down because: "
			    "%s. ****\n", reason);
		}
	}

	TerminateCleanup();
	fprintf(stderr, "FICS: Shut down ordered at %s by %s.\n",
	    strltime(&shuttime), downer);
	output_shut_mess();
	net_close();
	exit(0);
}

PUBLIC void
ShutHeartBeat(void)
{
	int	crossing = 0;
	int	p1;
	int	timeLeft;
	time_t	t = time(NULL);

	if (!shutdownTime)
		return;
	if (!lastTimeLeft)
		lastTimeLeft = shutdownTime;

	timeLeft = shutdownTime - (t - shutdownStartTime);

	if (lastTimeLeft > 3600 && timeLeft <= 3600)
		crossing = 1;
	if (lastTimeLeft > 2400 && timeLeft <= 2400)
		crossing = 1;
	if (lastTimeLeft > 1200 && timeLeft <= 1200)
		crossing = 1;
	if (lastTimeLeft > 600 && timeLeft <= 600)
		crossing = 1;
	if (lastTimeLeft > 300 && timeLeft <= 300)
		crossing = 1;
	if (lastTimeLeft > 120 && timeLeft <= 120)
		crossing = 1;
	if (lastTimeLeft > 60 && timeLeft <= 60)
		crossing = 1;
	if (lastTimeLeft > 10 && timeLeft <= 10)
		crossing = 1;

	if (crossing) {
		fprintf(stderr, "FICS:   **** Server going down in %d minutes "
		    "and %d seconds. ****\n\n",
		    (timeLeft / 60),
		    timeLeft - ((timeLeft / 60) * 60));

		if (reason[0] != '\0') {
			fprintf(stderr,"FICS: We are going down because: %s.\n",
			    reason);
		}

		for (p1 = 0; p1 < p_num; p1++) {
			if (parray[p1].status != PLAYER_PROMPT)
				continue;

			pprintf(p1, "\n\n    **** Server going down in %d "
			    "minutes and %d seconds. ****\n",
			    (timeLeft / 60),
			    timeLeft - ((timeLeft / 60) * 60));

			if (reason[0] != '\0') {
				pprintf_prompt(p1, "\n    **** We are going "
				    "down because: %s. ****\n", reason);
			} else
				pprintf_prompt(p1, "\n");
		}
	}

	lastTimeLeft = timeLeft;

	if (timeLeft <= 0)
		ShutDown();
}

/*
 * Tells a user about a shutdown. Returns 1 if there is to be one, and
 * 0 otherwise. (For 'whenshut' command.)
 */
PUBLIC int
check_and_print_shutdown(int p)
{
	int	timeLeft;
	time_t	t = time(NULL);

	if (!shutdownTime)
		return 0;     // no shutdown

	timeLeft = shutdownTime - (t - shutdownStartTime);

	pprintf(p, "\n    **** Server going down in %d minutes and %d seconds. "
	    "****\n",
	    (timeLeft / 60),
	    timeLeft - ((timeLeft / 60) * 60));

	if (reason[0] != '\0') {
		pprintf(p, "\n    **** We are going down because: %s. ****\n",
		    reason);
	}
	return 1;
}


/*
 * Usage: shutdown [now,cancel,time]
 *
 * This command shuts down the server. If the parameter is omitted or
 * is 'now' then the server is immediately halted cleanly. If a time
 * is given then a countdown commences and the server is halted when
 * time is up. If 'cancel' is given then the countdown is stopped.
 */
PUBLIC int
com_shutdown(int p, param_list param)
{
	char	*ptr;
	int	 p1, secs;

	ASSERT(parray[p].adminLevel >= ADMIN_ADMIN);
	strlcpy(downer, parray[p].name, sizeof downer);
	shutdownStartTime = time(NULL);

	if (shutdownTime) {   // Cancel any pending shutdowns
		for (p1 = 0; p1 < p_num; p1++) {
			if (parray[p1].status != PLAYER_PROMPT)
				continue;
			pprintf(p1, "\n\n    **** Server shutdown canceled by "
			    "%s. ****\n", downer);
		}

		shutdownTime = 0;

		if (param[0].type == TYPE_NULL)
			return COM_OK;
	}

	/*
	 * Work out how soon to shut down
	 */
	if (param[0].type == TYPE_NULL) {
		shutdownTime = 300;
	} else {
		if (!strcmp(param[0].val.word, "now")) {
			shutdownTime = 0;
		} else if (!strcmp(param[0].val.word, "die")) {
			fprintf(stderr,"%s salutes FICS and presses the "
			    "self-destruct button.\n", parray[p].name);
			output_shut_mess();
			abort();
		} else if (!strcmp(param[0].val.word, "cancel")) {
			return COM_OK;
		} else {
			ptr = param[0].val.word;
			shutdownTime = secs = 0;
			p1 = 2;

			while (*ptr) {
				switch (*ptr) {
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
					secs = (secs * 10 + *ptr - '0');
					break;
				case ':':
					if (p1--) {
						shutdownTime = (shutdownTime *
						    60 + secs);
						secs = 0;
						break;
					}
				default:
					shutdownTime = 0;
					pprintf(p, "I don't know what you mean "
					    "by %s\n", param[0].val.word);
					return COM_OK;
				}

				ptr++;
			}

			shutdownTime = (shutdownTime * 60 + secs);
		}
	}

	if (shutdownTime <= 0)
		ShutDown();
	if (param[1].type == TYPE_STRING)
		strlcpy(reason, param[1].val.string, sizeof reason);
	else
		reason[0] = '\0';	// No reason - perhaps admin is in a
					// bad mood? :)

	for (p1 = 0; p1 < p_num; p1++) {
		if (parray[p1].status != PLAYER_PROMPT)
			continue;

		pprintf(p1, "\n\n    **** Server shutdown ordered by %s. "
		    "****\n", downer);

		if (reason[0] != '\0') {
			pprintf(p1, "    **** We are going down because: "
			    "%s. ****\n", reason);
		}

		pprintf(p1, "    **** Server going down in %ld minutes and %ld "
		    "seconds. ****\n",
		    (long int)(shutdownTime / 60),
		    (long int)(shutdownTime % 60));
		if (p != p1)  // fix double prompt - DAV
			pprintf_prompt(p1, "\n");
		else
			pprintf(p1, "\n");
	}

	lastTimeLeft = 0;
	return COM_OK;
}

PUBLIC int
server_shutdown(int secs, char *why)
{
	if (shutdownTime && shutdownTime <= secs) {
		/*
		 * Server is already shutting down
		 */
		return 0;
	}

	strlcpy(downer, "Automatic", sizeof downer);
	shutdownTime = secs;
	shutdownStartTime = time(NULL);

	for (int p1 = 0; p1 < p_num; p1++) {
		if (parray[p1].status != PLAYER_PROMPT)
			continue;
		pprintf(p1, "\n\n    **** Automatic Server shutdown. ****\n");
		pprintf(p1, "%s\n", why);
		pprintf_prompt(p1, "    **** Server going down in %ld minutes "
		    "and %ld seconds. ****\n\n",
		    (long int)(shutdownTime / 60),
		    (long int)(shutdownTime - ((shutdownTime / 60) * 60)));
	}

	fprintf(stderr, "FICS:    **** Automatic Server shutdown. ****\n");
	fprintf(stderr, "FICS: %s\n", why);
	return 0;
}

PUBLIC int
com_whenshut(int p, param_list param)
{
	if (check_and_print_shutdown(p) == 0)
		pprintf(p, "No shutdown currently in progress\n");
	return COM_OK;
}