/* 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 "mm/mm1/views/character_info.h"
#include "mm/mm1/views/combat.h"
#include "mm/mm1/utils/strings.h"
#include "mm/mm1/globals.h"
#include "mm/mm1/sound.h"

namespace MM {
namespace MM1 {
namespace Views {

void CharacterInfo::draw() {
	assert(g_globals->_currCharacter);
	CharacterBase::draw();

	MetaEngine::setKeybindingMode(
		_state == DISPLAY || _state == TRADE_WITH ?
		KeybindingMode::KBMODE_PARTY_MENUS :
		KeybindingMode::KBMODE_MENUS
	);

	switch (_state) {
	case DISPLAY:
		writeString(0, 21, STRING["dialogs.character.legend1"]);
		writeString(0, 22, STRING["dialogs.character.legend2"]);
		writeString(0, 23, STRING["dialogs.character.legend3"]);
		writeString(0, 24, STRING["dialogs.character.legend4"]);
		break;

	case DISCARD:
		writeString(0, 20, STRING["dialogs.character.discard"]);
		escToGoBack(0);
		break;

	case EQUIP:
		writeString(0, 20, STRING["dialogs.character.equip"]);
		escToGoBack(0);
		break;

	case REMOVE:
		writeString(0, 20, STRING["dialogs.character.remove"]);
		escToGoBack(0);
		break;

	case SHARE:
		writeString(8, 20, STRING["dialogs.character.share_all"]);
		drawGemsGoldFood();
		break;

	case TRADE_WITH:
		// Print party
		clearLines(13, 24);
		for (uint i = 0; i < g_globals->_party.size(); ++i) {
			const Character &c = g_globals->_party[i];
			_textPos.x = (i % 2) == 0 ? 1 : 22;
			_textPos.y = 15 + (i / 2);
			writeChar(c._condition ? '*' : ' ');
			writeChar('1' + i);
			writeString(") ");
			writeString(c._name);
		}

		writeString(10, 20, Common::String::format(
			STRING["dialogs.character.trade_with"].c_str(),
			(int)g_globals->_party.size()
		));
		break;

	case TRADE_KIND:
		writeString(6, 20, STRING["dialogs.character.trade_which"]);
		drawGemsGoldFood();
		writeString(20, 23, STRING["dialogs.character.item"]);
		escToGoBack(0);
		break;

	case TRADE_ITEM:
		writeString(10, 20, STRING["dialogs.character.which"]);
		escToGoBack(0);
		break;

	case USE:
		g_globals->_combatEffectCtr = 0;
		g_globals->_nonCombatEffectCtr = 0;
		writeString(7, 20, STRING["dialogs.character.use_what"]);
		escToGoBack(0);
		break;

	default:
		break;
	}
}

void CharacterInfo::timeout() {
	switch (_state) {
	case USE:
		if (g_events->isInCombat()) {
			close();
		} else {
			_state = DISPLAY;
			redraw();
		}
		break;
	default:
		return CharacterBase::timeout();
	}
}

bool CharacterInfo::msgFocus(const FocusMessage &msg) {
	CharacterBase::msgFocus(msg);
	_state = DISPLAY;
	return true;
}

bool CharacterInfo::msgKeypress(const KeypressMessage &msg) {
	switch (_state) {
	case DISPLAY:
		switch (msg.keycode) {
		case Common::KEYCODE_c:
			send("CastSpell", GameMessage("SPELL", 0));
			break;
		case Common::KEYCODE_d:
			if (!g_globals->_currCharacter->_backpack.empty())
				_state = DISCARD;
			redraw();
			break;
		case Common::KEYCODE_e:
			if (!g_globals->_currCharacter->_backpack.empty())
				_state = EQUIP;
			redraw();
			break;
		case Common::KEYCODE_g:
			g_globals->_currCharacter->gatherGold();
			redraw();
			break;
		case Common::KEYCODE_q:
			replaceView("QuickRef");
			break;
		case Common::KEYCODE_r:
			if (!g_globals->_currCharacter->_equipped.empty())
				_state = REMOVE;
			redraw();
			break;
		case Common::KEYCODE_s:
			_state = SHARE;
			redraw();
			break;
		case Common::KEYCODE_t:
			_state = TRADE_WITH;
			redraw();
			break;
		case Common::KEYCODE_u:
			_state = USE;
			redraw();
			break;
		default:
			break;
		 }
		break;

	case DISCARD:
		if (msg.keycode >= Common::KEYCODE_a &&
			msg.keycode <= Common::KEYCODE_f)
			discardItem(msg.keycode - Common::KEYCODE_a);
		redraw();
		break;

	case EQUIP:
		if (msg.keycode >= Common::KEYCODE_a &&
				msg.keycode <= Common::KEYCODE_f)
			equipItem(msg.keycode - Common::KEYCODE_a);
		redraw();
		break;

	case REMOVE:
		if (msg.keycode >= Common::KEYCODE_1 &&
			msg.keycode <= Common::KEYCODE_6)
			removeItem(msg.keycode - Common::KEYCODE_1);
		redraw();
		break;

	case SHARE:
		if (msg.keycode >= Common::KEYCODE_1 &&
			msg.keycode <= Common::KEYCODE_3) {
			Party::share((TransferKind)(msg.keycode - Common::KEYCODE_0));
			_state = DISPLAY;
			redraw();
			break;
		}
		break;

	case TRADE_KIND:
		if (msg.keycode >= Common::KEYCODE_1 &&
				msg.keycode <= Common::KEYCODE_3) {
			_tradeKind = (TransferKind)(msg.keycode - Common::KEYCODE_0);
			tradeHowMuch();

		} else if (msg.keycode == Common::KEYCODE_4) {
			if (g_globals->_party[_tradeWith]._backpack.full()) {
				writeString(14, 21, STRING["dialogs.character.full"]);
				Sound::sound(SOUND_2);
				_state = DISPLAY;
				delaySeconds(3);
			} else {
				_state = TRADE_ITEM;
				redraw();
			}
		}
		break;

	case TRADE_ITEM:
		if (msg.keycode >= Common::KEYCODE_a &&
				msg.keycode <= Common::KEYCODE_f) {
			switch (g_globals->_currCharacter->trade(_tradeWith,
				msg.keycode - Common::KEYCODE_a)) {
			case Character::TRADE_FULL:
				writeString(14, 21, STRING["dialogs.character.full"]);
				_state = DISPLAY;
				delaySeconds(3);
				break;
			case Character::TRADE_SUCCESS:
				_state = DISPLAY;
				redraw();
				break;
			default:
				// Do nothing, no item at selected index
				break;
			}
		}
		break;

	case USE: {
		Character &c = *g_globals->_currCharacter;
		Inventory *inv;
		Inventory::Entry *invEntry;
		if (msg.keycode >= Common::KEYCODE_1 && msg.keycode <= Common::KEYCODE_6 &&
			(msg.keycode - Common::KEYCODE_1) < (int)c._equipped.size()) {
			inv = &c._equipped;
			invEntry = &c._equipped[msg.keycode - Common::KEYCODE_1];
		} else if (msg.keycode >= Common::KEYCODE_a && msg.keycode <= Common::KEYCODE_f &&
				(msg.keycode - Common::KEYCODE_a) < (int)c._backpack.size()) {
			inv = &c._backpack;
			invEntry = &c._backpack[msg.keycode - Common::KEYCODE_a];
		} else {
			break;
		}

		if (g_events->isInCombat())
			combatUseItem(*inv, *invEntry, msg.keycode >= Common::KEYCODE_a);
		else
			nonCombatUseItem(*inv, *invEntry, msg.keycode >= Common::KEYCODE_a);
		break;
	}
	default:
		break;
	}

	return true;
}

bool CharacterInfo::msgAction(const ActionMessage &msg) {
	switch (msg._action) {
	case KEYBIND_ESCAPE:
		if (_state != DISPLAY) {
			redraw();
		} else {
			close();
		}

		_state = DISPLAY;
		return true;
	case KEYBIND_VIEW_PARTY1:
	case KEYBIND_VIEW_PARTY2:
	case KEYBIND_VIEW_PARTY3:
	case KEYBIND_VIEW_PARTY4:
	case KEYBIND_VIEW_PARTY5:
	case KEYBIND_VIEW_PARTY6:
		if (_state == DISPLAY) {
			g_globals->_currCharacter = &g_globals->_party[
				msg._action - KEYBIND_VIEW_PARTY1];
			redraw();
		} else if (_state == TRADE_WITH) {
			_state = TRADE_KIND;
			_tradeWith = msg._action - KEYBIND_VIEW_PARTY1;
			redraw();
		}
		return true;
	default:
		break;
	}

	return false;
}

bool CharacterInfo::msgGame(const GameMessage &msg) {
	if (msg._name == "USE") {
		addView();
		_state = USE;
		redraw();
		return true;
	}

	return false;
}

void CharacterInfo::discardItem(uint index) {
	Inventory &inv = g_globals->_currCharacter->_backpack;
	if (index < inv.size())
		inv.removeAt(index);
	_state = DISPLAY;
}

void CharacterInfo::equipItem(uint index) {
	Common::String errMsg;
	_state = DISPLAY;

	if (!EquipRemove::equipItem(index, _textPos, errMsg)) {
		clearLines(20, 24);
		_textPos.y = 21;
		writeString(errMsg);

		Sound::sound(SOUND_2);
		delaySeconds(3);
	}
}

void CharacterInfo::removeItem(uint index) {
	Common::String errMsg;
	_state = DISPLAY;

	if (!EquipRemove::removeItem(index, _textPos, errMsg)) {
		clearLines(20, 24);
		_textPos.y = 21;
		writeString(errMsg);

		Sound::sound(SOUND_2);
		delaySeconds(3);
	}
}

void CharacterInfo::drawGemsGoldFood() {
	writeString(20, 20, STRING["dialogs.character.gems"]);
	writeString(20, 21, STRING["dialogs.character.gold"]);
	writeString(20, 22, STRING["dialogs.character.food"]);
}

void CharacterInfo::howMuchAborted() {
	_state = TRADE_WITH;
	redraw();
}

void CharacterInfo::howMuchEntered(uint amount) {
	Character &src = *g_globals->_currCharacter;
	Character &dest = g_globals->_party[_tradeWith];

	switch (_tradeKind) {
	case TK_GEMS:
		if (amount > src._gems || ((int)dest._gems + amount) > 0xffff) {
			Sound::sound(SOUND_2);
		} else {
			src._gems -= amount;
			dest._gems += amount;
		}
		break;
	case TK_GOLD:
		if (amount > src._gold || (dest._gold + amount) > 0xffffff) {
			Sound::sound(SOUND_2);
		} else {
			src._gold -= amount;
			dest._gold += amount;
		}
		break;
	case TK_FOOD:
		if (amount > src._food || (dest._food + amount) > 40) {
			Sound::sound(SOUND_2);
		} else {
			src._food -= amount;
			dest._food += amount;
		}
		break;

	default:
		break;
	}

	_state = DISPLAY;
	redraw();
}

void CharacterInfo::abortFunc() {
	CharacterInfo *view = (CharacterInfo *)g_events->focusedView();
	view->howMuchAborted();
}

void CharacterInfo::enterFunc(const Common::String &text) {
	CharacterInfo *view = (CharacterInfo *)g_events->focusedView();
	view->howMuchEntered(atoi(text.c_str()));
}

void CharacterInfo::tradeHowMuch() {
	clearLines(20, 24);
	escToGoBack(0);
	writeString(10, 20, STRING["dialogs.character.how_much"]);

	_textEntry.display(20, 20, 5, true, abortFunc, enterFunc);
}

void CharacterInfo::combatUseItem(Inventory &inv, Inventory::Entry &invEntry, bool isEquipped) {
	Common::String msg = Game::UseItem::combatUseItem(inv, invEntry, isEquipped);
	clearLines(20, 24);
	writeString(8, 21, msg);
	delaySeconds(3);
}

void CharacterInfo::nonCombatUseItem(Inventory &inv, Inventory::Entry &invEntry, bool isEquipped) {
	Common::String msg = Game::UseItem::nonCombatUseItem(inv, invEntry, isEquipped);

	clearLines(20, 24);
	writeString(8, 21, msg);
	delaySeconds(3);
}

} // namespace ViewsEnh
} // namespace MM1
} // namespace MM
