/* 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 "common/config-manager.h"
#include "common/file.h"

#include "agos/intern.h"
#include "agos/agos.h"
#include "agos/midi.h"
#include "agos/vga.h"

namespace AGOS {

uint AGOSEngine::setVerbText(HitArea *ha) {
	uint id = 0xFFFF;

	if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2)
		return id;

	if (ha->flags & kBFTextBox) {
		if (getGameType() == GType_PP)
			id = ha->id;
		else if (getGameType() == GType_FF && (ha->flags & kBFHyperBox))
			id = ha->data;
		else
			id = ha->flags / 256;
	}
	if (getGameType() == GType_PP)
		_variableArray[199] = id;
	else if (getGameType() == GType_WW)
		_variableArray[10] = id;
	else
		_variableArray[60] = id;

	return id;
}

void AGOSEngine::setup_cond_c_helper() {
	HitArea *last;

	_noRightClick = 1;

	if (getGameType() == GType_WW)
		clearMenuStrip();

	if (getGameType() == GType_FF) {
		int cursor = 5;
		int animMax = 16;

		if (getBitFlag(200)) {
			cursor = 11;
			animMax = 5;
		} else if (getBitFlag(201)) {
			cursor = 12;
			animMax = 5;
		} else if (getBitFlag(202)) {
			cursor = 13;
			animMax = 5;
		} else if (getBitFlag(203)) {
			cursor = 14;
			animMax = 9;
		} else if (getBitFlag(205)) {
			cursor = 17;
			animMax = 11;
		} else if (getBitFlag(206)) {
			cursor = 16;
			animMax = 2;
		} else if (getBitFlag(208)) {
			cursor = 26;
			animMax = 2;
		} else if (getBitFlag(209)) {
			cursor = 27;
			animMax = 9;
		} else if (getBitFlag(210)) {
			cursor = 28;
			animMax = 9;
		}

		_animatePointer = false;
		_mouseCursor = cursor;
		_mouseAnimMax = animMax;
		_mouseAnim = 1;
		_needHitAreaRecalc++;
	}

	if (getGameType() == GType_SIMON2) {
		_mouseCursor = 0;
		if (_defaultVerb != 999) {
			_mouseCursor = 9;
			_needHitAreaRecalc++;
			_defaultVerb = 0;
		}
	}

	_lastHitArea = 0;
	_hitAreaObjectItem = NULL;
	_nameLocked = false;

	last = _lastNameOn;
	clearName();
	_lastNameOn = last;

	while (!shouldQuit()) {
		_lastHitArea = NULL;
		_lastHitArea3 = 0;
		_leftButtonDown = false;

		do {
			if (_exitCutscene && getBitFlag(9)) {
				endCutscene();
				goto out_of_here;
			}

			if (getGameType() == GType_FF) {
				if (_variableArray[254] == 63) {
					hitarea_stuff_helper_2();
				} else if (_variableArray[254] == 75) {
					hitarea_stuff_helper_2();
					_variableArray[60] = 9999;
					goto out_of_here;
				}
			}

			delay(100);
		} while ((_lastHitArea3 == (HitArea *) -1 || _lastHitArea3 == 0) && !shouldQuit());

		if (_lastHitArea == NULL) {
		} else if (_lastHitArea->id == 0x7FFB) {
			inventoryUp(_lastHitArea->window);
		} else if (_lastHitArea->id == 0x7FFC) {
			inventoryDown(_lastHitArea->window);
		} else if (_lastHitArea->itemPtr != NULL) {
			_hitAreaObjectItem = _lastHitArea->itemPtr;
			setVerbText(_lastHitArea);
			break;
		}
	}

out_of_here:
	_lastHitArea3 = 0;
	_lastHitArea = 0;
	_lastNameOn = NULL;

	_mouseCursor = 0;
	_noRightClick = 0;
}

void AGOSEngine::waitForInput() {
	HitArea *ha;
	uint id;

	_leftButtonDown = false;
	_lastHitArea = 0;
	//_lastClickRem = 0;
	_verbHitArea = 0;
	_hitAreaSubjectItem = NULL;
	_hitAreaObjectItem = NULL;
	_clickOnly = false;
	_nameLocked = false;

	if (getGameType() == GType_WW) {
		_mouseCursor = 0;
		_needHitAreaRecalc++;
		clearMenuStrip();
	} else {
		resetVerbs();
	}

	while (!shouldQuit()) {
		_lastHitArea = NULL;
		_lastHitArea3 = NULL;
		_dragAccept = true;

		while (!shouldQuit()) {
			if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) &&
					_keyPressed.keycode == Common::KEYCODE_F10)
				displayBoxStars();
			if (processSpecialKeys()) {
				if (getGameId() != GID_DIMP)
					goto out_of_here;
			}
			if (_lastHitArea3 == (HitArea *) -1) {
				_lastHitArea = NULL;
				_lastHitArea3 = NULL;
				_dragAccept = true;
			} else {
				if (_lastHitArea3 || _dragMode)
					break;
				hitarea_stuff_helper();
				delay(100);
			}
		}

		if (!_lastHitArea3 && _dragMode) {
			ha = _lastClickRem;

			if (ha == 0 || ha->itemPtr == NULL || !(ha->flags & kBFDragBox)) {
				_dragFlag = false;
				_dragMode = false;
				_dragCount = 0;
				_dragEnd = false;
				continue;
			}

			_hitAreaSubjectItem = ha->itemPtr;
			_verbHitArea = 500;

			do {
				processSpecialKeys();
				hitarea_stuff_helper();
				delay(100);

				if (!_dragFlag) {
					_dragFlag = false;
					_dragMode = false;
					_dragCount = 0;
					_dragEnd = false;
				}
			} while (!_dragEnd);

			_dragFlag = false;
			_dragMode = false;
			_dragCount = 0;
			_dragEnd = false;

			boxController(_mouse.x, _mouse.y, 1);

			if (_currentBox != NULL) {
				_hitAreaObjectItem = _currentBox->itemPtr;
				setVerbText(_currentBox);
			}

			break;
		}

		ha = _lastHitArea;
		if (ha == NULL) {
		} else if (ha->id == 0x7FFB) {
			inventoryUp(ha->window);
		} else if (ha->id == 0x7FFC) {
			inventoryDown(ha->window);
		} else if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) &&
			(ha->id >= 101 && ha->id < 113)) {
			_verbHitArea = ha->verb;
			setVerb(ha);
			_defaultVerb = 0;
		} else {
			if (getGameType() == GType_WW) {
				if (_mouseCursor == 3)
					_verbHitArea = 236;

				if (ha->id == 98) {
					animate(2, 1, 110, 0, 0, 0);
					waitForSync(34);
				} else if (ha->id == 108) {
					animate(2, 1, 106, 0, 0, 0);
					waitForSync(34);
				} else if (ha->id == 109) {
					animate(2, 1, 107, 0, 0, 0);
					waitForSync(34);
				} else if (ha->id == 115) {
					animate(2, 1, 109, 0, 0, 0);
					waitForSync(34);
				} else if (ha->id == 116) {
					animate(2, 1, 113, 0, 0, 0);
					waitForSync(34);
				} else if (ha->id == 117) {
					animate(2, 1, 112, 0, 0, 0);
					waitForSync(34);
				} else if (ha->id == 118) {
					animate(2, 1, 108, 0, 0, 0);
					waitForSync(34);
				} else if (ha->id == 119) {
					animate(2, 1, 111, 0, 0, 0);
					waitForSync(34);
				}
			}
			if (ha->itemPtr && (!ha->verb || _verbHitArea ||
					(_hitAreaSubjectItem != ha->itemPtr && (ha->flags & kBFBoxItem)))
				) {
				_hitAreaSubjectItem = ha->itemPtr;
				id = setVerbText(ha);
				_nameLocked = false;
				displayName(ha);
				_nameLocked = true;

				if (_verbHitArea) {
					break;
				}

				if (getGameType() == GType_WW)
					doMenuStrip(menuFor_ww(ha->itemPtr, id));
				else if (getGameType() == GType_ELVIRA2)
					doMenuStrip(menuFor_e2(ha->itemPtr));
				else if (getGameType() == GType_ELVIRA1)
					lightMenuStrip(getUserFlag1(ha->itemPtr, 6));
			} else {
				if (ha->verb) {
					if (getGameType() == GType_WW && _mouseCursor && _mouseCursor < 4) {
						_hitAreaSubjectItem = ha->itemPtr;
						break;
					}

					_verbHitArea = ha->verb & 0xBFFF;
					if (ha->verb & 0x4000) {
						_hitAreaSubjectItem = ha->itemPtr;
						break;
					}
					if (_hitAreaSubjectItem != NULL)
						break;

					if (getGameType() == GType_WW) {
						if (ha->id == 109) {
							_mouseCursor = 2;
							_needHitAreaRecalc++;
						} else if (ha->id == 117) {
							_mouseCursor = 3;
							_needHitAreaRecalc++;
						}
					}
				}
			}
		}
	}

out_of_here:
	if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW)
		clearMenuStrip();
	else if (getGameType() == GType_ELVIRA1)
		unlightMenuStrip();

	_nameLocked = false;
	_needHitAreaRecalc++;
	_dragAccept = false;

	if (getGameType() == GType_WW && _mouseCursor < 3)
		_mouseCursor = 0;
}

void AGOSEngine::hitarea_stuff_helper() {
	if (getGameType() == GType_SIMON2 || getGameType() == GType_FF ||
		getGameType() == GType_PP) {
		if (_variableArray[254] || _variableArray[249]) {
			hitarea_stuff_helper_2();
		}
	} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW ||
		getGameType() == GType_SIMON1) {
		uint subr_id = (uint16)_variableArray[254];
		if (subr_id) {
			Subroutine *sub = getSubroutineByID(subr_id);
			if (sub != NULL) {
				startSubroutineEx(sub);
				permitInput();
			}
			_variableArray[254] = 0;
			_runScriptReturn1 = false;
		}
	}

	uint32 cur_time = getTime();
	if (cur_time != _lastTime) {
		_lastTime = cur_time;
		if (kickoffTimeEvents())
			permitInput();
	}

	if (getGameId() == GID_DIMP)
		delay(200);
}

void AGOSEngine::hitarea_stuff_helper_2() {
	uint subr_id;
	Subroutine *sub;

	subr_id = (uint16)_variableArray[249];
	if (subr_id) {
		sub = getSubroutineByID(subr_id);
		if (sub != NULL) {
			_variableArray[249] = 0;
			startSubroutineEx(sub);
			permitInput();
		}
		_variableArray[249] = 0;
	}

	subr_id = (uint16)_variableArray[254];
	if (subr_id) {
		sub = getSubroutineByID(subr_id);
		if (sub != NULL) {
			_variableArray[254] = 0;
			startSubroutineEx(sub);
			permitInput();
		}
		_variableArray[254] = 0;
	}

	_runScriptReturn1 = false;
}

#ifdef ENABLE_AGOS2
void AGOSEngine_Feeble::handleMouseWheelUp() {
	if (getGameType() == GType_PP || !(getBitFlag(99)))
		return;

	if (_mouse.x >= 128 && _mouse.x <= 515 && _mouse.y >= 102 && _mouse.y <= 206) {
		oracleTextDown();
	} else if (_mouse.x >= 172 && _mouse.x <= 469 && _mouse.y >= 287 && _mouse.y <= 382) {
		HitArea *ha = findBox(0x7FFB);
		if (ha != NULL && (ha->flags & kBFBoxInUse)) {
			if (!isSpriteLoaded(21, 9) && !isSpriteLoaded(23, 9))
				inventoryUp(ha->window);
		}
	}
}

void AGOSEngine_Feeble::handleMouseWheelDown() {
	if (getGameType() == GType_PP || !(getBitFlag(99)))
		return;

	if (_mouse.x >= 128 && _mouse.x <= 515 && _mouse.y >= 102 && _mouse.y <= 206) {
		oracleTextUp();
	} else if (_mouse.x >= 172 && _mouse.x <= 469 && _mouse.y >= 287 && _mouse.y <= 382) {
		HitArea *ha = findBox(0x7FFC);
		if (ha != NULL && (ha->flags & kBFBoxInUse)) {
			if (!isSpriteLoaded(21, 9) && !isSpriteLoaded(23, 9))
					inventoryDown(ha->window);
		}
	}
}
#endif

void AGOSEngine_Simon1::handleMouseWheelUp() {
	HitArea *ha = findBox(206);
	if (ha != NULL && (ha->flags & kBFBoxInUse) && !(ha->flags & kBFBoxDead)) {
			if (_saveLoadRowCurPos != 1) {
				if (_saveLoadRowCurPos < 7)
					_saveLoadRowCurPos = 1;
				else
					_saveLoadRowCurPos -= 1;

				_saveLoadEdit = false;
				listSaveGames();
			}
	} else {
		AGOSEngine::handleMouseWheelUp();
	}
}

void AGOSEngine_Simon1::handleMouseWheelDown() {
	HitArea *ha = findBox(207);
	if (ha != NULL && (ha->flags & kBFBoxInUse) && !(ha->flags & kBFBoxDead)) {
			if (_saveDialogFlag) {
				_saveLoadRowCurPos += 1;
				if (_saveLoadRowCurPos >= _numSaveGameRows)
					_saveLoadRowCurPos = _numSaveGameRows;

				_saveLoadEdit = false;
				listSaveGames();
			}
	} else {
		AGOSEngine::handleMouseWheelDown();
	}
}

void AGOSEngine_Elvira2::handleMouseWheelUp() {
	HitArea *ha = findBox(224);
	if (ha != NULL && (ha->flags & kBFBoxInUse)) {
			_saveGameNameLen = 0;

			if (_saveLoadRowCurPos < 3)
				_saveLoadRowCurPos = 1;
			else
				_saveLoadRowCurPos -= 3;

			listSaveGames();
	} else {
		AGOSEngine::handleMouseWheelUp();
	}
}

void AGOSEngine_Elvira2::handleMouseWheelDown() {
	HitArea *ha =  findBox(224);
	if (ha != NULL && (ha->flags & kBFBoxInUse)) {
			_saveGameNameLen = 0;
			_saveLoadRowCurPos += 3;
			if (_saveLoadRowCurPos >= _numSaveGameRows)
				_saveLoadRowCurPos = 1;

			listSaveGames();
	} else {
		AGOSEngine::handleMouseWheelDown();
	}
}

void AGOSEngine::handleMouseWheelUp() {
	HitArea *ha = findBox(0x7FFB);
	if (ha != NULL && (ha->flags & kBFBoxInUse)) {
		inventoryUp(ha->window);
	}
}

void AGOSEngine::handleMouseWheelDown() {
	HitArea *ha = findBox(0x7FFC);
	if (ha != NULL && (ha->flags & kBFBoxInUse)) {
		inventoryDown(ha->window);
	}
}

void AGOSEngine::permitInput() {
	if (_mortalFlag)
		return;

	_mortalFlag = true;
	justifyOutPut(0);

	if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
		int n = 0;
		while (n < 8) {
			if ((_fcsData1[n]) && (_windowArray[n]) && (_windowArray[n]->flags & 128)) {
				_textWindow = _windowArray[n];
				waitWindow(_textWindow);
				clsCheck(_textWindow);
			}
			_fcsData1[n]=0;
			n++;
		}

		restartAnimation();
	}

	_curWindow = 0;
	if (_windowArray[0]) {
		_textWindow = _windowArray[0];
		justifyStart();
	}
	_mortalFlag = false;

}

bool AGOSEngine::processSpecialKeys() {
	bool verbCode = false;

	if (getGameId() == GID_DIMP) {
		uint32 t1 = getTime() / 30;
		if (!_lastMinute)
			_lastMinute = t1;
		if (t1 - _lastMinute) {
			_variableArray[120] += (t1 - _lastMinute);
			_lastMinute = t1;
		}
	}

	if (shouldQuit())
		_exitCutscene = true;

	switch (_keyPressed.keycode) {
	case Common::KEYCODE_UP:
		if (getGameType() == GType_PP)
			_verbHitArea = 302;
		else if (getGameType() == GType_WW)
			_verbHitArea = 239;
		else if (getGameType() == GType_ELVIRA2 && isBoxDead(101))
			_verbHitArea = 200;
		else if (getGameType() == GType_ELVIRA1 && isBoxDead(101))
			_verbHitArea = 214;
		verbCode = true;
		break;
	case Common::KEYCODE_DOWN:
		if (getGameType() == GType_PP)
			_verbHitArea = 304;
		else if (getGameType() == GType_WW)
			_verbHitArea = 241;
		else if (getGameType() == GType_ELVIRA2 && isBoxDead(107))
			_verbHitArea = 202;
		else if (getGameType() == GType_ELVIRA1 && isBoxDead(105))
			_verbHitArea = 215;
		verbCode = true;
		break;
	case Common::KEYCODE_RIGHT:
		if (getGameType() == GType_PP)
			_verbHitArea = 303;
		else if (getGameType() == GType_WW)
			_verbHitArea = 240;
		else if (getGameType() == GType_ELVIRA2 && isBoxDead(102))
			_verbHitArea = 201;
		else if (getGameType() == GType_ELVIRA1 && isBoxDead(103))
			_verbHitArea = 216;
		verbCode = true;
		break;
	case Common::KEYCODE_LEFT:
		if (getGameType() == GType_PP)
			_verbHitArea = 301;
		else if (getGameType() == GType_WW)
			_verbHitArea = 242;
		else if (getGameType() == GType_ELVIRA2 && isBoxDead(104))
			_verbHitArea = 203;
		else if (getGameType() == GType_ELVIRA1 && isBoxDead(107))
			_verbHitArea = 217;
		verbCode = true;
		break;
	case Common::KEYCODE_ESCAPE:
		_exitCutscene = true;
		break;
	case Common::KEYCODE_F1:
		if (getGameType() == GType_SIMON2) {
			vcWriteVar(5, 50);
			vcWriteVar(86, 0);
		} else if (getGameType() == GType_SIMON1) {
			vcWriteVar(5, 40);
			vcWriteVar(86, 0);
		}
		break;
	case Common::KEYCODE_F2:
		if (getGameType() == GType_SIMON2) {
			vcWriteVar(5, 75);
			vcWriteVar(86, 1);
		} else if (getGameType() == GType_SIMON1) {
			vcWriteVar(5, 60);
			vcWriteVar(86, 1);
		}
		break;
	case Common::KEYCODE_F3:
		if (getGameType() == GType_SIMON2) {
			vcWriteVar(5, 125);
			vcWriteVar(86, 2);
		} else if (getGameType() == GType_SIMON1) {
			vcWriteVar(5, 100);
			vcWriteVar(86, 2);
		}
		break;
	case Common::KEYCODE_F5:
		if (getGameType() == GType_SIMON2 || getGameType() == GType_FF)
			_exitCutscene = true;
		break;
	case Common::KEYCODE_F7:
		if (getGameType() == GType_FF && getBitFlag(76))
			_variableArray[254] = 70;
		break;
	case Common::KEYCODE_F9:
		if (getGameType() == GType_FF)
			setBitFlag(73, !getBitFlag(73));
		break;
	case Common::KEYCODE_F12:
		if (getGameType() == GType_PP && getGameId() != GID_DIMP) {
			if (!getBitFlag(110)) {
				setBitFlag(107, !getBitFlag(107));
				_vgaPeriod = (getBitFlag(107) != 0) ? 15 : 30;
			}
		}
		break;
	case Common::KEYCODE_PAUSE:
		pause();
		break;
	default:
		break;
	}

	switch (_keyPressed.ascii) {
	case 't':
		if (getGameType() == GType_FF || (getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE)) ||
			((getFeatures() & GF_TALKIE) && _language != Common::EN_ANY && _language != Common::DE_DEU)) {
			if (_speech)
				_subtitles = !_subtitles;
		}
		break;
	case 'v':
		if (getGameType() == GType_FF || (getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE))) {
			if (_subtitles)
				_speech = !_speech;
		}
		break;
	case '+':
		if (_midiEnabled) {
			_midi->setVolume(_midi->getMusicVolume() + 16, _midi->getSFXVolume() + 16);
		}
		ConfMan.setInt("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 16);
		syncSoundSettings();
		break;
	case '-':
		if (_midiEnabled) {
			_midi->setVolume(_midi->getMusicVolume() - 16, _midi->getSFXVolume() - 16);
		}
		ConfMan.setInt("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) - 16);
		syncSoundSettings();
		break;
	case 'm':
		_musicPaused = !_musicPaused;
		if (_midiEnabled) {
			_midi->pause(_musicPaused);
		}
		_mixer->pauseHandle(_modHandle, _musicPaused);
		syncSoundSettings();
		break;
	case 's':
		if (getGameId() == GID_SIMON1DOS) {
			_midi->_enable_sfx = !_midi->_enable_sfx;
		} else {
			_effectsPaused = !_effectsPaused;
			_sound->effectsPause(_effectsPaused);
		}
		break;
	case 'b':
		if (getGameType() == GType_SIMON2) {
			_ambientPaused = !_ambientPaused;
			_sound->ambientPause(_ambientPaused);
		}
		break;
	default:
		break;
	}

	_keyPressed.reset();
	return verbCode;
}

} // End of namespace AGOS