/*
 * Kangaroo Punch MultiPlayer Game Server Mark II
 * Copyright (C) 2020-2021  Scott Duensing
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */


#include "welcome.h"
#include "settings.h"
#include "login.h"

#include "taglist.h"
#include "task.h"
#include "config.h"
#include "comport.h"
#include "timer.h"
#include "network.h"
#include "runtime.h"

#include "window.h"
#include "picture.h"
#include "button.h"
#include "msgbox.h"


static WindowT  *_winWelcome   = NULL;
static PictureT *_picLogo      = NULL;
static PictureT *_picInit      = NULL;
static PictureT *_picDialing   = NULL;
static PictureT *_picConnect   = NULL;
static ButtonT  *_btnQuit      = NULL;
static ButtonT  *_btnSettings  = NULL;
static ButtonT  *_btnConnect   = NULL;


static void taskConnectClick(void *data);
static void btnMsgBox(MsgBoxButtonT button);
static void btnMsgBoxQuit(MsgBoxButtonT button);
static void btnQuitClick(WidgetT *widget);
static void btnSettingsClick(WidgetT *widget);
static void setButtons(uint8_t enabled);
static void settingsFinished(WidgetT *widget);


static void btnMsgBox(MsgBoxButtonT button) {
	(void)button;

	// Re-enable buttons.
	setButtons(1);

	// Reset to Welcome image.
	widgetVisibleSet(W(_picLogo), 1);
	widgetVisibleSet(W(_picInit), 0);
	widgetVisibleSet(W(_picDialing), 0);
	widgetVisibleSet(W(_picConnect), 0);
}


static void btnMsgBoxQuit(MsgBoxButtonT button) {
	if (button == MSGBOX_BUTTON_ONE) {
		guiStop();
	} else {
		setButtons(1);
	}
}


static void taskConnectClick(void *data) {
	int32_t            r            = 0;
	char               buffer[1024] = { 0 };
	PacketDecodeDataT *decoded      = NULL;
	int16_t            timeout      = 0;

	(void)data;

	// Ghost all buttons.
	widgetEnableSet(W(_btnConnect), 0);
	widgetEnableSet(W(_btnSettings), 0);
	widgetEnableSet(W(_btnQuit), 0);

	// Hide welcome banner, show init.
	widgetVisibleSet(W(_picLogo), 0);
	widgetVisibleSet(W(_picInit), 1);
	taskYield();

	// Open COM port.
	r = comOpen(__configData.serialCom - 1, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
	if (r != SER_SUCCESS) {
		msgBoxOne("COM Problem", MSGBOX_ICON_ERROR, "Unable to open COM port!\nPlease check settings.", "Okay", btnMsgBox);
		return;
	}
	// Send a CR to clear anything in the modem.
	snprintf(buffer, 1023, "%c", 13);
	comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
	// Wait roughly a second for anything.
	comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "weExpectNothing");
	// Send actual init
	snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
	comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
	// Wait roughly a second for "OK".
	r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "OK");
	if (r <= 0) {
		comClose(__configData.serialCom - 1);
		msgBoxOne("Modem Problem", MSGBOX_ICON_ERROR, "Modem does not support ENET!\nPlease check settings.", "Okay", btnMsgBox);
		return;
	}
	// Flush COM port.
	timerQuarterSecondsWait(4);
	comReceiveBufferFlush(__configData.serialCom - 1);

	// Show dialing, dial service.
	widgetVisibleSet(W(_picDialing), 1);
	taskYield();
	snprintf(buffer, 1023, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
	comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
	// Wait 7 seconds for welcome banner.
	r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4 * 7, "KPMPGSMKII\r");
	if (r <= 0) {
		comClose(__configData.serialCom - 1);
		msgBoxOne("No Connection", MSGBOX_ICON_INFORMATION, "Unable to connect to server!\nPlease check settings or try later.", "Okay", btnMsgBox);
		return;
	}

	// Connected!  Show icon.
	widgetVisibleSet(W(_picConnect), 1);
	taskYield();

	// Start packet handler and negotiate encryption.
	taskCreate(taskNetwork, NULL);
	packetEncryptionSetup(__packetThreadData);
	timeout = 5;
	do {
		if (packetEncryptionReady()) break;
		taskYield();
		if (__timerSecondTick) timeout--;
	} while (!guiHasStopped() && timeout >= 0);
	if (timeout < 0) {
		comClose(__configData.serialCom - 1);
		msgBoxOne("Negotiation Error", MSGBOX_ICON_INFORMATION, "Unable to negotiate encryption settings!", "Okay", btnMsgBox);
		return;
	}

	// Wait for version packet to arrive.
	timeout = 10;
	do {
		decoded = netGetPacket(0);
		if (decoded) {
			if (decoded->packetType == PACKET_TYPE_VERSION) {
				__runtimeData.protocolVersion = *(uint32_t *)decoded->data;
				packetDecodeDataDestroy(&decoded);
				break;
			}
		}
		taskYield();
		if (__timerSecondTick) timeout--;
	} while (!guiHasStopped() && timeout >= 0);
	if (timeout < 0) {
		comClose(__configData.serialCom - 1);
		msgBoxOne("Negotiation Error", MSGBOX_ICON_INFORMATION, "Unable to fetch client settings!", "Okay", btnMsgBox);
		return;
	}

	// Switch to Login window.
	guiDelete(D(_winWelcome));
	taskCreate(taskLogin, NULL);
}


static void btnQuitClick(WidgetT *widget) {
	(void)widget;
	setButtons(0);
	msgBoxTwo("Quit?", MSGBOX_ICON_QUESTION, "Exit to DOS?", "Okay", btnMsgBoxQuit, "Cancel", btnMsgBoxQuit);
}


static void btnSettingsClick(WidgetT *widget) {
	(void)widget;
	setButtons(0);
	taskCreate(taskSettings, settingsFinished);
}


void setButtons(uint8_t enabled) {
	widgetEnableSet(W(_btnConnect), (__configData.serialCom > 0 && strlen(__configData.serverHost) > 2) ? enabled : 0);
	widgetEnableSet(W(_btnSettings), enabled);
	widgetEnableSet(W(_btnQuit), enabled);
}


static void settingsFinished(WidgetT *widget) {
	(void)widget;
	setButtons(1);
}


void taskWelcome(void *data) {

	(void)data;

	// 450x128 logo

	TagItemT uiWelcome[] = {
		T_START,
			T_WINDOW, O(_winWelcome),
				T_TITLE, P("Welcome to KangaWorld!"),
				T_WIDTH, 500, T_HEIGHT, 225,

				T_PICTURE, O(_picLogo),
					T_FILENAME, P("data/logo.png"),
					T_X, 18, T_Y, 18,
				T_PICTURE, T_DONE,

				T_PICTURE, O(_picInit),
					T_FILENAME, P("data/dinit.png"),
					T_X, 18, T_Y, 18,
					T_VISIBLE, T_FALSE,
				T_PICTURE, T_DONE,
				T_PICTURE, O(_picDialing),
					T_FILENAME, P("data/ddialing.png"),
					T_X, 179, T_Y, 18,
					T_VISIBLE, T_FALSE,
				T_PICTURE, T_DONE,
				T_PICTURE, O(_picConnect),
					T_FILENAME, P("data/dconnect.png"),
					T_X, 339, T_Y, 18,
					T_VISIBLE, T_FALSE,
				T_PICTURE, T_DONE,

				T_BUTTON, O(_btnQuit),
					T_TITLE, P("Quit"),
					T_X, 30, T_Y, 157,
					T_CLICK, P(btnQuitClick),
				T_BUTTON, T_DONE,
				T_BUTTON, O(_btnSettings),
					T_TITLE, P("Settings"),
					T_X, 201, T_Y, 157,
					T_CLICK, P(btnSettingsClick),
				T_BUTTON, T_DONE,
				T_BUTTON, O(_btnConnect),
					T_TITLE, P("Connect"),
					T_X, 379, T_Y, 157,
					T_CLICK, P(taskProxy),
					T_USER_DATA, P(taskConnectClick),
					T_ENABLED, (__configData.serialCom > 0 && strlen(__configData.serverHost) > 2) ? T_TRUE : T_FALSE,
				T_BUTTON, T_DONE,

			T_WINDOW, T_DONE,
		T_END
	};

	tagListRun(uiWelcome);
}
