/* 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/>.
 *
 *
 *              Originally written by Syn9 in FreeBASIC with SDL
 *              http://syn9.thehideoutgames.com/index_backup.php
 *
 *            Ported to plain C for GCW-Zero handheld by Dmitry Smagin
 *                http://github.com/dmitrysmagin/griffon_legend
 *
 *
 *                 Programming/Graphics: Daniel "Syn9" Kennedy
 *                     Music/Sound effects: David Turner
 *
 *                   Beta testing and gameplay design help:
 *                    Deleter, Cha0s, Aether Fox, and Kiz
 *
 */

#include "common/system.h"

#include "griffon/griffon.h"

#include "common/config-manager.h"
#include "common/text-to-speech.h"

namespace Griffon {

#define POLL_AND_CHECK_QUIT() 		if (g_system->getEventManager()->pollEvent(_event)) { \
		if (_event.type == Common::EVENT_QUIT || _event.type == Common::EVENT_RETURN_TO_LAUNCHER) { \
			_shouldQuit = true; \
			return; \
		} \
	}

#define CHECK_QUIT() 		if (_event.type == Common::EVENT_QUIT || _event.type == Common::EVENT_RETURN_TO_LAUNCHER) { \
		_shouldQuit = true; \
		return; \
	}

const char *story[48] = {
	"The Griffon Legend",
	"http://syn9.thehideoutgames.com/",
	"",
	"Programming/Graphics: Daniel Kennedy",
	"Music/Sound effects: David Turner",
	"",
	"Porting to GCW-Zero: Dmitry Smagin",
	"",
	"",
	"Story",
	"Ever since I was a child",
	"I remember being told the",
	"Legend of the Griffon Knights,",
	"who rid the world of the",
	"Dragon Empire.  These great",
	"heroes inspired us to become",
	"knights as well.",
	" ",
	"Now, 500 years after the war",
	"ended, the Dragons have",
	"returned.  Cities are falling",
	"from the lack of knights to",
	"protect them.",
	" ",
	"We never saw it coming.",
	" ",
	"And now, here I am, making",
	"my way into the lower town",
	"of Fidelis, a small city on",
	"the main continent. The rest",
	"of my men have died over",
	"the last couple days from",
	"aerial attacks.",
	" ",
	"We believed we could find",
	"shelter here, only to find",
	"every last griffon dead,",
	"the town burned to the ground,",
	"and transformed into a garrison",
	"for the Dragon forces.",
	" ",
	"In these dark times, I try to",
	"draw strength from the stories",
	"of those knights that risked",
	"everything to protect their homeland,",
	" ",
	"and hope that I can die",
	"with that honor as well."
};

const char *story2[27] = {
	"After the fall of Margrave Gradius,",
	"All the dragons, struck with panic,",
	"evacuated the city immediately.",
	" ",
	"It\'s funny how without a leader",
	"everyone is so weak.",
	" ",
	" ",
	"But yet another leader will rise,",
	"and another city will fall.",
	" ",
	" ",
	"I should return home to Asherton",
	"It\'s time to leave this place",
	"and cleanse this blood stained",
	"life of mine.",
	" ",
	"No one should have to see as much",
	"death as I have.",
	" ",
	" ",
	"Before, I said that I wanted",
	"to die an honorable death.",
	" ",
	"Now I say that I have lived an",
	"honorable life,",
	"and I am free to die as I please."
};

int textToSpeech(int nextparagraph, const char *storyVariable[], int arraysize) {
	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
	if (ttsMan != nullptr && ConfMan.getBool("tts_enabled") && storyVariable[nextparagraph][0] != 0) {
		Common::String paragraph;
		while (nextparagraph < arraysize && storyVariable[nextparagraph][0] != ' ') {
			if (!paragraph.empty())
				paragraph += " ";
			paragraph += storyVariable[nextparagraph++];
		}
		while (nextparagraph < arraysize && storyVariable[nextparagraph][0] == ' ') {
			nextparagraph += 1;
		}
		ttsMan->say(paragraph, Common::TextToSpeechManager::QUEUE_NO_REPEAT);
	}
	return nextparagraph;
}

void GriffonEngine::showLogos() {
	_ticks = g_system->getMillis();
	int ticks1 = _ticks;

	do {
		float y = 255.0;
		if (_ticks < ticks1 + 1000) {
			y = 255.0 * ((float)(_ticks - ticks1) / 1000.0);
			y = CLIP<float>(y, 0.0, 255.0);
		}

		if (_ticks > ticks1 + 3000) {
			y = 255.0 - 255.0 * ((float)(_ticks - ticks1 - 3000.0) / 1000.0);
			y = CLIP<float>(y, 0.0, 255.0);
		}

		_videoBuffer->fillRect(Common::Rect(0, 0, 320, 240), 0);
		_logosImg->blit(*_videoBuffer, 0, 0, Graphics::FLIP_NONE, nullptr, TS_ARGB((int)y, (int)y, (int)y, (int)y));

		g_system->copyRectToScreen(_videoBuffer->getPixels(), _videoBuffer->pitch, 0, 0, _videoBuffer->w, _videoBuffer->h);
		g_system->updateScreen();

		if (g_system->getEventManager()->pollEvent(_event)) {
			if (_event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START && _event.customType == kGriffonMenu)
				return;

			CHECK_QUIT();
		}

		_ticksPassed = _ticks;
		_ticks = g_system->getMillis();

		_ticksPassed = _ticks - _ticksPassed;
		_fpsr = (float)_ticksPassed / 24;

		_fp++;
		if (_ticks > _nextTicks) {
			_nextTicks = _ticks + 1000;
			_fps = _fp;
			_fp = 0;
		}

		g_system->delayMillis(10);
		if (_ticks > ticks1 + 4000)
			break;
	} while (!_shouldQuit);
}

void GriffonEngine::intro() {
	_videoBuffer2->fillRect(Common::Rect(0, 0, _videoBuffer2->w, _videoBuffer2->h), 0);
	_videoBuffer3->fillRect(Common::Rect(0, 0, _videoBuffer3->w, _videoBuffer3->h), 0);

	_ticks = g_system->getMillis();

	_videoBuffer->blit(*_videoBuffer3);
	_videoBuffer->blit(*_videoBuffer2);

	_fpsr = 0.0;
	int y = 140;

	if (config.music) {
		haltSoundChannel(-1);
		_musicChannel = playSound(_musicEndOfGame, true);
		setChannelVolume(_musicChannel, 0);
	}

	_secsInGame = 0;
	_secStart = 0;

	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();

	bool ldStop = false;
	bool speedUp = false;
	int cnt = 0;
	float xofs = 0.0;
	float ld = 0.0;
	int nextparagraph = 0;

	do {
		Common::Rect rc;

		ld += 4 * _fpsr;
		if ((int)ld > config.musicVol)
			ld = config.musicVol;
		if (!ldStop) {
			setChannelVolume(_musicChannel, (int)ld);
			if ((int)ld == config.musicVol)
				ldStop = true;
		}

		rc.left = -xofs;
		rc.top = 0;

		_titleImg->blit(*_videoBuffer, rc.left, rc.top);

		rc.left = -xofs + 320;
		rc.top = 0;

		_titleImg->blit(*_videoBuffer, rc.left, rc.top);

		if (++cnt >= 6) {
			cnt = 0;
			y--;
		}

		for (int i = 0; i < ARRAYSIZE(story); i++) {
			int yy = y + i * 10;

			if (i == nextparagraph)
				nextparagraph = textToSpeech(nextparagraph, story, ARRAYSIZE(story));

			if (yy > -8 && yy < 240) {
				int x = 160 - strlen(story[i]) * 4;
				drawString(_videoBuffer, story[i], x, yy, 4);
			}

			if (yy < 10 && i == ARRAYSIZE(story) - 1) {
				if (ttsMan == nullptr || ttsMan->isSpeaking() == false)
					return;
			}
		}

		g_system->copyRectToScreen(_videoBuffer->getPixels(), _videoBuffer->pitch, 0, 0, _videoBuffer->w, _videoBuffer->h);
		g_system->updateScreen();

		_ticksPassed = _ticks;
		_ticks = g_system->getMillis();

		_ticksPassed = _ticks - _ticksPassed;
		_fpsr = (float)_ticksPassed / 24.0;

		_fp++;
		if (_ticks > _nextTicks) {
			_nextTicks = _ticks + 1000;
			_fps = _fp;
			_fp = 0;
		}

		float add = 0.5 * _fpsr;
		if (add > 1)
			add = 1;
		xofs += add;
		if (xofs >= 320)
			xofs -= 320;

		if (g_system->getEventManager()->pollEvent(_event)) {
			if (_event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START) {
				if (_event.customType == kGriffonCutsceneSpeedUp) {
					speedUp = true;
					cnt = 6;
				}
				else if (_event.customType == kGriffonMenu) {
					if (ttsMan != nullptr)
						ttsMan->stop();
					return;
				}
			} else if (_event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
				if (_event.customType == kGriffonCutsceneSpeedUp) {
					speedUp = false;
				}
			}

			CHECK_QUIT();
		} else if (speedUp)
			cnt = 6;

		g_system->delayMillis(10);
	} while (!_shouldQuit);
}

void GriffonEngine::endOfGame() {
	float xofs = 0;
	_ticks = g_system->getMillis();

	float spd = 0.2f;

	if (config.music) {
		haltSoundChannel(-1);
		_musicChannel = playSound(_musicEndOfGame, true);
		setChannelVolume(_musicChannel, 0);
	}

	int ticks1 = _ticks;
	int ya = 0;

	float ld = 0;
	bool ldstop = false; // CHECKME: Check if actually used
	int nextparagraph = 0;

	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();

	do {
		ld += 4 * _fpsr;
		if (ld > config.musicVol)
			ld = config.musicVol;
		if (!ldstop) {
			setChannelVolume(_musicChannel, (int)ld);
			if ((int)ld == config.musicVol)
				ldstop = true;
		}

		ya = 0;
		if (_ticks < ticks1 + 1500) {
			ya = (255 * (_ticks - ticks1)) / 1500;
			ya = CLIP(ya, 0, 255);
		} else
			break;

		_videoBuffer2->fillRect(Common::Rect(0, 0, _videoBuffer2->w, _videoBuffer2->h), 0);
		_videoBuffer->setAlpha(255 - ya);
		_videoBuffer->blit(*_videoBuffer2);

		g_system->copyRectToScreen(_videoBuffer2->getPixels(), _videoBuffer2->pitch, 0, 0, _videoBuffer2->w, _videoBuffer2->h);

		POLL_AND_CHECK_QUIT();

		g_system->updateScreen();
		g_system->delayMillis(10);

		_ticksPassed = _ticks;
		_ticks = g_system->getMillis();

		_ticksPassed = _ticks - _ticksPassed;
		_fpsr = (float)_ticksPassed / 24;

		_fp++;
		if (_ticks > _nextTicks) {
			_nextTicks = _ticks + 1000;
			_fps = _fp;
			_fp = 0;
		}
	} while (1);

	ticks1 = _ticks;
	ya = 0;
	float y = 140;

	do {
		Common::Rect rc;

		rc.left = -xofs;
		rc.top = 0;

		_titleImg->blit(*_videoBuffer, rc.left, rc.top);

		rc.left = -xofs + 320;
		rc.top = 0;

		_titleImg->blit(*_videoBuffer, rc.left, rc.top);

		y = y - spd * _fpsr;

		for (int i = 0; i < ARRAYSIZE(story2); i++) {
			int yy = y + i * 10;

			if (i == nextparagraph)
				nextparagraph = textToSpeech(nextparagraph, story2, ARRAYSIZE(story2));

			if (yy > -8 && yy < 240) {
				int x = 160 - strlen(story2[i]) * 4;
				drawString(_videoBuffer, story2[i], x, yy, 4);
			}

			if (yy < 10 && i == ARRAYSIZE(story2)-1) {
				if (ttsMan == nullptr || ttsMan->isSpeaking() == false)
					break;
			}
		}

		ya = 255;
		if (_ticks < ticks1 + 1000) {
			ya = 255 * (_ticks - ticks1) / 1000;
			ya = CLIP(ya, 0, 255);
		}

		_videoBuffer->setAlpha(ya);
		g_system->copyRectToScreen(_videoBuffer->getPixels(), _videoBuffer->pitch, 0, 0, _videoBuffer->w, _videoBuffer->h);

		_ticksPassed = _ticks;
		_ticks = g_system->getMillis();

		_ticksPassed = _ticks - _ticksPassed;
		_fpsr = (float)_ticksPassed / 24;

		_fp++;
		if (_ticks > _nextTicks) {
			_nextTicks = _ticks + 1000;
			_fps = _fp;
			_fp = 0;
		}

		float add = 0.5 * _fpsr;
		if (add > 1)
			add = 1;
		xofs += add;
		if (xofs >= 320)
			xofs -= 320;

		if (g_system->getEventManager()->pollEvent(_event)) {
			if (_event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START) {
				if (_event.customType == kGriffonCutsceneSpeedUp)
					spd = 1.0f;
				else if (_event.customType == kGriffonMenu) {
					if (ttsMan != nullptr)
						ttsMan->stop();
					break;
				}
			} else if (_event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
				if (_event.customType == kGriffonCutsceneSpeedUp)
					spd = 0.2f;
			}

			CHECK_QUIT();
		}

		g_system->updateScreen();
		g_system->delayMillis(10);
	} while (1);


	ticks1 = _ticks;
	int y1 = 0;

	_videoBuffer2->copyRectToSurface(_videoBuffer->getPixels(), _videoBuffer->pitch, 0, 0, _videoBuffer->w, _videoBuffer->h);

	do {
		if (_ticks < ticks1 + 1500) {
			y1 = 255 * (_ticks - ticks1) / 1500;
			y1 = CLIP(y1, 0, 255);
		} else
			break;

		_videoBuffer->fillRect(Common::Rect(0, 0, _videoBuffer->w, _videoBuffer->h), 0);

		_videoBuffer->setAlpha(y1);
		_videoBuffer2->blit(*_videoBuffer3);
		_videoBuffer->blit(*_videoBuffer3);

		g_system->copyRectToScreen(_videoBuffer3->getPixels(), _videoBuffer3->pitch, 0, 0, _videoBuffer3->w, _videoBuffer3->h);
		g_system->updateScreen();

		POLL_AND_CHECK_QUIT();

		g_system->delayMillis(10);

		_ticksPassed = _ticks;
		_ticks = g_system->getMillis();

		_ticksPassed = _ticks - _ticksPassed;
		_fpsr = (float)_ticksPassed / 24;

		_fp++;
		if (_ticks > _nextTicks) {
			_nextTicks = _ticks + 1000;
			_fps = _fp;
			_fp = 0;
		}
	} while (1);


	int keywait = 2000 + _ticks;

	ticks1 = _ticks;
	y1 = 0;
	do {

		_videoBuffer->copyRectToSurface(_theEndImg->getPixels(), _theEndImg->pitch, 0, 0, _theEndImg->w, _theEndImg->h);

		y1 = 255;
		if (_ticks < ticks1 + 1000) {
			y1 = 255 * (_ticks - ticks1) / 1000;
			y1 = CLIP(y1, 0, 255);
		}

		_videoBuffer->setAlpha(y1);

		_videoBuffer2->fillRect(Common::Rect(0, 0, _videoBuffer2->w, _videoBuffer2->h), 0);
		_videoBuffer->blit(*_videoBuffer2);

		g_system->copyRectToScreen(_videoBuffer2->getPixels(), _videoBuffer2->pitch, 0, 0, _videoBuffer2->w, _videoBuffer2->h);

		g_system->updateScreen();
		g_system->delayMillis(10);

		_ticksPassed = _ticks;
		_ticks = g_system->getMillis();

		_ticksPassed = _ticks - _ticksPassed;
		_fpsr = (float)_ticksPassed / 24;

		_fp++;
		if (_ticks > _nextTicks) {
			_nextTicks = _ticks + 1000;
			_fps = _fp;
			_fp = 0;
		}

		if (g_system->getEventManager()->pollEvent(_event)) {
			CHECK_QUIT();

			if ((_event.type == Common::EVENT_KEYDOWN || _event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START) && keywait < _ticks)
				break;
		}

	} while (1);

	_videoBuffer2->fillRect(Common::Rect(0, 0, _videoBuffer2->w, _videoBuffer2->h), 0);
	_videoBuffer3->fillRect(Common::Rect(0, 0, _videoBuffer3->w, _videoBuffer3->h), 0);

	theEnd();
}

void GriffonEngine::theEnd() {
	for (int i = 0; i < kMaxFloat; i++) {
		_floatText[i].framesLeft = 0;
		_floatIcon[i].framesLeft = 0;
	}

	for (float y = 0; y < 100; y += _fpsr) {
		_videoBuffer2->fillRect(Common::Rect(0, 0, _videoBuffer2->w, _videoBuffer2->h), 0);
		_videoBuffer->setAlpha((int)((100.0 - y) / 100 * 255));
		_videoBuffer->blit(*_videoBuffer2);

		g_system->copyRectToScreen(_videoBuffer2->getPixels(), _videoBuffer2->pitch, 0, 0, _videoBuffer2->w, _videoBuffer2->h);
		g_system->updateScreen();

		POLL_AND_CHECK_QUIT();

		g_system->delayMillis(10);

		_ticksPassed = _ticks;
		_ticks = g_system->getMillis();

		_ticksPassed = _ticks - _ticksPassed;
		_fpsr = (float)_ticksPassed / 24.0;

		_fp++;
		if (_ticks > _nextTicks) {
			_nextTicks = _ticks + 1000;
			_fps = _fp;
			_fp = 0;
		}
	}
}


} // end of namespace Griffon
