/* 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 "neverhood/navigationscene.h"
#include "neverhood/mouse.h"

namespace Neverhood {

enum AreaType {
	kAreaCanMoveForward = 0,
	kAreaCannotMoveForward = 1
};

NavigationScene::NavigationScene(NeverhoodEngine *vm, Module *parentModule, uint32 navigationListId, int navigationIndex, const byte *itemsTypes)
	: Scene(vm, parentModule), _itemsTypes(itemsTypes), _navigationIndex(navigationIndex), _smackerDone(false),
	_isWalkingForward(false), _isTurning(false), _smackerFileHash(0), _interactive(true), _leaveSceneAfter(false) {

	_navigationList = _vm->_staticData->getNavigationList(navigationListId);
	_navigationListId = navigationListId;

	if (_navigationIndex < 0) {
		_navigationIndex = (int)getGlobalVar(V_NAVIGATION_INDEX);
		if (_navigationIndex >= (int)_navigationList->size())
			_navigationIndex = 0;
	}
	setGlobalVar(V_NAVIGATION_INDEX, _navigationIndex);

	SetUpdateHandler(&NavigationScene::update);
	SetMessageHandler(&NavigationScene::handleMessage);

	_smackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, (*_navigationList)[_navigationIndex].fileHash, true, true));

	createMouseCursor();

	_vm->_screen->clear();
	_vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder());

	sendMessage(_parentModule, 0x100A, _navigationIndex);
}

NavigationScene::~NavigationScene() {
	_vm->_soundMan->setTwoSoundsPlayFlag(false);
	_vm->_soundMan->setSoundThreePlayFlag(false);
}

int NavigationScene::getNavigationAreaType() {
	NPoint mousePos;
	mousePos.x = _mouseCursor->getX();
	mousePos.y = _mouseCursor->getY();
	return sendPointMessage(_mouseCursor, 0x2064, mousePos);
}

void NavigationScene::update() {
	if (_smackerFileHash != 0) {
		showMouse(false);
		_smackerPlayer->open(_smackerFileHash, false);
		_vm->_screen->clear();
		_vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder());
		_smackerDone = false;
		/*
		if (!_interactive)
			_smackerDone = true;
		*/
		_smackerFileHash = 0;
	} else if (_smackerDone) {
		if (_leaveSceneAfter) {
			_vm->_screen->setSmackerDecoder(nullptr);
			sendMessage(_parentModule, 0x1009, _navigationIndex);
		} else {
			const NavigationItem &navigationItem = (*_navigationList)[_navigationIndex];
			createMouseCursor();
			showMouse(true);
			_isTurning = false;
			_isWalkingForward = false;
			_interactive = true;
			_vm->_soundMan->setTwoSoundsPlayFlag(false);
			_vm->_soundMan->setSoundThreePlayFlag(false);
			_smackerDone = false;
			_smackerPlayer->open(navigationItem.fileHash, true);
			_vm->_screen->clear();
			_vm->_screen->setSmackerDecoder(_smackerPlayer->getSmackerDecoder());
			sendMessage(_parentModule, 0x100A, _navigationIndex);
		}
	}
	Scene::update();
}

uint32 NavigationScene::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
	switch (messageNum) {
	case NM_MOUSE_MOVE:
		if (_interactive)
			sendMessage(_mouseCursor, 0x4002, param);
		break;
	case NM_MOUSE_CLICK:
		if (_interactive)
			handleNavigation(param.asPoint());
		break;
	case NM_KEYPRESS_SPACE:
		if (!_interactive)
			_smackerDone = true;
		break;
	case NM_ANIMATION_STOP:
		_smackerDone = true;
		break;
	default:
		break;
	}
	return 0;
}

void NavigationScene::createMouseCursor() {
	const NavigationItem &navigationItem = (*_navigationList)[_navigationIndex];
	uint32 mouseCursorFileHash;
	int areaType;

	if (_mouseCursor)
		deleteSprite((Sprite**)&_mouseCursor);

	mouseCursorFileHash = navigationItem.mouseCursorFileHash;
	if (mouseCursorFileHash == 0)
		mouseCursorFileHash = 0x63A40028;

	if (_itemsTypes)
		areaType = _itemsTypes[_navigationIndex];
	else if (navigationItem.middleSmackerFileHash != 0 || navigationItem.middleFlag)
		areaType = kAreaCanMoveForward;
	else
		areaType = kAreaCannotMoveForward;

	insertNavigationMouse(mouseCursorFileHash, areaType);
	sendPointMessage(_mouseCursor, 0x4002, _vm->getMousePos());
}

void NavigationScene::handleNavigation(const NPoint &mousePos) {
	const NavigationItem &navigationItem = (*_navigationList)[_navigationIndex];
	bool oldIsWalkingForward = _isWalkingForward;
	bool oldIsTurning = _isTurning;
	uint32 direction = sendPointMessage(_mouseCursor, 0x2064, mousePos);

	switch (direction) {
	case 0:
		if (navigationItem.leftSmackerFileHash != 0) {
			_smackerFileHash = navigationItem.leftSmackerFileHash;
			_interactive = false;
			_isWalkingForward = false;
			_isTurning = true;
			do {
				_navigationIndex--;
				if (_navigationIndex < 0)
					_navigationIndex = _navigationList->size() - 1;
			} while (!(*_navigationList)[_navigationIndex].interactive);
			setGlobalVar(V_NAVIGATION_INDEX, _navigationIndex);
		} else {
			_vm->_screen->setSmackerDecoder(nullptr);
			sendMessage(_parentModule, 0x1009, _navigationIndex);
		}
		break;
	case 1:
		if (navigationItem.rightSmackerFileHash != 0) {
			_smackerFileHash = navigationItem.rightSmackerFileHash;
			_interactive = false;
			_isWalkingForward = false;
			_isTurning = true;
			do {
				_navigationIndex++;
				if (_navigationIndex >= (int)_navigationList->size())
					_navigationIndex = 0;
			} while (!(*_navigationList)[_navigationIndex].interactive);
			setGlobalVar(V_NAVIGATION_INDEX, _navigationIndex);
		} else {
			_vm->_screen->setSmackerDecoder(nullptr);
			sendMessage(_parentModule, 0x1009, _navigationIndex);
		}
		break;
	case 2:
	case 3:
	case 4:
		if (navigationItem.middleFlag) {
			_vm->_screen->setSmackerDecoder(nullptr);
			sendMessage(_parentModule, 0x1009, _navigationIndex);
		} else if (navigationItem.middleSmackerFileHash != 0) {
			_smackerFileHash = navigationItem.middleSmackerFileHash;
			_interactive = false;
			_isWalkingForward = true;
			_isTurning = false;
			_leaveSceneAfter = true;
		}
		break;
	default:
		break;
	}

	if (oldIsTurning != _isTurning)
		_vm->_soundMan->setSoundThreePlayFlag(_isTurning);

	if (oldIsWalkingForward != _isWalkingForward)
		_vm->_soundMan->setTwoSoundsPlayFlag(_isWalkingForward);
}

} // End of namespace Neverhood
