/* 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 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 <http://www.gnu.org/licenses/>.
 *
 */

#include "sherlock/tattoo/widget_verbs.h"
#include "sherlock/tattoo/tattoo_fixed_text.h"
#include "sherlock/tattoo/tattoo_scene.h"
#include "sherlock/tattoo/tattoo_user_interface.h"
#include "sherlock/tattoo/tattoo_people.h"
#include "sherlock/tattoo/tattoo.h"

namespace Sherlock {

namespace Tattoo {

WidgetVerbs::WidgetVerbs(SherlockEngine *vm) : WidgetBase(vm) {
	_selector = _oldSelector = -1;
	_outsideMenu = false;
}

void WidgetVerbs::load(bool objectsOn) {
	Events &events = *_vm->_events;
	TattooPeople &people = *(TattooPeople *)_vm->_people;
	Talk &talk = *_vm->_talk;
	TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
	Common::Point mousePos = events.mousePos();
	bool isWatson = false;

	if (talk._talkToAbort)
		return;

	ui._activeObj = ui._bgFound;
	_outsideMenu = false;
	_verbCommands.clear();
	_selector = _oldSelector = -1;

	// Check if we need to show options for the highlighted object
	if (objectsOn) {
		// Set the verb list accordingly, depending on the target being a
		// person or an object
		if (ui._personFound) {
			TattooPerson &person = people[ui._activeObj - 1000];

			if (!scumm_strnicmp(person._npcName.c_str(), "WATS", 4))
				isWatson = true;


			if (scumm_strnicmp(person._examine.c_str(), "_EXIT", 5))
				_verbCommands.push_back(FIXED(Look));

			_verbCommands.push_back(FIXED(Talk));

			// Add any extra active verbs from the NPC's verb list
			for (int idx = 0; idx < 2; ++idx) {
				if (!person._use[idx]._verb.empty() && !person._use[idx]._verb.hasPrefix(" ") &&
						(person._use[idx]._target.empty() || person._use[idx]._target.hasPrefix(" "))) {
					_verbCommands.push_back(person._use[idx]._verb);
				}
			}
		} else {
			if (!scumm_strnicmp(ui._bgShape->_name.c_str(), "WATS", 4))
				// Looking at Watson
				isWatson = true;

			if (scumm_strnicmp(ui._bgShape->_examine.c_str(), "_EXIT", 5))
				// It's not an exit, so include Look as an option
				_verbCommands.push_back(FIXED(Look));

			if (ui._bgShape->_aType == PERSON)
				_verbCommands.push_back(FIXED(Talk));

			// Add any extra active verbs from the object's verb list
			for (int idx = 0; idx < 6; ++idx) {
				UseType &use = ui._bgShape->_use[idx];
				if (!use._verb.empty() && !use._verb.hasPrefix(" ") && !use._verb.hasPrefix("*") &&
					(use._target.empty() || use._target.hasPrefix("*") || use._target.hasPrefix(" "))) {
					_verbCommands.push_back(use._verb);
				}
			}
		}
	}

	// If clicked on Watson, have Journal as an option
	if (isWatson)
		_verbCommands.push_back(FIXED(Journal));

	// Add the system commands
	_verbCommands.push_back(FIXED(Inventory));
	_verbCommands.push_back(FIXED(Options));

	// Figure out the needed width to show the commands
	int width = 0;
	for (uint idx = 0; idx < _verbCommands.size(); ++idx)
		width = MAX(width, _surface.stringWidth(_verbCommands[idx]));
	width += _surface.widestChar() * 2 + 6;
	int height = (_surface.fontHeight() + 7) * _verbCommands.size() + 3;

	// Set the bounds
	_bounds = Common::Rect(width, height);
	_bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2);

	// Render the window on the internal surface
	render();
}

void WidgetVerbs::render() {
	TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
	ImageFile &images = *ui._interfaceImages;

	// Create the drawing surface
	_surface.create(_bounds.width(), _bounds.height());
	_surface.clear(TRANSPARENCY);

	// Draw basic background
	makeInfoArea();

	// Draw the verb commands and the lines separating them
	for (uint idx = 0; idx < _verbCommands.size(); ++idx) {
		_surface.writeString(_verbCommands[idx], Common::Point((_bounds.width() - _surface.stringWidth(_verbCommands[idx])) / 2,
			(_surface.fontHeight() + 7) * idx + 5), INFO_TOP);

		if (idx < (_verbCommands.size() - 1)) {
			_surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1), _bounds.width() - 4, INFO_TOP);
			_surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 1, _bounds.width() - 4, INFO_MIDDLE);
			_surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 2, _bounds.width() - 4, INFO_BOTTOM);

			_surface.SHtransBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1) - 1));
			_surface.SHtransBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width,
				(_surface.fontHeight() + 7) * (idx + 1) - 1));
		}
	}
}

void WidgetVerbs::handleEvents() {
	Events &events = *_vm->_events;
	FixedText &fixedText = *_vm->_fixedText;
	People &people = *_vm->_people;
	TattooScene &scene = *(TattooScene *)_vm->_scene;
	Talk &talk = *_vm->_talk;
	TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
	Common::Point mousePos = events.mousePos();

	Common::String strLook = fixedText.getText(kFixedText_Look);
	Common::String strTalk = fixedText.getText(kFixedText_Talk);
	Common::String strJournal = fixedText.getText(kFixedText_Journal);

	checkTabbingKeys(_verbCommands.size());

	// Highlight verb display as necessary
	highlightVerbControls();

	// Flag if the user has started pressing the button with the cursor outsie the menu
	if (events._firstPress && !_bounds.contains(mousePos))
		_outsideMenu = true;

	// See if they released the mouse button
	if (events._released || events._rightReleased) {
		// See if they want to close the menu (they clicked outside of the menu)
		if (!_bounds.contains(mousePos)) {
			if (_outsideMenu) {
				if (events._rightReleased) {
					// Change to the item (if any) that was right-clicked on, and re-draw the verb menu
					ui._bgFound = scene.findBgShape(mousePos);
					ui._personFound = ui._bgFound >= 1000;
					ui._bgShape = ui._personFound || ui._bgFound == -1 ? nullptr : &scene._bgShapes[ui._bgFound];

					bool noDesc = false;
					if (ui._personFound) {
						if (people[ui._bgFound - 1000]._description.empty() || people[ui._bgFound - 1000]._description.hasPrefix(" "))
							noDesc = true;
					} else if (ui._bgFound != -1) {
						if (ui._bgShape->_description.empty() || ui._bgShape->_description.hasPrefix(" "))
							noDesc = true;
					} else {
						noDesc = true;
					}

					// Call the Routine to turn on the Commands for this Object
					load(!noDesc);
				} else {
					// Close the window and clear the events
					banishWindow();
					events.clearEvents();

					// Reset the active UI mode
					ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
				}
			}
		} else if (_bounds.contains(mousePos) && _selector != -1) {
			// Mouse is within the menu
			// Erase the menu
			banishWindow();
			events.clearEvents();

			// See if they are activating the Look Command
			if (!_verbCommands[_selector].compareToIgnoreCase(strLook)) {
				ui._bgFound = ui._activeObj;
				if (ui._activeObj >= 1000) {
					ui._personFound = true;
				} else {
					ui._personFound = false;
					ui._bgShape = &scene._bgShapes[ui._activeObj];
				}

				ui.lookAtObject();

			} else if (!_verbCommands[_selector].compareToIgnoreCase(strTalk)) {
				// Talk command is being activated
				talk.initTalk(ui._activeObj);
				ui._activeObj = -1;

			} else if (!_verbCommands[_selector].compareToIgnoreCase(strJournal)) {
				ui.doJournal();

				// See if we're in a Lab Table scene
				ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
			} else if (_selector >= ((int)_verbCommands.size() - 2)) {
				switch (_selector - (int)_verbCommands.size() + 2) {
				case 0:
					// Inventory
					ui.doInventory(2);
					break;

				case 1:
					// Options
					ui.doControls();
					break;

				default:
					ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
					break;
				}
			} else {
				// If they have selected anything else, process it
				people[HOLMES].gotoStand();

				if (ui._activeObj < 1000) {
					for (int idx = 0; idx < 6; ++idx) {
						if (!_verbCommands[_selector].compareToIgnoreCase(scene._bgShapes[ui._activeObj]._use[idx]._verb)) {
							// See if they are Picking this object up
							if (!scene._bgShapes[ui._activeObj]._use[idx]._target.compareToIgnoreCase("*PICKUP"))
								ui.pickUpObject(ui._activeObj);
							else
								ui.checkAction(scene._bgShapes[ui._activeObj]._use[idx], ui._activeObj);
						}
					}
				} else {
					for (int idx = 0; idx < 2; ++idx) {
						if (!_verbCommands[_selector].compareToIgnoreCase(people[ui._activeObj - 1000]._use[idx]._verb))
							ui.checkAction(people[ui._activeObj - 1000]._use[idx], ui._activeObj);
					}
				}

				ui._activeObj = -1;
				if (ui._menuMode != MESSAGE_MODE) {
					// See if we're in a Lab Table Room
					ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
				}
			}
		}
	} else if (ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
		// User closing the menu with the ESC key
		banishWindow();
		ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
	}
}

void WidgetVerbs::highlightVerbControls() {
	Events &events = *_vm->_events;
	Screen &screen = *_vm->_screen;
	Common::Point mousePos = events.mousePos();

	// Get highlighted verb
	_selector = -1;
	Common::Rect bounds = _bounds;
	bounds.grow(-3);
	if (bounds.contains(mousePos))
		_selector = (mousePos.y - bounds.top) / (screen.fontHeight() + 7);

	// See if a new verb is being pointed at
	if (_selector != _oldSelector) {
		// Redraw the verb list
		for (int idx = 0; idx < (int)_verbCommands.size(); ++idx) {
			byte color = (idx == _selector) ? (byte)COMMAND_HIGHLIGHTED : (byte)INFO_TOP;
			_surface.writeString(_verbCommands[idx], Common::Point((_bounds.width() - screen.stringWidth(_verbCommands[idx])) / 2,
				(screen.fontHeight() + 7) * idx + 5), color);
		}

		_oldSelector = _selector;
	}
}

} // End of namespace Tattoo

} // End of namespace Sherlock
