/* 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 "engines/nancy/nancy.h"
#include "engines/nancy/graphics.h"
#include "engines/nancy/resource.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/input.h"
#include "engines/nancy/util.h"

#include "engines/nancy/action/telephone.h"

#include "engines/nancy/state/scene.h"

namespace Nancy {
namespace Action {

void Telephone::init() {
	_drawSurface.create(_screenPosition.width(), _screenPosition.height(), g_nancy->_graphicsManager->getInputPixelFormat());
	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());

	setTransparent(true);

	g_nancy->_resource->loadImage(_imageName, _image);

	NancySceneState.setShouldClearTextbox(false);
}

void Telephone::readData(Common::SeekableReadStream &stream) {
	readFilename(stream, _imageName);

	_srcRects.reserve(12);
	for (uint i = 0; i < 12; ++i) {
		_srcRects.push_back(Common::Rect());
		readRect(stream, _srcRects.back());
	}

	_destRects.reserve(12);
	for (uint i = 0; i < 12; ++i) {
		_destRects.push_back(Common::Rect());
		readRect(stream, _destRects.back());

		if (i == 0) {
			_screenPosition = _destRects.back();
		} else {
			_screenPosition.extend(_destRects.back());
		}
	}

	_genericDialogueSound.read(stream, SoundDescription::kNormal);
	_genericButtonSound.read(stream, SoundDescription::kNormal);
	_ringSound.read(stream, SoundDescription::kNormal);
	_dialToneSound.read(stream, SoundDescription::kNormal);
	_dialAgainSound.read(stream, SoundDescription::kNormal);
	_hangUpSound.read(stream, SoundDescription::kNormal);

	_buttonSoundNames.reserve(12);
	for (uint i = 0; i < 12; ++i) {
		Common::String buttonSoundName;
		readFilename(stream, buttonSoundName);
		_buttonSoundNames.push_back(buttonSoundName);
	}

	char textBuf[200];
	stream.read(textBuf, 200);
	textBuf[199] = '\0';
	_addressBookString = textBuf;
	stream.read(textBuf, 200);
	textBuf[199] = '\0';
	_dialAgainString = textBuf;
	_reloadScene.readData(stream);
	stream.skip(2);
	_flagOnReload.label = stream.readSint16LE();
	_flagOnReload.flag = (NancyFlag)stream.readUint16LE();
	_exitScene.readData(stream);
	stream.skip(2);
	_flagOnExit.label = stream.readSint16LE();
	_flagOnExit.flag = (NancyFlag)stream.readUint16LE();
	readRect(stream, _exitHotspot);

	uint numCalls = stream.readUint16LE();

	_calls.reserve(numCalls);
	for (uint i = 0; i < numCalls; ++i) {
		_calls.push_back(PhoneCall());
		PhoneCall &call = _calls.back();

		call.phoneNumber.reserve(11);
		for (uint j = 0; j < 11; ++j) {
			call.phoneNumber.push_back(stream.readByte());
		}

		readFilename(stream, call.soundName);
		stream.read(textBuf, 200);
		textBuf[199] = '\0';
		call.text = textBuf;
		call.sceneChange.readData(stream);
		stream.skip(2);
		call.flag.label = stream.readSint16LE();
		call.flag.flag = (NancyFlag)stream.readUint16LE();
	}
}

void Telephone::execute() {
	switch (_state) {
	case kBegin:
		init();
		registerGraphics();
		g_nancy->_sound->loadSound(_dialToneSound);
		g_nancy->_sound->playSound(_dialToneSound);
		NancySceneState.getTextbox().clear();
		NancySceneState.getTextbox().addTextLine(_addressBookString);
		_state = kRun;
		// fall through
	case kRun:
		switch (_callState) {
		case kWaiting:
			// Long phone numbers start with 1
			if (_calledNumber.size() >= 11 || (_calledNumber.size() >= 7 && (_calledNumber[0] != 1))) {
				NancySceneState.getTextbox().clear();
				NancySceneState.getTextbox().addTextLine("ringing...<n><e>"); // Hardcoded in the original engine
				g_nancy->_sound->loadSound(_ringSound);
				g_nancy->_sound->playSound(_ringSound);
				_callState = kRinging;
			}

			break;
		case kButtonPress:
			if (!g_nancy->_sound->isSoundPlaying(_genericButtonSound)) {
				g_nancy->_sound->stopSound(_genericButtonSound);
				undrawButton(_selected);
				_callState = kWaiting;
			}

			break;
		case kRinging:
			if (!g_nancy->_sound->isSoundPlaying(_ringSound)) {
				g_nancy->_sound->stopSound(_ringSound);
				uint numberLength = _calledNumber[0] == 1 ? 11 : 7;

				for (uint i = 0; i < _calls.size(); ++i) {
					bool invalid = false;

					for (uint j = 0; j < numberLength; ++j) {
						if (_calledNumber[j] != _calls[i].phoneNumber[j]) {
							// Invalid number, move onto next
							invalid = true;
							break;
						}
					}

					if (invalid) {
						continue;
					}

					NancySceneState.getTextbox().clear();
					NancySceneState.getTextbox().addTextLine(_calls[i].text);

					_genericDialogueSound.name = _calls[i].soundName;
					g_nancy->_sound->loadSound(_genericDialogueSound);
					g_nancy->_sound->playSound(_genericDialogueSound);
					_selected = i;
					_callState = kCall;

					return;
				}

				NancySceneState.getTextbox().clear();
				NancySceneState.getTextbox().addTextLine(_dialAgainString);

				g_nancy->_sound->loadSound(_dialAgainSound);
				g_nancy->_sound->playSound(_dialAgainSound);
				_callState = kBadNumber;
				return;
			}

			break;
		case kBadNumber:
			if (!g_nancy->_sound->isSoundPlaying(_dialAgainSound)) {
				g_nancy->_sound->stopSound(_dialAgainSound);

				_state = kActionTrigger;
			}

			break;
		case kCall:
			if (!g_nancy->_sound->isSoundPlaying(_genericDialogueSound)) {
				g_nancy->_sound->stopSound(_genericDialogueSound);

				_state = kActionTrigger;
			}

			break;
		case kHangUp:
			if (!g_nancy->_sound->isSoundPlaying(_hangUpSound)) {
				g_nancy->_sound->stopSound(_hangUpSound);

				_state = kActionTrigger;
			}

			break;
		}

		break;
	case kActionTrigger:
		switch (_callState) {
		case kBadNumber:
			NancySceneState.changeScene(_reloadScene);
			_calledNumber.clear();
			NancySceneState.setEventFlag(_flagOnReload);
			_state = kRun;
			_callState = kWaiting;

			break;
		case kCall: {
			PhoneCall &call = _calls[_selected];
			NancySceneState.changeScene(call.sceneChange);
			NancySceneState.setEventFlag(call.flag);

			break;
		}
		case kHangUp:
			NancySceneState.changeScene(_exitScene);
			NancySceneState.setEventFlag(_flagOnExit);

			break;
		default:
			break;
		}

		finishExecution();
		NancySceneState.setShouldClearTextbox(true);
		NancySceneState.getTextbox().clear();
	}
}

void Telephone::handleInput(NancyInput &input) {
	int buttonNr = -1;
	// Cursor gets changed regardless of state
	for (uint i = 0; i < 12; ++i) {
		if (NancySceneState.getViewport().convertViewportToScreen(_destRects[i]).contains(input.mousePos)) {
			g_nancy->_cursorManager->setCursorType(CursorManager::kHotspot);
			buttonNr = i;
			break;
		}
	}

	if (_callState != kWaiting) {
		return;
	}

	if (NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
		g_nancy->_cursorManager->setCursorType(CursorManager::kExit);

		if (input.input & NancyInput::kLeftMouseButtonUp) {
			g_nancy->_sound->loadSound(_hangUpSound);
			g_nancy->_sound->playSound(_hangUpSound);

			_callState = kHangUp;
		}

		return;
	}

	if (buttonNr != -1) {
		if (input.input & NancyInput::kLeftMouseButtonUp) {
			if (g_nancy->_sound->isSoundPlaying(_dialToneSound)) {
				g_nancy->_sound->stopSound(_dialToneSound);
			}

			_calledNumber.push_back(buttonNr);
			_genericButtonSound.name = _buttonSoundNames[buttonNr];
			g_nancy->_sound->loadSound(_genericButtonSound);
			g_nancy->_sound->playSound(_genericButtonSound);

			drawButton(buttonNr);

			_selected = buttonNr;

			_callState = kButtonPress;
		}
	}
}

void Telephone::drawButton(uint id) {
	Common::Point destPoint(_destRects[id].left - _screenPosition.left, _destRects[id].top - _screenPosition.top);
	_drawSurface.blitFrom(_image, _srcRects[id], destPoint);

	_needsRedraw = true;
}

void Telephone::undrawButton(uint id) {
	Common::Rect bounds = _destRects[id];
	bounds.translate(-_screenPosition.left, -_screenPosition.top);

	_drawSurface.fillRect(bounds, g_nancy->_graphicsManager->getTransColor());
	_needsRedraw = true;
}

} // End of namespace Action
} // End of namespace Nancy
