/* 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/m4_views.h"
#include "m4/events.h"
#include "m4/font.h"
#include "m4/globals.h"
#include "m4/m4.h"

namespace M4 {

GUIInventory::GUIInventory(View *owner, M4Engine *vm, const Common::Rect &bounds, int horizCells,
		   int vertCells, int cellWidth, int cellHeight, int tag): GUIRect(owner, bounds, tag) {

    _vm = vm;
	_cellCount.x = horizCells;
	_cellCount.y = vertCells;
	_cellSize.x = cellWidth;
	_cellSize.y = cellHeight;

	// Validate the cell settings
	if ((_cellCount.x * _cellSize.x > _bounds.width()) ||
		(_cellCount.y * _cellSize.y > _bounds.height()))
		error("Cell settings for inventory display exceeded control size");

	_visible = true;
	_scrollPosition = 0;
	_scrollable = false;
	_highlightedIndex = -1;
	_selectedIndex = -1;
}

void GUIInventory::onRefresh() {
	_parent->fillRect(_bounds, _vm->_palette->BLACK);
	//_parent->frameRect(_bounds, _vm->_palette->LIGHT_GRAY);

	if (_visible) {
		//kernel_trigger_dispatch(kernel_trigger_create(TRIG_INV_CLICK));

		_scrollable = false;

		// Get to the starting inventory position for display
		ItemsIterator i = _inventoryItems.begin();
		int index = _scrollPosition;
		while (index-- > 0) ++i;

		// Loop through displaying entries
		for (index = 0; (i != _inventoryItems.end()) && (index < _cellCount.x * _cellCount.y); ++index, ++i) {
			GUIInventoryItem *item = (*i).get();
			const Common::Point cellPos = getCellPosition(index);
/*			Common::Rect cellBounds(_bounds.left + cellPos.x + xOffset,
				_bounds.top + cellPos.y + yOffset,
				_bounds.left + cellPos.x + xOffset + _cellSize.x,
				_bounds.top + cellPos.y + _cellSize.y);*/
			Common::Rect cellBounds(_bounds.left + cellPos.x, _bounds.top + cellPos.y,
				_bounds.left + cellPos.x + _cellSize.x, _bounds.top + cellPos.y + _cellSize.y);

			Common::Point iconPt(
				cellBounds.left + (cellBounds.width() - item->icon->width()) / 2,
				cellBounds.top + (cellBounds.height() - item->icon->height()) / 2);

			item->icon->copyTo(_parent, iconPt.x, iconPt.y, 0);

			if (_highlightedIndex == index)
				_parent->frameRect(Common::Rect(iconPt.x - 2, iconPt.y - 2,
				iconPt.x + item->icon->width() + 2, iconPt.y + item->icon->height() + 2),
				_vm->_palette->LIGHT_GRAY);
		}
	}
}

bool GUIInventory::onEvent(M4EventType eventType, int param, int x, int y, GUIObject *&currentItem) {
	bool result = false;
	int overIndex = getInsideIndex(x, y);
	bool isPressed = (eventType == MEVENT_LEFT_CLICK) || (eventType == MEVENT_LEFT_HOLD) ||
		(eventType == MEVENT_LEFT_DRAG);
	ItemsIterator curItem = _inventoryItems.begin();

	if (isPressed) {
		if (_selectedIndex == -1 && overIndex != -1) {
			setHighlight(overIndex);
			_selectedIndex = overIndex;
			for (int i = 0; i < _scrollPosition + _selectedIndex; i++)
				++curItem;
			if (_scrollPosition + _selectedIndex < (int)_inventoryItems.size())
				_vm->_mouse->setCursorNum(curItem->get()->iconIndex);
			result = true;
		} else {
			// We are over something being tracked
			if (_selectedIndex == overIndex) {
				setHighlight(overIndex);
				result = true;
			} else {
				// Otherwise reset highlighting
				setHighlight(-1);
				result = false;
			}
		}
	} else {
		// No button pressed
		if (_selectedIndex == overIndex) {
			result = (_selectedIndex != -1);
		} else {
			result = (overIndex + _scrollPosition < (int)_inventoryItems.size());
			if (result) {
				for (int i = 0; i < overIndex + _scrollPosition; i++)
					++curItem;
				_vm->_interfaceView->setStatusText(curItem->get()->name);
			}
		}

		// Stop tracking anything
		setHighlight(overIndex);
	}

	return result;
}

void GUIInventory::add(const char *name, const char *verb, M4Surface *icon, int iconIndex) {
	// First scan through the list to prevent duplicate objects
	for (ItemsIterator i = _inventoryItems.begin(); i != _inventoryItems.end(); ++i) {
		if (!strcmp(name, ((*i).get())->name))
			return;
	}

	_inventoryItems.push_back(InventoryList::value_type(new GUIInventoryItem(name, verb, icon, iconIndex)));
}

bool GUIInventory::remove(const char *name) {
	for (ItemsIterator i = _inventoryItems.begin(); i != _inventoryItems.end(); ++i) {
		if (!strcmp(name, ((*i).get())->name)) {
			_inventoryItems.erase(i);
			_scrollPosition = 0;
			return true;
		}
	}

	return false;
}

int GUIInventory::getInsideIndex(int x, int y) {
	if (!_bounds.contains(x, y))
		return -1;

	int localX = x - _bounds.left;
	int localY = y - _bounds.top;
	return (localX / _cellSize.x) * _cellCount.y + (localY / _cellSize.y);
}

const char *GUIInventory::getSelectedObjectName() {
	if (_selectedIndex != -1) {
		ItemsIterator curItem = _inventoryItems.begin();
		for (int i = 0; i < _selectedIndex; i++)
			++curItem;
		return curItem->get()->name;
	} else {
		return NULL;
	}
}

const Common::Point &GUIInventory::getCellPosition(int index) {
	static Common::Point result;

	if (_cellCount.x > _cellCount.y) {
		// Horizontal orientation
		result.x = (index / _cellCount.y) * _cellSize.x;
		result.y = (index % _cellCount.y) * _cellSize.x;
	} else {
		// Vertical orientation
		result.x = (index / _cellCount.x) * _cellSize.y;
		result.y = (index % _cellCount.x) * _cellSize.y;
	}

	return result;
}

void GUIInventory::setHighlight(int index) {
	if (_highlightedIndex == index)
		return;

	_highlightedIndex = index;
}

void GUIInventory::setScrollPosition(int value) {
	if (value < 0)
		return;
	else if (value >= (int)_inventoryItems.size() - (_cellCount.x * _cellCount.y))
		return;

	_scrollPosition = value;
}

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

const char *INTERFACE_SERIES = "999intr";

#define SPR(x) _sprites->getFrame(x)

GameInterfaceView::GameInterfaceView(M4Engine *vm):
		View(vm, Common::Rect(0, vm->_screen->height() - INTERFACE_HEIGHT,
				vm->_screen->width(), vm->_screen->height())),
		_statusText(GUITextField(this, Common::Rect(200, 1, 450, 21))),
		_inventory(GUIInventory(this, vm, Common::Rect(188, 22, 539, 97), 9, 1, 39, 75, 3)) {

	_screenType = VIEWID_INTERFACE;
	_screenFlags.layer = LAYER_INTERFACE;
	_screenFlags.visible = false;
	_screenFlags.get = SCREVENT_MOUSE;
	_highlightedIndex = -1;
	_selected = false;

	Common::SeekableReadStream *data = _vm->res()->get(INTERFACE_SERIES);
	RGB8 *palette;

	_sprites = new SpriteAsset(_vm, data, data->size(), INTERFACE_SERIES);
	palette = _sprites->getPalette();

	//Palette.setPalette(palette, 0, _sprites->getColorCount());

	_vm->res()->toss(INTERFACE_SERIES);

	// Setup the interface buttons

	_buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(15, 35, 47, 66), 0, SPR(0), SPR(1), SPR(2))));   // look
	_buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(60, 35, 92, 66), 1, SPR(3), SPR(4), SPR(5))));   // take
	_buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(105, 35, 137, 66), 2, SPR(6), SPR(7), SPR(8)))); // manipulate

	_buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(580, 10, 620, 69), 3, SPR(69), SPR(70), SPR(71))));  // abduction
	_buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(582, 70, 619, 105), 4, SPR(76), SPR(77), SPR(78)))); // menu

	_buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(168, 22, 188, 97), 5, SPR(60), SPR(61), SPR(62))));   // Scroll left
	_buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(539, 22, 559, 97), 6, SPR(64), SPR(65), SPR(66))));   // Scroll right
}

#undef SPR

GameInterfaceView::~GameInterfaceView() {
	delete _sprites;
}

void GameInterfaceView::setHighlightedButton(int index) {
	if (index == _highlightedIndex)
		return;

	_selected = (index == -1);
	_highlightedIndex = index;
}

bool GameInterfaceView::onEvent(M4EventType eventType, int param, int x, int y, bool &captureEvents) {
	static bool selectionFlag = false;
	if (eventType == MEVENT_LEFT_RELEASE)
		selectionFlag = false;

	captureEvents = isInside(x, y);
	if (!captureEvents)
		return false;

	int localX = x - _coords.left;
	int localY = y - _coords.top;
	GUIObject *currentItem;

	_statusText.onEvent(eventType, param, localX, localY, currentItem);
	_inventory.onEvent(eventType, param, localX, localY, currentItem);

	if (_vm->_mouse->getCursorNum() != CURSOR_LOOK &&
		_vm->_mouse->getCursorNum() != CURSOR_TAKE &&
		_vm->_mouse->getCursorNum() != CURSOR_USE &&
		_vm->_interfaceView->_inventory.getSelectedIndex() == -1) {
		if (_vm->_mouse->getCursorNum() != 0)
			_vm->_mouse->setCursorNum(0);
	}

	for (ButtonsIterator i = _buttons.begin(); i != _buttons.end(); ++i) {
		GUIButton *btn = (*i).get();
		btn->onEvent(eventType, param, localX, localY, currentItem);
		if ((btn->getState() == BUTTON_PRESSED) && !selectionFlag) {
			selectionFlag = true;
			_highlightedIndex = btn->getTag();

			switch (_highlightedIndex) {
			case 0:
				_vm->_mouse->setCursorNum(CURSOR_LOOK);
				break;
			case 1:
				_vm->_mouse->setCursorNum(CURSOR_TAKE);
				break;
			case 2:
				_vm->_mouse->setCursorNum(CURSOR_USE);
				break;
			case 3:
				// TODO: Jump to abduction
				break;
			case 4:
				_vm->loadMenu(GAME_MENU);
				break;
			case 5:
				_inventory.scrollLeft();
				break;
			case 6:
				_inventory.scrollRight();
				break;
			default:
				break;
			}
		}
	}

	return true;
}

void GameInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) {
	clear();

	_statusText.onRefresh();
	_inventory.onRefresh();
	for (ButtonsIterator i = _buttons.begin(); i != _buttons.end(); ++i)
		((*i).get())->onRefresh();

	View::onRefresh(rects, destSurface);
}


} // End of namespace M4