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

#include "agi/agi.h"
#include "agi/graphics.h"
#include "agi/inv.h"
#include "agi/text.h"
#include "agi/keyboard.h"
#include "agi/systemui.h"

namespace Agi {

InventoryMgr::InventoryMgr(AgiEngine *agi, GfxMgr *gfx, TextMgr *text, SystemUI *systemUI) {
	_vm = agi;
	_gfx = gfx;
	_text = text;
	_systemUI = systemUI;

	_activeItemNr = -1;
}

InventoryMgr::~InventoryMgr() {
}

void InventoryMgr::getPlayerInventory() {
	AgiGame game = _vm->_game;
	int16 selectedInventoryItem = _vm->getVar(VM_VAR_SELECTED_INVENTORY_ITEM);
	uint16 objectNr = 0;
	int16 curRow = 2; // starting at position 2,1
	int16 curColumn = 1;

	_array.clear();
	_activeItemNr = 0;

	for (objectNr = 0; objectNr < game.numObjects; objectNr++) {
		if (_vm->objectGetLocation(objectNr) == EGO_OWNED) {
			// item is in the possession of ego, so add it to our internal list
			if (objectNr == selectedInventoryItem) {
				// it's the currently selected inventory item, remember that
				_activeItemNr = _array.size();
			}

			InventoryEntry inventoryEntry;

			inventoryEntry.objectNr = objectNr;
			inventoryEntry.name = _vm->objectName(objectNr);
			inventoryEntry.row = curRow;
			inventoryEntry.column = curColumn;
			if (inventoryEntry.column > 1) {
				// right side, adjust column accordingly
				inventoryEntry.column -= strlen(inventoryEntry.name);
			}
			_array.push_back(inventoryEntry);

			// go to next position
			if (curColumn == 1) {
				// current position is left side, go to right side
				curColumn = 39;
			} else {
				// current position is right side, so go to left side again and new row
				curColumn = 1;
				curRow++;
			}
		}
	}

	if (_array.size() == 0) {
		// empty inventory
		InventoryEntry inventoryEntry;

		inventoryEntry.objectNr = 0;
		inventoryEntry.name = _systemUI->getInventoryTextNothing();
		inventoryEntry.row = 2;
		inventoryEntry.column = 19 - (strlen(inventoryEntry.name) / 2);
		_array.push_back(inventoryEntry);
	}
}

void InventoryMgr::drawAll() {
	int16 inventoryCount = _array.size();
	int16 inventoryNr = 0;

	_text->charPos_Set(0, 11);
	_text->displayText(_systemUI->getInventoryTextYouAreCarrying());

	for (inventoryNr = 0; inventoryNr < inventoryCount; inventoryNr++) {
		drawItem(inventoryNr);
	}
}

void InventoryMgr::drawItem(int16 itemNr) {
	if (itemNr == _activeItemNr) {
		_text->charAttrib_Set(15, 0);
	} else {
		_text->charAttrib_Set(0, 15);
	}

	_text->charPos_Set(_array[itemNr].row, _array[itemNr].column);
	// original interpreter used printf here
	// this doesn't really make sense, because for length calculation it's using strlen without printf
	// which means right-aligned inventory items on the right side would not be displayed properly
	// in case printf-formatting was actually used
	// I have to assume that no game uses this, because behavior in original interpreter would have been buggy.
	_text->displayText(_array[itemNr].name);
}

void InventoryMgr::show() {
	bool selectItems = false;

	// figure out current inventory of the player
	getPlayerInventory();

	if (_vm->getFlag(VM_FLAG_STATUS_SELECTS_ITEMS)) {
		selectItems = true;
	} else {
		_activeItemNr = -1; // so that none is shown as active
	}

	drawAll();

	_text->charAttrib_Set(0, 15);
	if (selectItems) {
		_text->charPos_Set(24, 2);
		_text->displayText(_systemUI->getInventoryTextSelectItems());
	} else {
		_text->charPos_Set(24, 4);
		_text->displayText(_systemUI->getInventoryTextReturnToGame());
	}

	if (selectItems) {
		_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_INVENTORY);

		do {
			_vm->processAGIEvents();
		} while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));

		if (_activeItemNr >= 0) {
			// pass selected object number
			_vm->setVar(VM_VAR_SELECTED_INVENTORY_ITEM, _array[_activeItemNr].objectNr);
		} else {
			// nothing was selected
			_vm->setVar(VM_VAR_SELECTED_INVENTORY_ITEM, 0xff);
		}

	} else {
		// no selection is supposed to be possible, just wait for key and exit
		_vm->waitAnyKey();
	}
}

void InventoryMgr::keyPress(uint16 newKey) {
	switch (newKey) {
	case AGI_KEY_ENTER: {
		_vm->cycleInnerLoopInactive(); // exit show-loop
		break;
	}

	case AGI_KEY_ESCAPE: {
		_vm->cycleInnerLoopInactive(); // exit show-loop
		_activeItemNr = -1; // no item selected
		break;
	}

	case AGI_KEY_UP:
		changeActiveItem(-2);
		break;
	case AGI_KEY_DOWN:
		changeActiveItem(+2);
		break;
	case AGI_KEY_LEFT:
		changeActiveItem(-1);
		break;
	case AGI_KEY_RIGHT:
		changeActiveItem(+1);
		break;

	default:
		break;
	}
}

void InventoryMgr::changeActiveItem(int16 direction) {
	int16 orgItemNr = _activeItemNr;

	_activeItemNr += direction;

	if ((_activeItemNr >= 0) && (_activeItemNr < (int16)_array.size())) {
		// within bounds
		drawItem(orgItemNr);
		drawItem(_activeItemNr);
	} else {
		// out of bounds, revert change
		_activeItemNr = orgItemNr;
	}
}

} // End of namespace Agi