/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *
 */

#include "m4/mads_menus.h"
#include "m4/m4.h"

namespace M4 {

#define REX_MENUSCREEN 990
#define PHANTOM_MENUSCREEN 920
#define DRAGON_MENUSCREEN 922

#define DRAGON_MENU_BUTTON_W = 45
#define DRAGON_MENU_BUTTON_H = 11

RexMainMenuView::RexMainMenuView(MadsM4Engine *vm):
		View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())) {

	_screenType = VIEWID_MAINMENU;
	_screenFlags.get = SCREVENT_ALL;

	_delayTimeout = 0;
	_menuItem = NULL;
	_menuItemIndex = 0;
	_frameIndex = 0;
	_highlightedIndex = -1;
	_skipFlag = false;

	// Load the background for the Rex Nebular game
	_bgSurface = new M4Surface();
	_bgSurface->loadBackground(REX_MENUSCREEN, &_bgPalData);
	_vm->_palette->addRange(_bgPalData);
	_bgSurface->translate(_bgPalData);

	int row = (height() - MADS_SURFACE_HEIGHT) / 2;
	_bgSurface->copyTo(this, 0, row);

	// Add in the bounding lines for the background
	setColor(2);
	hLine(0, width() - 1, row - 1);
	hLine(0, width() - 1, height() - row + 1);

	// Set up the menu item pos list
	_menuItemPosList[0] = Common::Point(12, 68);
	_menuItemPosList[1] = Common::Point(12, 87);
	_menuItemPosList[2] = Common::Point(12, 107);
	_menuItemPosList[3] = Common::Point(184, 75);
	_menuItemPosList[4] = Common::Point(245, 75);
	_menuItemPosList[5] = Common::Point(184, 99);
}

RexMainMenuView::~RexMainMenuView() {
	delete _menuItem;

	_vm->_palette->deleteRange(_bgPalData);

	delete _bgPalData;
	delete _bgSurface;

	for (uint i = 0; i < _itemPalData.size(); ++i) {
		_vm->_palette->deleteRange(_itemPalData[i]);
		delete _itemPalData[i];
	}
}

bool RexMainMenuView::onEvent(M4EventType eventType, int32 param, int x, int y, bool &captureEvents) {
	// Handle keypresses - these can be done at any time, even when the menu items are being drawn
	if (eventType == KEVENT_KEY) {
		switch (param) {
		case Common::KEYCODE_ESCAPE:
		case Common::KEYCODE_F6:
			handleAction(EXIT);
			break;

		case Common::KEYCODE_F1:
			handleAction(START_GAME);
			break;

		case Common::KEYCODE_F2:
			handleAction(RESUME_GAME);
			break;

		case Common::KEYCODE_F3:
			handleAction(SHOW_INTRO);
			break;

		case Common::KEYCODE_F4:
			handleAction(CREDITS);
			break;

		case Common::KEYCODE_F5:
			handleAction(QUOTES);
			break;

		case Common::KEYCODE_s:
			// Goodness knows why, but Rex has a key to restart the menuitem animations

			// Delete the current menu items
			delete _menuItem;

			_vm->_palette->deleteRange(_bgPalData);
			delete _bgPalData;
			for (uint i = 0; i < _itemPalData.size(); ++i) {
				_vm->_palette->deleteRange(_itemPalData[i]);
				delete _itemPalData[i];
			}
			_itemPalData.clear();

			// Reload the background surface, and restart the animation
			_bgSurface->loadBackground(REX_MENUSCREEN, &_bgPalData);
			_vm->_palette->addRange(_bgPalData);
			_bgSurface->translate(_bgPalData);

			_menuItemIndex = 0;
			_skipFlag = false;
			_menuItem = NULL;
			_vm->_mouse->cursorOff();
			break;

		default:
			// Any other key skips the menu animation
			_skipFlag = true;
			return false;
		}

		return true;
	}

	int row = (height() - MADS_SURFACE_HEIGHT) / 2;
	int menuIndex;

	switch (eventType) {
	case MEVENT_LEFT_CLICK:
	case MEVENT_LEFT_DRAG:
		if (_vm->_mouse->getCursorOn()) {
			menuIndex = getHighlightedItem(x, y);
			if (menuIndex != _highlightedIndex) {
				_bgSurface->copyTo(this, 0, row);

				_highlightedIndex = menuIndex;
				if (_highlightedIndex != -1) {
					M4Sprite *spr = _menuItem->getFrame(_highlightedIndex);
					const Common::Point &pt = _menuItemPosList[_highlightedIndex];
					spr->copyTo(this, pt.x, row + pt.y, 0);
				}
			}
		} else {
			// Skip the menu animation
			_skipFlag = true;
		}
		return true;

	case MEVENT_LEFT_RELEASE:
		if (_highlightedIndex != -1)
			handleAction((MadsGameAction) _highlightedIndex);
		return true;

	default:
		break;
	}

	return false;
}

void RexMainMenuView::updateState() {
	char resName[20];
	Common::SeekableReadStream *data;
	int row = (height() - MADS_SURFACE_HEIGHT) / 2;
	int itemSize;

	uint32 currTime = g_system->getMillis();
	if (currTime < _delayTimeout)
		return;
	_delayTimeout = currTime + MADS_MENU_ANIM_DELAY;

	// Rex Nebular handling to cycle through the animated display of the menu items
	if (_menuItemIndex == 7)
		return;

	// If the user has chosen to skip the menu animation, show the menu immediately
	if (_skipFlag && !_vm->_mouse->getCursorOn()) {
		// Clear any pending animation
		_bgSurface->copyTo(this, 0, row);
		// Quickly loop through all the menuitems to display each's final frame
		while (_menuItemIndex < 7) {

			if (_menuItem) {
				// Draw the final frame of the menuitem
				M4Sprite *spr = _menuItem->getFrame(0);
				itemSize = _menuItem->getFrame(0)->height();
				spr->copyTo(this, _menuItemPosList[_menuItemIndex - 1].x,
					_menuItemPosList[_menuItemIndex - 1].y + row + (itemSize / 2) - (spr->height() / 2), 0);

				delete _menuItem;
				copyTo(_bgSurface, Common::Rect(0, row, width(), row + MADS_SURFACE_HEIGHT), 0, 0);
			}

			// Get the next sprite set
			sprintf(resName, "RM%dA%d.SS", REX_MENUSCREEN, ++_menuItemIndex);
			data = _vm->res()->get(resName);
			_menuItem = new SpriteAsset(_vm, data, data->size(), resName);
			_vm->res()->toss(resName);

			// Slot it into available palette space
			RGBList *palData = _menuItem->getRgbList();
			_vm->_palette->addRange(palData);
			_menuItem->translate(palData, true);
			_itemPalData.push_back(palData);
		}

		_vm->_mouse->cursorOn();
		return;
	}

	if ((_menuItemIndex == 0) || (_frameIndex == 0)) {
		// Get the next menu item
		if (_menuItem) {
			delete _menuItem;

			// Copy over the current display surface area to the background, so the final frame
			// of the previous menuitem should be kept on the screen
			copyTo(_bgSurface, Common::Rect(0, row, width(), row + MADS_SURFACE_HEIGHT), 0, 0);
		}

		// Get the next menuitem resource
		sprintf(resName, "RM%dA%d.SS", REX_MENUSCREEN, ++_menuItemIndex);
		data = _vm->res()->get(resName);
		_menuItem = new SpriteAsset(_vm, data, data->size(), resName);
		_vm->res()->toss(resName);

		// Slot it into available palette space
		RGBList *palData = _menuItem->getRgbList();
		_vm->_palette->addRange(palData);
		_menuItem->translate(palData, true);
		_itemPalData.push_back(palData);

		_frameIndex = _menuItem->getCount() - 1;

		// If the final resource is now loaded, which contains the highlighted versions of
		// each menuitem, then the startup animation is complete
		if (_menuItemIndex == 7) {
			_vm->_mouse->cursorOn();
			return;
		}
	} else {
		--_frameIndex;
	}

	// Move to the next menuitem frame

	itemSize = _menuItem->getFrame(0)->height();

	_bgSurface->copyTo(this, 0, row);
	M4Sprite *spr = _menuItem->getFrame(_frameIndex);
	spr->copyTo(this, _menuItemPosList[_menuItemIndex - 1].x, _menuItemPosList[_menuItemIndex - 1].y +
		row + (itemSize / 2) - (spr->height() / 2), 0);
}

int RexMainMenuView::getHighlightedItem(int x, int y) {
	y -= (height() - MADS_SURFACE_HEIGHT) / 2;

	for (int index = 0; index < 6; ++index) {
		const Common::Point &pt = _menuItemPosList[index];
		M4Sprite *spr = _menuItem->getFrame(index);

		if ((x >= pt.x) && (y >= pt.y) && (x < (pt.x + spr->width())) && (y < (pt.y + spr->height())))
			return index;
	}

	return -1;
}

void RexMainMenuView::handleAction(MadsGameAction action) {
	MadsEngine *vm = (MadsEngine *)_vm;
	vm->_mouse->cursorOff();
	vm->_viewManager->deleteView(this);

	switch (action) {
	case START_GAME:
	case RESUME_GAME:
		// Load a sample starting scene - note that, currently, calling loadScene automatically
		// removes this menu screen from being displayed
		vm->_mouse->cursorOn();
		vm->startScene(101);
		return;

	case SHOW_INTRO:
		vm->_viewManager->showAnimView("@rexopen");
		break;

	case CREDITS:
		vm->_viewManager->showTextView("credits");
		return;

	case QUOTES:
		vm->_viewManager->showTextView("quotes");
		return;

	case EXIT:
		{
			// When the Exit action is done from the menu, show one of two possible advertisements

			// Activate the scene display with the specified scene
			bool altAdvert = vm->_random->getRandomNumber(1000) >= 500;
			vm->startScene(altAdvert ? 995 : 996);
			vm->_viewManager->addView(vm->_scene);

			vm->_viewManager->refreshAll();
			vm->delay(10000);

			vm->_events->quitFlag = true;
			return;
		}
		break;
	default:
		break;
	}
}

//--------------------------------------------------------------------------

MadsMainMenuView::MadsMainMenuView(MadsM4Engine *vm):
		View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())) {

}

bool MadsMainMenuView::onEvent(M4EventType eventType, int32 param, int x, int y, bool &captureEvents) {
	return false;
}

void MadsMainMenuView::updateState() {
	// TODO: Implement me
}

//--------------------------------------------------------------------------

DragonMainMenuView::DragonMainMenuView(MadsM4Engine *vm):
		View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())) {

	_screenType = VIEWID_MAINMENU;
	_screenFlags.get = SCREVENT_ALL;

	_delayTimeout = 0;
	_menuItem = NULL;
	_menuItemIndex = 0;
	_frameIndex = 0;
	_highlightedIndex = -1;
	_skipFlag = false;

	// Load the background for the Dragonsphere game
	this->loadBackground(942, &_bgPalData);
	_vm->_palette->addRange(_bgPalData);
	this->translate(_bgPalData);

	// Set up the menu item pos list
	_menuItemPosList[0] = Common::Point(46, 187);
	_menuItemPosList[1] = Common::Point(92, 187);
	_menuItemPosList[2] = Common::Point(138, 187);
	_menuItemPosList[3] = Common::Point(184, 187);
	_menuItemPosList[4] = Common::Point(230, 187);
	_menuItemPosList[5] = Common::Point(276, 187);
}

DragonMainMenuView::~DragonMainMenuView() {
	//if (_menuItem)
	//	delete _menuItem;

	_vm->_palette->deleteRange(_bgPalData);

	delete _bgPalData;

	for (uint i = 0; i < _itemPalData.size(); ++i) {
		_vm->_palette->deleteRange(_itemPalData[i]);
		delete _itemPalData[i];
	}
}

bool DragonMainMenuView::onEvent(M4EventType eventType, int32 param, int x, int y, bool &captureEvents) {
	char resName[20];
	Common::SeekableReadStream *data;

	// Handle keypresses - these can be done at any time, even when the menu items are being drawn
	if (eventType == KEVENT_KEY) {
		switch (param) {
		case Common::KEYCODE_ESCAPE:
		case Common::KEYCODE_F6:
			handleAction(EXIT);
			break;

		case Common::KEYCODE_F1:
			handleAction(START_GAME);
			break;

		case Common::KEYCODE_F2:
			handleAction(RESUME_GAME);
			break;

		case Common::KEYCODE_F3:
			handleAction(SHOW_INTRO);
			break;

		case Common::KEYCODE_F4:
			handleAction(CREDITS);
			break;

		default:
			// Any other key skips the menu animation
			_skipFlag = true;
			return false;
		}

		return true;
	}

	int menuIndex;

	switch (eventType) {
	case MEVENT_LEFT_CLICK:
	case MEVENT_LEFT_DRAG:
		if (_vm->_mouse->getCursorOn()) {
			menuIndex = getHighlightedItem(x, y);
			if (menuIndex != _highlightedIndex) {

				_highlightedIndex = menuIndex;
				if (_highlightedIndex != -1) {
					sprintf(resName, "MAIN%d.SS", menuIndex);
					data = _vm->res()->get(resName);
					_menuItem = new SpriteAsset(_vm, data, data->size(), resName);
					_vm->res()->toss(resName);

					M4Sprite *spr = _menuItem->getFrame(1);
					spr->copyTo(this, spr->xOffset - 25, spr->yOffset - spr->height());
				}
			}
		} else {
			// Skip the menu animation
			_skipFlag = true;
		}
		return true;

	case MEVENT_LEFT_RELEASE:
		if (_highlightedIndex != -1)
			handleAction((MadsGameAction) _highlightedIndex);
		return true;

	default:
		break;
	}

	return false;
}

void DragonMainMenuView::updateState() {
	char resName[20];
	Common::SeekableReadStream *data;
	RGBList *palData;
	M4Sprite *spr;

	if (_menuItemIndex == 6)
		return;

	while (_menuItemIndex < 6) {
		sprintf(resName, "MAIN%d.SS", _menuItemIndex);
		data = _vm->res()->get(resName);
		_menuItem = new SpriteAsset(_vm, data, data->size(), resName);
		_vm->res()->toss(resName);

		// Slot it into available palette space
		palData = _menuItem->getRgbList();
		_vm->_palette->addRange(palData);
		_menuItem->translate(palData, true);
		_itemPalData.push_back(palData);

		spr = _menuItem->getFrame(0);
		spr->copyTo(this, spr->xOffset - 25, spr->yOffset - spr->height());

		if (_menuItemIndex != 5)
			delete _menuItem;
		_menuItemIndex++;
	}

	// Sphere
	sprintf(resName, "RM920X0.SS");
	data = _vm->res()->get(resName);
	_menuItem = new SpriteAsset(_vm, data, data->size(), resName);
	_vm->res()->toss(resName);

	// Slot it into available palette space
	palData = _menuItem->getRgbList();
	_vm->_palette->addRange(palData);
	_menuItem->translate(palData, true);
	_itemPalData.push_back(palData);

	spr = _menuItem->getFrame(0);					// empty sphere
	spr->copyTo(this, spr->xOffset - 75, spr->yOffset - spr->height());
	spr = _menuItem->getFrame(1);					// dragon inside sphere
	spr->copyTo(this, spr->xOffset - 75, spr->yOffset - spr->height());

	// Dragonsphere letters
	sprintf(resName, "RM920X3.SS");
	data = _vm->res()->get(resName);
	_menuItem = new SpriteAsset(_vm, data, data->size(), resName);
	_vm->res()->toss(resName);

	// Slot it into available palette space
	palData = _menuItem->getRgbList();
	_vm->_palette->addRange(palData);
	_menuItem->translate(palData, true);
	_itemPalData.push_back(palData);

	spr = _menuItem->getFrame(1);
	spr->copyTo(this, spr->xOffset - 140, spr->yOffset - spr->height(), (int)spr->getTransparentColor());

	_vm->_mouse->cursorOn();
}

int DragonMainMenuView::getHighlightedItem(int x, int y) {
	y -= (height() - MADS_SURFACE_HEIGHT) / 2;

	for (int index = 0; index < 6; ++index) {
		const Common::Point &pt = _menuItemPosList[index];
		M4Sprite *spr = _menuItem->getFrame(0);

		if ((x >= pt.x - 25) && (y >= pt.y - spr->height()) && (x < (pt.x - 25 + spr->width())) && (y < (pt.y)))  {
			printf("x = %d, y = %d, index = %d\n", x, y, index);
			return index;
		}
	}

	return -1;
}

void DragonMainMenuView::handleAction(MadsGameAction action) {
	MadsM4Engine *vm = _vm;
	vm->_mouse->cursorOff();
	vm->_viewManager->deleteView(this);

	switch (action) {
	case START_GAME:
	case RESUME_GAME:
		// Load a sample starting scene - note that, currently, calling loadScene automatically
		// removes this menu screen from being displayed
		vm->_mouse->cursorOn();
		vm->_viewManager->addView(vm->_scene);
		vm->_scene->loadScene(101);
		return;

	case SHOW_INTRO:
		vm->_viewManager->showAnimView("@dragon");
		break;

	case CREDITS:
		vm->_viewManager->showTextView("credits");
		return;

	case EXIT:
		vm->_events->quitFlag = true;
		return;

	default:
		break;
	}
}


/*--------------------------------------------------------------------------
 * RexDialogView is the base class for the different full-screen dialogs
 * in at least Rex Nebular
 *--------------------------------------------------------------------------
 */

RexDialogView::RexDialogView(): View(_madsVm, Common::Rect(0, 0, _madsVm->_screen->width(), _madsVm->_screen->height())),
		MadsView(this) {
	_screenType = VIEWID_MENU;

	// Initialise class variables
	_priorSceneId = _madsVm->_scene->getCurrentScene();
	_dialogType = DIALOG_NONE;

	// Load necessary quotes
	_madsVm->globals()->loadQuoteRange(1, 48);

	initialiseLines();
	initialiseGraphics();
}

void RexDialogView::initialiseLines() {
	// Set up a list of blank entries for use in the various dialogs
	for (int i = 0; i < DIALOG_LINES_SIZE; ++i) {
		DialogTextEntry rec;
		rec.in_use = false;
		_dialogText.push_back(rec);
	}
	_totalTextEntries = 0;

	// Set up a default sprite slot entry for a full screen refresh
	_spriteSlots.startIndex = 1;
	_spriteSlots[0].spriteType = FULL_SCREEN_REFRESH;
	_spriteSlots[0].seqIndex = -1;
}

void RexDialogView::initialiseGraphics() {
	// Set needed palette entries
	_madsVm->_palette->blockRange(0, 16);
	_madsVm->_palette->setEntry(10, 0, 255, 0);
	_madsVm->_palette->setEntry(11, 0, 180, 0);
	_madsVm->_palette->setEntry(12, 255, 255, 0);
	_madsVm->_palette->setEntry(13, 180, 180, 0);
	_madsVm->_palette->setEntry(14, 255, 255, 180);
	_madsVm->_palette->setEntry(15, 180, 180,  180);

	// Load an appropriate background and menu sprites
	loadBackground();
	loadMenuSprites();

	// Set the current cursor
	_madsVm->_mouse->setCursorNum(CURSOR_ARROW);
}


RexDialogView::~RexDialogView() {
	_madsVm->_palette->deleteRange(_bgPalData);
	delete _bgPalData;
	delete _backgroundSurface;
}

void RexDialogView::loadBackground() {
	int bgIndex = _madsVm->globals()->sceneNumber / 100;
	int screenId = 0;

	switch (bgIndex) {
	case 1:
	case 2:
		screenId = 921;
		break;
	case 3:
	case 4:
		screenId = 922;
		break;
	case 5:
	case 6:
	case 7:
		screenId = 923;
		break;
	case 8:
		screenId = 924;
	case 9:
		screenId = 920;
	default:
		error("Unknown scene number");
	}

	_backgroundSurface = new M4Surface(width(), MADS_SURFACE_HEIGHT);
	_backgroundSurface->loadBackground(screenId, &_bgPalData);
	_vm->_palette->addRange(_bgPalData);
	_backgroundSurface->translate(_bgPalData);
}

void RexDialogView::loadMenuSprites() {
	const char *SPRITES_NAME = "*MENU.SS";

	_spriteSlots.addSprites(SPRITES_NAME);
}


void RexDialogView::updateState() {
}

void RexDialogView::onRefresh(RectList *rects, M4Surface *destSurface) {
	// Draw the framed base area
	fillRect(this->bounds(), _madsVm->_palette->BLACK);
	setColour(2);
	hLine(0, width(), MADS_Y_OFFSET - 2);
	hLine(0, width(), MADS_Y_OFFSET + MADS_SURFACE_HEIGHT + 2);

	// Add in the loaded background vertically centred
	_backgroundSurface->copyTo(this, 0, (height() - MADS_SURFACE_HEIGHT) / 2);

	// Check whether any of the dialog text entries need to be refreshed
	refreshText();

	// Handle the drawing of the various Mads elements
	refresh();

	View::onRefresh(rects, destSurface);
}

/**
 * Handles item selection within dialogs
 */
bool RexDialogView::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
	static bool word_7F28C = false;
	int word_7FED2 = 0;
	int word_8502A = 0;

	// If it's a keypress, handle it immediately
	if (eventType == KEVENT_KEY) {
		switch (param1) {
		case Common::KEYCODE_q | (Common::KBD_CTRL << 24):
		case Common::KEYCODE_q | (Common::KBD_ALT << 24):
			_madsVm->quitGame();
			return true;
		case Common::KEYCODE_RETURN:
			_enterFlag = true;
			_selectedLine = 0;
			break;
		case Common::KEYCODE_ESCAPE:
			_selectedLine = 0;
			break;
		default:
			return false;
		}
	}

	// Mark all the dialog text entries as not being seelcted
	for (uint i = 0; i < _dialogText.size(); ++i)
		_dialogText[i].state = STATE_DESELECTED;

	// Check if the mouse is over a registered screen object
	int idx = _screenObjects.scan(x, y, LAYER_GUI);

	if (word_7F28C) {
		if (y < _screenObjects[2].bounds.top) {
			if (eventType != MEVENT_LEFT_RELEASE)
				_dialogText[1].state = STATE_SELECTED;
			idx = 19;
		}

		if (y > _screenObjects[8].bounds.bottom) {
			if (eventType != MEVENT_LEFT_RELEASE)
				_dialogText[7].state = STATE_SELECTED;
			idx = 20;
		}
	}

	int objIndex = -1;
	if ((idx > 0) && ((eventType == MEVENT_LEFT_HOLD) || (eventType == MEVENT_LEFT_DRAG) ||
					(eventType == MEVENT_LEFT_RELEASE))) {
		objIndex = _screenObjects[idx].index;

		if ((_dialogType == DIALOG_SAVE) || (_dialogType == DIALOG_RESTORE)) {
			if ((objIndex > 7) && (objIndex <= 14))
				_dialogText[objIndex].state = STATE_SELECTED;
		}

		if (word_7FED2)
			word_7F28C = (objIndex > 0) && (objIndex <= 7);

		if (_screenObjects[idx].category == 1)
			_dialogText[objIndex].state = STATE_SELECTED;
	} else {
		idx = -1;
	}

	if (idx == 0)
		idx = -1;

	if (_dialogType == DIALOG_ERROR) {
		if (idx == 1)
			idx = -1;
	}

	if (eventType == MEVENT_LEFT_RELEASE) {
		if (!word_7F28C || (objIndex <= 18))
			_selectedLine = objIndex;

		word_8502A = -1;
	}

	return true;
}

void RexDialogView::setFrame(int frameNumber, int depth) {
	int slotIndex = _spriteSlots.getIndex();
	_spriteSlots[slotIndex].spriteType = FOREGROUND_SPRITE;
	_spriteSlots[slotIndex].seqIndex = 1;
	_spriteSlots[slotIndex].spriteListIndex = 0; //_menuSpritesIndex;
	_spriteSlots[slotIndex].frameNumber = frameNumber;

	M4Sprite *spr = _spriteSlots.getSprite(0).getFrame(frameNumber - 1);
	_spriteSlots[slotIndex].xp = spr->x;
	_spriteSlots[slotIndex].yp = spr->y;
	_spriteSlots[slotIndex].depth = depth;
	_spriteSlots[slotIndex].scale = 100;
}

void RexDialogView::initVars() {
	_word_8502C = -1;
	_selectedLine = -1;
	_lineIndex = 0;
	_enterFlag = false;
	_textLines.clear();
}

void RexDialogView::addLine(const char *msg_p, Font *font, MadsTextAlignment alignment, int left, int top) {
	DialogTextEntry *rec = NULL;

	if (_lineIndex < _totalTextEntries) {
		if (strcmp(msg_p, _dialogText[_lineIndex].text) == 0)  {
			rec = &_dialogText[_lineIndex];
			if (rec->textDisplay_index != 0) {
				MadsTextDisplayEntry &tdEntry = _textDisplay[rec->textDisplay_index];
				if (tdEntry.active) {
					if (_textLines.size() < 20) {
						// Add entry to line list
						_textLines.push_back(tdEntry.msg);
						tdEntry.msg = _textLines[_textLines.size() - 1].c_str();
					}
				}
			}
		}
	} else {
		if (_lineIndex < DIALOG_LINES_SIZE) {
			rec = &_dialogText[_lineIndex];
			_totalTextEntries = _lineIndex + 1;
		}
	}

	// Handling for if a line needs to be added
	if (rec) {
		strcpy(rec->text, msg_p);
		rec->font = font;
		rec->state = STATE_DESELECTED;
		rec->pos.y = top;
		rec->widthAdjust = -1;
		rec->in_use = true;
		rec->textDisplay_index = -1;

		switch (alignment) {
		case ALIGN_CENTER:
			// Center text
			rec->pos.x = (width() - font->getWidth(rec->text)) / 2 + left;
			break;

		case ALIGN_CHAR_CENTER: {
			// Text is center aligned on the '@' character within the string
			char *p = strchr(rec->text, '@');

			if (p) {
				// '@' string handling
				// Get length of string up to the '@' character
				*p = '\0';
				int strWidth = font->getWidth(rec->text, rec->widthAdjust);
				// Remove the character from the string. strcpy isn't used here because it's unsafe for
				// copying within the same string
				while ((*p = *(p + 1)) != '\0') ++p;

				rec->pos.x = (width() / 2) - strWidth;
			} else {
				rec->pos.x = left;
			}
			break;
		}
	
		case RIGHT_ALIGN:
			// Right align (moving left from given passed left)
			rec->pos.x = left - font->getWidth(rec->text);
			break;

		default:
			break;
		}
	}

	++_lineIndex;
}

/**
 * Adds a line consisting of either a single quote, or the combination of two quote Ids
 */
void RexDialogView::addQuote(Font *font, MadsTextAlignment alignment, int left, int top, int id1, int id2) {
	char buffer[80];

	// Copy the first quote string into the buffer
	const char *quoteStr = _madsVm->globals()->getQuote(id1);
	strcpy(buffer, quoteStr);

	// Handle the optional second quote Id
	if (id2 != 0) {
		quoteStr = _madsVm->globals()->getQuote(id2);
		strcat(buffer, " ");
		strcat(buffer, quoteStr);
	}

	// Add in the generated line
	addLine(buffer, font, alignment, left, top);
}

/**
 * Sets any previously created dialog text entries as clickable items
 */
void RexDialogView::setClickableLines() {
	_screenObjects.clear();

	for (int i = 0; i < DIALOG_LINES_SIZE; ++i) {
		if (_dialogText[i].in_use) {
			// Add an entry for the line
			_screenObjects.add(Common::Rect(_dialogText[i].pos.x, _dialogText[i].pos.y, 
				_dialogText[i].pos.x + _dialogText[i].font->getWidth(_dialogText[i].text, _dialogText[i].widthAdjust),
				_dialogText[i].pos.y + _dialogText[i].font->getHeight()), 19, i, 1);
		}
	}

	if ((_madsVm->globals()->dialogType == DIALOG_SAVE) || (_madsVm->globals()->dialogType == DIALOG_RESTORE)) {
		// Extra entries for the scroller areas of the  Save and Restor dialogs
		_screenObjects.add(Common::Rect(293, 26, 312, 75), LAYER_GUI, 50, 2);
		_screenObjects.add(Common::Rect(293, 78, 312, 127), LAYER_GUI, 51, 2);
	}
}

/**
 * Handles creating text display objects for each dialog line initially, and when the selected state
 * of any entry changes
 */
void RexDialogView::refreshText() {
	for (uint i = 0; i < _dialogText.size(); ++i) {
		if (!_dialogText[i].in_use)
			continue;

		// Get the item's colours
		uint colour;
		if (_dialogText[i].state == STATE_DESELECTED)
			colour = 0xB0A;
		else if (_dialogText[i].state == STATE_SELECTED)
			colour = 0xD0C;
		else
			colour = 0xF0E;

		// If there's an associated text display entry, check to see if it's colour needs to change
		if (_dialogText[i].textDisplay_index >= 0) {
			MadsTextDisplayEntry &tdEntry = _textDisplay[_dialogText[i].textDisplay_index];

			if ((tdEntry.colour1 == (colour & 0xff)) && (tdEntry.colour2 == (colour >> 8)))
				// It's still the same, so no further action needed
				continue;

			// Flag the currently assigned text display to be expired, so it can be re-created
			_textDisplay.expire(_dialogText[i].textDisplay_index);
			_dialogText[i].textDisplay_index = -1;
		}

		// Create a new text display entry for the dialog text line
		_dialogText[i].textDisplay_index = _textDisplay.add(_dialogText[i].pos.x, _dialogText[i].pos.y,
			colour, _dialogText[i].widthAdjust, _dialogText[i].text, _dialogText[i].font);
	}
}

/*--------------------------------------------------------------------------
 * RexGameMenuDialog is the main game dialog for the game
 *--------------------------------------------------------------------------
 */

RexGameMenuDialog::RexGameMenuDialog(): RexDialogView() {
	_dialogType = DIALOG_GAME_MENU;
	setFrame(1, 2);
	initVars();

	_vm->_font->setFont(FONT_CONVERSATION_MADS);
	addLines();
	setClickableLines();
}

void RexGameMenuDialog::addLines() {
	// Add the title
	int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 2) * 6) >> 1) - 78);
		
	addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 10);

	// Loop for adding the option lines of the dialog
	top += 6;
	for (int idx = 0; idx < 5; ++idx) {
		top += _vm->_font->current()->getHeight() + 1;
		addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 11 + idx);
	}
}

bool RexGameMenuDialog::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
	// Call the parent event handler to handle line selection
	bool handled = RexDialogView::onEvent(eventType, param1, x, y, captureEvents);

	if (_selectedLine > 0) {
		switch (_selectedLine) {
		case 1:
			// Save Game
			_madsVm->globals()->dialogType = DIALOG_SAVE;
			break;
		case 2:
			// Restore Game
			_madsVm->globals()->dialogType = DIALOG_RESTORE;
			break;
		case 3:
			// Game Play Options
			_madsVm->globals()->dialogType = DIALOG_OPTIONS;
			break;
		case 4:
			// Resume Current Game
			_madsVm->globals()->dialogType = DIALOG_NONE;
			break;
		case 5:
			// Exit From Game
			_madsVm->quitGame();
			break;
		default:
			// TODO: Extra logic for such as resuming scene if necessary
			_madsVm->globals()->dialogType = DIALOG_NONE;
			break;
		}

		// Close this dialog
		_madsVm->_viewManager->deleteView(this);
	}

	return handled;
}

/*--------------------------------------------------------------------------
 * RexOptionsDialog is the game options dialog for Rex Nebular
 *--------------------------------------------------------------------------
 */

RexOptionsDialog::RexOptionsDialog(): RexDialogView() {
	_dialogType = DIALOG_OPTIONS;
	_tempConfig = _madsVm->globals()->_config;

	setFrame(2, 2);
	initVars();

	_vm->_font->setFont(FONT_CONVERSATION_MADS);
	addLines();
	setClickableLines();
}

void RexOptionsDialog::reload() {
	for (int i = 0; i < DIALOG_LINES_SIZE; ++i)
		_dialogText[i].in_use = false;
	_totalTextEntries = 0;
	_textDisplay.clear();
	_screenObjects.clear();

	initVars();

	_vm->_font->setFont(FONT_CONVERSATION_MADS);
	addLines();
	setClickableLines();
}

void RexOptionsDialog::addLines() {
	// Add the title
	int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 1) * 9 + 12) >> 1) - 78);

	addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 16);

	// Music state line
	top += _vm->_font->current()->getHeight() + 1 + 6;
	addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);

	// Sound state line
	top += _vm->_font->current()->getHeight() + 1;
	addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);

	// Interface easy state line
	top += _vm->_font->current()->getHeight() + 1;
	addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);

	// Inventory sppinng state line
	top += _vm->_font->current()->getHeight() + 1;
	addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);

	// Text window state line
	top += _vm->_font->current()->getHeight() + 1;
	addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);

	// Screen fade state line
	top += _vm->_font->current()->getHeight() + 1;
	addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);

	// Storyline mode line
	top += _vm->_font->current()->getHeight() + 1;
	addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);

	// Add Done and Cancel button texts
	top += _vm->_font->current()->getHeight() + 1 + 6;
	addQuote(_vm->_font->current(), ALIGN_CENTER, -54, top, 1, 0);
	addQuote(_vm->_font->current(), ALIGN_CENTER, 54, top, 2, 0);
}

bool RexOptionsDialog::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
	// Call the parent event handler to handle line selection
	bool handled = RexDialogView::onEvent(eventType, param1, x, y, captureEvents);

	if (_selectedLine > 0) {
		switch (_selectedLine) {
		case 0:
			// Enter or Escape
			_selectedLine = _enterFlag ? 8 : 9;
			return true;
		case 1:
			// Music line
			_tempConfig.musicFlag = !_tempConfig.musicFlag;
			break;
		case 2:
			// Sound line
			_tempConfig.soundFlag = !_tempConfig.soundFlag;
			break;
		case 3:
			// Interface line
			_tempConfig.easyMouse = !_tempConfig.easyMouse;
			break;
		case 4:
			// Inventory line
			_tempConfig.invObjectsStill = !_tempConfig.invObjectsStill;
			break;
		case 5:
			// Text window line
			_tempConfig.textWindowStill = !_tempConfig.textWindowStill;
			break;
		case 6:
			// Screen fades line
			if (++_tempConfig.screenFades > 2)
				_tempConfig.screenFades = 0;
			break;
		case 7:
			// Story mode line
			if (_tempConfig.storyMode == 2)
				_tempConfig.storyMode = 1;
			else if (_tempConfig.storyMode == 1)
				_tempConfig.storyMode = 2;
			break;
		case 8:
		case 9:
			// Done and Cancel buttons
			// TODO: Proper re-loading of settings if Cancel button clicked
			_madsVm->globals()->_config = _tempConfig;

			// Closing the dialog, so return to the game menu
			_madsVm->globals()->dialogType = DIALOG_GAME_MENU;
			_madsVm->_viewManager->deleteView(this);
			return true;
		}

		// Update the option selections 
		reload();
	}

	return handled;
}

}