/*
 * 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 "msgbox.h"

#include "font.h"

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


#define WIN_MARGIN_TOP    26
#define WIN_MARGIN_LEFT    7
#define WIN_MARGIN_RIGHT   8
#define WIN_MARGIN_BOTTOM  8

#define BTN_MARGIN_TOP     4
#define BTN_MARGIN_LEFT   14
#define BTN_MARGIN_RIGHT  14
#define BTN_MARGIN_BOTTOM  4

#define MSG_PADDING 10

#define ICN_SIZE    32


static msgBoxCallback  _cbOne     = NULL;
static msgBoxCallback  _cbTwo     = NULL;
static msgBoxCallback  _cbThree   = NULL;

static WindowT        *_winDialog = NULL;
static PictureT       *_picIcon   = NULL;
static LabelT         *_lblText   = NULL;
static ButtonT        *_btnOne    = NULL;
static ButtonT        *_btnTwo    = NULL;
static ButtonT        *_btnThree  = NULL;


//***TODO*** This depends on the cache system which isn't really part of the GUI.
static char *_iconFiles[MSGBOX_ICON_COUNT] = {
	"system:exclamation",
	"system:warning",
	"system:information",
	"system:message",
	"system:question"
};


static void btnMsgBox(WidgetT *widget);


static void btnMsgBox(WidgetT *widget) {
	// Remove us from the display.
	guiDelete(D(_winDialog));
	// Call whoever wanted called.
	if (widget == W(_btnOne)) {
		if (_cbOne) _cbOne(MSGBOX_BUTTON_ONE);
	}
	if (widget == W(_btnTwo)) {
		if (_cbTwo) _cbTwo(MSGBOX_BUTTON_TWO);
	}
	if (widget == W(_btnThree)) {
		if (_cbThree) _cbThree(MSGBOX_BUTTON_THREE);
	}
}


void msgBoxOne(char *title, MsgBoxIconT icon, char *message, char *buttonOne, msgBoxCallback callbackOne) {
	return msgBoxThree(title, icon, message, buttonOne, callbackOne, NULL, NULL, NULL, NULL);
}


void msgBoxThree(char *title, MsgBoxIconT icon, char *message, char *buttonOne, msgBoxCallback callbackOne, char *buttonTwo, msgBoxCallback callbackTwo, char *buttonThree, msgBoxCallback callbackThree) {
	uint16_t  w         = 0;
	uint16_t  h         = 0;
	uint16_t  x         = 0;
	uint16_t  y         = 0;
	uint16_t  t         = 0;
	uint16_t  textH     = 0;
	uint16_t  textW     = 0;
	uint16_t  iconW     = 0;
	uint16_t  newW      = 0;
	uint16_t  cursorH   = 0;
	char     *token     = NULL;
	char     *text      = NULL;

	// Null these for later.
	_btnOne   = NULL;
	_btnTwo   = NULL;
	_btnThree = NULL;

	// Remember callbacks for later.
	_cbOne   = callbackOne;
	_cbTwo   = callbackTwo;
	_cbThree = callbackThree;

	// Calculate size of dialog box window.

	// Initial minimum window width is the left and right margins + font width * (title length + 3).
	w = WIN_MARGIN_LEFT + WIN_MARGIN_RIGHT + (fontWidthGet(_guiFont) * (strlen(title) + 3));

	// Initial minimum window height is the top and bottom margins + font height + button height + (padding * 2).
	h = WIN_MARGIN_TOP + WIN_MARGIN_BOTTOM + fontHeightGet(_guiFont) + (BTN_MARGIN_TOP + BTN_MARGIN_BOTTOM + fontHeightGet(_guiFont)) + (MSG_PADDING * 2);

	// Count lines of text and add up height.  Find widest line.
	text = strdup(message);
	token = strtok(text, "\n");
	while (token) {
		textH += fontHeightGet(_guiFont);
		if (strlen(token) > textW) {
			textW = strlen(token);
		}
		token = strtok(NULL, "\n");
	}
	free(text);
	textW *= fontWidthGet(_guiFont);

	// Initial cursor move and window sizing are based on text height.
	cursorH = textH;

	// Is there an icon?
	if (icon > MSGBOX_ICON_NONE && icon < MSGBOX_ICON_COUNT) {
		// Is the icon taller than the message text?
		if (ICN_SIZE > textH) {
			// Use icon height.
			cursorH = ICN_SIZE;
		}
		iconW = ICN_SIZE + MSG_PADDING;
	}

	// Add icon and/or text height to window.
	h += cursorH;

	// Do we need to make the dialog wider to contain the text and icon?
	newW = WIN_MARGIN_LEFT + WIN_MARGIN_RIGHT + iconW + textW + (MSG_PADDING * 2);  // Only 2 here because iconW includes one.
	if (newW > w) w = newW;

	// Do we need to make the dialog wider to contain the buttons?
	newW = WIN_MARGIN_LEFT + WIN_MARGIN_RIGHT + MSG_PADDING + BTN_MARGIN_LEFT + BTN_MARGIN_RIGHT + (fontWidthGet(_guiFont) * strlen(buttonOne));
	if (buttonTwo) newW += MSG_PADDING + BTN_MARGIN_LEFT + BTN_MARGIN_RIGHT + (fontWidthGet(_guiFont) * strlen(buttonTwo));
	if (buttonThree) newW += MSG_PADDING + BTN_MARGIN_LEFT + BTN_MARGIN_RIGHT + (fontWidthGet(_guiFont) * strlen(buttonThree));
	if (newW > w) w = newW;

	// Draw dialog.

	h -= 5;  // Height is off for some reason.  At least, to me, it doesn't look right.
	_winDialog = windowNew(vbeDisplayWidthGet() / 2 - w / 2, vbeDisplayHeightGet() / 2 - h / 2, w, h, title);
	guiAttach(guiRootGet(), W(_winDialog));

	// Initial x cursor is the (implied window left margin +) padding
	x = MSG_PADDING;

	// Initial y cursor is the (implied window top margin +) padding
	y = MSG_PADDING;

	// Load proper icon, if desired.
	if (icon > MSGBOX_ICON_NONE && icon < MSGBOX_ICON_COUNT) {
		_picIcon = pictureNew(x, y, cacheFilenameGet(_iconFiles[icon - 1]));
		guiAttach(W(_winDialog), W(_picIcon));
	}

	// Draw message text.
	t = y;
	x += iconW;
	text = strdup(message);
	token = strtok(text, "\n");
	while (token) {
		_lblText = labelNew(x, t, token);
		guiAttach(W(_winDialog), W(_lblText));
		t += fontHeightGet(_guiFont);
		token = strtok(NULL, "\n");
	}
	free(text);

	// Move to where buttons belong.
	x = w - (WIN_MARGIN_LEFT + WIN_MARGIN_RIGHT + BTN_MARGIN_LEFT + BTN_MARGIN_RIGHT + (fontWidthGet(_guiFont) * strlen(buttonOne)));
	y += cursorH + MSG_PADDING;

	// We always have at least one button.
	_btnOne = buttonNew(x, y, buttonOne, btnMsgBox);
	guiAttach(W(_winDialog), W(_btnOne));

	// Two buttons?
	if (buttonTwo) {
		x -= (MSG_PADDING + BTN_MARGIN_LEFT + BTN_MARGIN_RIGHT + (fontWidthGet(_guiFont) * strlen(buttonTwo)));
		_btnTwo = buttonNew(x, y, buttonTwo, btnMsgBox);
		guiAttach(W(_winDialog), W(_btnTwo));
	}

	// Three buttons?
	if (buttonThree) {
		x -= (MSG_PADDING + BTN_MARGIN_LEFT + BTN_MARGIN_RIGHT + (fontWidthGet(_guiFont) * strlen(buttonThree)));
		_btnThree = buttonNew(x, y, buttonThree, btnMsgBox);
		guiAttach(W(_winDialog), W(_btnThree));
	}
}


void msgBoxTwo(char *title, MsgBoxIconT icon, char *message, char *buttonOne, msgBoxCallback callbackOne, char *buttonTwo, msgBoxCallback callbackTwo) {
	return msgBoxThree(title, icon, message, buttonOne, callbackOne, buttonTwo, callbackTwo, NULL, NULL);
}
