/* 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.
 *
 */

/*
* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
* Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
*/

/* Original name: HELPER	The help system unit. */

#include "avalanche/avalanche.h"
#include "avalanche/help.h"

#include "common/scummsys.h"

namespace Avalanche {

Help::Help(AvalancheEngine *vm) {
	_vm = vm;

	for (int i = 0; i < 10; i++) {
		_buttons[i]._trigger = Common::KEYCODE_INVALID;
		_buttons[i]._whither = 0;
	}
	_highlightWas = 0;
	_buttonNum = 0;
	_holdLeft = false;
}

/**
 * Loads and draws the chosen page of the help.
 * @remarks Originally called 'getme'
 */
void Help::switchPage(byte which) {
	// Help icons are 80x20.

	_highlightWas = 177; // Forget where the highlight was.

	Common::File file;

	if (!file.open("help.avd"))
		error("AVALANCHE: Help: File not found: help.avd");

	file.seek(which * 2);
	uint16 offset = file.readUint16LE();
	file.seek(offset);

	Common::String title = getLine(file);

	_vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 640, 200), kColorBlue);
	_vm->_graphics->drawFilledRectangle(Common::Rect(8, 40, 450, 200), kColorWhite);

	byte index = file.readByte();
	_vm->_graphics->helpDrawButton(-177, index);

	// Plot the title:
	_vm->_graphics->drawNormalText(title, _vm->_font, 8, 629 - 8 * title.size(), 26, kColorBlack);
	_vm->_graphics->drawNormalText(title, _vm->_font, 8, 630 - 8 * title.size(), 25, kColorCyan);

	_vm->_graphics->drawBigText("help!", _vm->_font, 8, 549, 1, kColorBlack);
	_vm->_graphics->drawBigText("help!", _vm->_font, 8, 550, 0, kColorCyan);

	byte y = 0;
	do {
		Common::String line = getLine(file);
		if (!line.empty()) {
			if (line.compareTo(Common::String('!')) == 0)  // End of the help text is signalled with a '!'.
				break;
			if (line[0] == '\\') {
				line.deleteChar(0);
				_vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorRed);
			}
			else
				_vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorBlack);
		}
		y++;
	} while (true);

	// We are now at the end of the text. Next we must read the icons:
	y = 0;
	_buttonNum = 0;
	while (!file.eos()) {
		int trigger = file.readByte();

		if (trigger == 177)
			break;
		switch (trigger) {
		case 254: // Escape
			trigger = 27;
			break;
		case 214: // PageUp
			trigger = 280;
			break;
		case 216: // PageDown
			trigger = 281;
			break;
		default: // A - Z
			// The characters are stored in the file in uppercase, but we need the lowercase versions for KeyCode:
			trigger = tolower(trigger);
			break;
		}

		_buttons[y]._trigger = Common::KeyCode(trigger);
		index = file.readByte();
		if (_buttons[y]._trigger != Common::KEYCODE_INVALID)
			_vm->_graphics->helpDrawButton(13 + (y + 1) * 27, index);
		_buttons[y]._whither = file.readByte(); // This is the position to jump to.

		Common::String text = "";
		switch (_buttons[y]._trigger) {
		case Common::KEYCODE_ESCAPE:
			text = Common::String("Esc");
			break;
		case Common::KEYCODE_PAGEUP:
			text = Common::String(24);
			break;
		case Common::KEYCODE_PAGEDOWN:
			text = Common::String(25);
			break;
		default:
			text = Common::String(toupper(_buttons[y]._trigger));
			break;
		}

		_vm->_graphics->drawBigText(text, _vm->_font, 8, 589 - (text.size() * 8), 18 + (y + 1) * 27, kColorBlack);
		_vm->_graphics->drawBigText(text, _vm->_font, 8, 590 - (text.size() * 8), 17 + (y + 1) * 27, kColorCyan);

		y++;
		_buttonNum++;
	}

	_vm->_graphics->refreshScreen();

	file.close();
}

Common::String Help::getLine(Common::File &file) {
	Common::String line;
	byte length = file.readByte();
	for (int i = 0; i < length; i++) {
		char c = file.readByte();
		line += (c ^ 177);
	}
	return line;
}

bool Help::handleMouse(const Common::Event &event) {
	Common::Point mousePos;
	mousePos.x = event.mouse.x;
	mousePos.y = event.mouse.y / 2;

	int index = -1;

	if (event.type == Common::EVENT_LBUTTONUP) { // Clicked *somewhere*...
		_holdLeft = false;

		if ((mousePos.x < 470) || (mousePos.x > 550) || (((mousePos.y - 13) % 27) > 20))
			index = -1;
		else // Clicked on a button.
			index = ((mousePos.y - 13) / 27) - 1;
	} else { // LBUTTONDOWN or MOUSEMOVE
		int highlightIs = 0;

		// Decide which button we are hovering the cursor over:
		if ((mousePos.x > 470) && (mousePos.x <= 550) && (((mousePos.y - 13) % 27) <= 20)) { // No click, so highlight.
			highlightIs = (mousePos.y - 13) / 27 - 1;
			if ((highlightIs < 0) || (5 < highlightIs))
				highlightIs = 177; // In case of silly values.
		} else
			highlightIs = 177;

		Color highlightColor = kColorLightblue;
		// If we clicked on a button or we are holding down the button, we have to highlight it with cyan:
		if (((highlightIs != 177) && ((event.type == Common::EVENT_LBUTTONDOWN)) || _holdLeft)) {
			_holdLeft = true;
			highlightColor = kColorLightcyan;
		}

		// Erase the previous highlight only if it's needed:
		if (_highlightWas != highlightIs) 
			_vm->_graphics->helpDrawHighlight(_highlightWas, kColorBlue);
			
		// Highligt the current one with the proper color:
		if (_buttons[highlightIs]._trigger != Common::KEYCODE_INVALID) {
			_highlightWas = highlightIs;
			_vm->_graphics->helpDrawHighlight(highlightIs, highlightColor);
		}
	}

	if ((index >= 0) && (_buttons[index]._trigger != Common::KEYCODE_INVALID)) {
		if (_buttons[index]._trigger == Common::KEYCODE_ESCAPE)
			return true;
		else {
			_vm->fadeOut();
			switchPage(_buttons[index]._whither);
			_vm->fadeIn();
			return false;
		}
	}

	return false;
}

bool Help::handleKeyboard(const Common::Event &event) {
	if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
		return true;

	for (int i = 0; i < _buttonNum; i++) {
		if (_buttons[i]._trigger == event.kbd.keycode) {
			_vm->fadeOut();
			switchPage(_buttons[i]._whither);
			_vm->fadeIn();
			return false;
		}
	}

	return false;
}

/**
 * @remarks Originally called 'boot_help'
 */
void Help::run() {
	_vm->_graphics->saveScreen();
	_vm->fadeOut();
	switchPage(0);
	_vm->fadeIn();

	_vm->_graphics->loadMouse(kCurHelp);

	// Originally it was the body of 'continue_help':
	bool close = false;
	while (!_vm->shouldQuit() && !close) {
		Common::Event event;
		_vm->getEvent(event);
		if (event.type == Common::EVENT_KEYDOWN)
			close = handleKeyboard(event);
		else if ((event.type == Common::EVENT_LBUTTONDOWN) || (event.type == Common::EVENT_LBUTTONUP) || (event.type == Common::EVENT_MOUSEMOVE))
			close = handleMouse(event);

		_vm->_graphics->refreshScreen();
	}
	// End of 'continue_help'.

	_vm->fadeOut();
	_vm->_graphics->restoreScreen();
	_vm->_graphics->removeBackup();
	_vm->fadeIn();
}

} // End of namespace Avalanche