/* 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.
 *
 */

#ifdef ENABLE_LOL

#include "kyra/text_lol.h"
#include "kyra/lol.h"
#include "kyra/screen_lol.h"
#include "kyra/timer.h"
#include "kyra/sound.h"

#include "common/system.h"

namespace Kyra {

TextDisplayer_LoL::TextDisplayer_LoL(LoLEngine *engine, Screen_LoL *screenLoL) : TextDisplayer_rpg(engine, screenLoL),
	_vm(engine), _screen(screenLoL), _scriptTextParameter(0) {

	memset(_stringParameters, 0, 15 * sizeof(char *));
	_buffer = new char[600];
	memset(_buffer, 0, 600);

	_waitButtonSpace = 0;
}

TextDisplayer_LoL::~TextDisplayer_LoL() {
	delete[] _buffer;
}

void TextDisplayer_LoL::setupField(bool mode) {
	if (_vm->textEnabled()) {

		int y = 142;
		int h = 37;
		int stepY = 3;
		int stepH = 1;

		if (_vm->gameFlags().use16ColorMode) {
			y = 140;
			h = 39;
			stepY = 4;
			stepH = 2;
		}

		if (mode) {
			_screen->copyRegionToBuffer(3, 0, 0, 320, 40, _vm->_pageBuffer1);
			_screen->copyRegion(80, y, 0, 0, 240, h, 0, 3, Screen::CR_NO_P_CHECK);
			_screen->copyRegionToBuffer(3, 0, 0, 320, 40, _vm->_pageBuffer2);
			_screen->copyBlockToPage(3, 0, 0, 320, 40, _vm->_pageBuffer1);
		} else {
			_screen->setScreenDim(clearDim(4));
			int cp = _screen->setCurPage(2);
			_screen->copyRegionToBuffer(3, 0, 0, 320, 40, _vm->_pageBuffer1);
			_screen->copyBlockToPage(3, 0, 0, 320, 40, _vm->_pageBuffer2);
			_screen->copyRegion(0, 0, 80, y, 240, h, 3, _screen->_curPage, Screen::CR_NO_P_CHECK);

			for (int i = 177; i > 141; i--) {
				uint32 endTime = _vm->_system->getMillis() + _vm->_tickLength;
				_screen->copyRegion(83, i - stepH + 1, 83, i - stepH, 235, stepY, 0, 0, Screen::CR_NO_P_CHECK);
				_screen->copyRegion(83, i + 1, 83, i + 1, 235, 1, 2, 0, Screen::CR_NO_P_CHECK);
				_vm->updateInput();
				_screen->updateScreen();
				_vm->delayUntil(endTime);
			}

			_screen->copyBlockToPage(3, 0, 0, 320, 200, _vm->_pageBuffer1);
			_screen->setCurPage(cp);

			_vm->_updateFlags &= 0xFFFD;
		}
	} else {
		if (!mode)
			_screen->setScreenDim(clearDim(4));
		_vm->toggleSelectedCharacterFrame(1);
	}
}

void TextDisplayer_LoL::expandField() {
	uint8 *tmp = _vm->_pageBuffer1 + 13000;

	if (_vm->textEnabled()) {
		_vm->_fadeText = false;
		_vm->_textColorFlag = 0;
		_vm->_timer->disable(11);
		_screen->setScreenDim(clearDim(3));
		_screen->copyRegionToBuffer(3, 0, 0, 320, 10, tmp);

		int y = 140;
		int h = 3;
		int stepH = 0;

		if (_vm->gameFlags().use16ColorMode) {
			y = 139;
			h = 4;
			stepH = 1;
		}

		_screen->copyRegion(83, y, 0, 0, 235, h, 0, 2, Screen::CR_NO_P_CHECK);

		for (int i = 140; i < 177; i++) {
			uint32 endTime = _vm->_system->getMillis() + _vm->_tickLength;
			_screen->copyRegion(0, 0, 83, i - stepH, 235, h, 2, 0, Screen::CR_NO_P_CHECK);
			_vm->updateInput();
			_screen->updateScreen();
			_vm->delayUntil(endTime);
		}

		_screen->copyBlockToPage(3, 0, 0, 320, 10, tmp);
		_vm->_updateFlags |= 2;

	} else {
		clearDim(3);
		_vm->toggleSelectedCharacterFrame(0);
	}
}

void TextDisplayer_LoL::printDialogueText(int dim, char *str, EMCState *script, const uint16 *paramList, int16 paramIndex) {
	int oldDim = 0;

	if (dim == 3) {
		if (_vm->_updateFlags & 2) {
			oldDim = clearDim(4);
			_textDimData[4].color1 = _vm->gameFlags().use16ColorMode ? 0x33 : 254;
			_textDimData[4].color2 = _screen->_curDim->unkA;
		} else {
			oldDim = clearDim(3);
			_textDimData[3].color1 = _vm->gameFlags().use16ColorMode ? 0x33 : 192;
			_textDimData[3].color2 = _screen->_curDim->unkA;
			if (!_vm->gameFlags().use16ColorMode)
				_screen->copyColor(192, 254);
			_vm->enableTimer(11);
			_vm->_textColorFlag = 0;
			_vm->_fadeText = false;
		}
	} else {
		oldDim = _screen->curDimIndex();
		_screen->setScreenDim(dim);
		_lineCount = 0;
		_textDimData[dim].color1 = _vm->gameFlags().use16ColorMode ? 0x33 : 254;
		_textDimData[dim].color2 = _screen->_curDim->unkA;
	}

	int cp = _screen->setCurPage(0);
	Screen::FontId of = _screen->setFont((_vm->gameFlags().lang == Common::JA_JPN && _vm->gameFlags().use16ColorMode) ? Screen::FID_SJIS_FNT : Screen::FID_9_FNT);

	preprocessString(str, script, paramList, paramIndex);
	_numCharsTotal = strlen(_dialogueBuffer);
	displayText(_dialogueBuffer);

	_screen->setScreenDim(oldDim);
	_screen->setCurPage(cp);
	_screen->setFont(of);
	_lineCount = 0;
	_vm->_fadeText = false;
}

void TextDisplayer_LoL::printMessage(uint16 type, const char *str, ...) {
	static const uint8 textColors256[] = { 0xFE, 0xA2, 0x84, 0x97, 0x9F };
	static const uint8 textColors16[] = { 0x33, 0xAA, 0x88, 0x55, 0x99 };
	static const uint8 soundEffect[] = { 0x0B, 0x00, 0x2B, 0x1B, 0x00 };

	const uint8 *textColors = _vm->gameFlags().use16ColorMode ? textColors16 : textColors256;

	if (type & 4)
		type ^= 4;
	else
		_vm->stopPortraitSpeechAnim();

	uint16 col = textColors[type & 0x7FFF];

	int od = _screen->curDimIndex();

	if (_vm->_updateFlags & 2) {
		clearDim(4);
		_textDimData[4].color1 = col;
	} else {
		clearDim(3);
		if (_vm->gameFlags().use16ColorMode) {
			_textDimData[3].color1 = col;
		} else {
			_screen->copyColor(192, col);
			_textDimData[3].color1 = 192;
		}
		_vm->enableTimer(11);
	}

	va_list args;
	va_start(args, str);

	vsnprintf((char *)_buffer, 240, str, args);

	va_end(args);

	displayText(_buffer);

	_screen->setScreenDim(od);
	_lineCount = 0;

	if (!(type & 0x8000)) {
		if (soundEffect[type])
			_vm->sound()->playSoundEffect(soundEffect[type]);
	}

	_vm->_textColorFlag = type & 0x7FFF;
	_vm->_fadeText = false;
}

void TextDisplayer_LoL::preprocessString(char *str, EMCState *script, const uint16 *paramList, int16 paramIndex) {
	char *dst = _dialogueBuffer;

	for (char *s = str; *s;) {
		if (_vm->gameFlags().lang == Common::JA_JPN) {
			uint8 c = *s;
			if (c >= 0xE0 || (c > 0x80 && c < 0xA0)) {
				*dst++ = *s++;
				*dst++ = *s++;
				continue;
			}
		}

		if (*s != '%') {
			*dst++ = *s++;
			continue;
		}

		char para = *++s;
		bool eos = false;

		switch (para) {
		case '\0':
			eos = true;
			break;
		case '#':
			para = *++s;
			switch (para) {
			case 'E':
			case 'G':
			case 'X':
			case 'c':
			case 'd':
			case 'e':
			case 'f':
			case 'g':
			case 's':
			case 'u':
			case 'x':
				break;
			default:
				eos = true;
			}
			break;
		case ' ':
		case '+':
		case '-':
			++s;
		default:
			break;
		}

		if (eos)
			continue;

		para = *s;

		switch (para) {
		case '\0':
			eos = true;
			break;
		case '0':
			++s;
			break;
		default:
			while (para && para > 47 && para < 58)
				para = *++s;
			break;
		}
		if (eos)
			continue;

		para = *s++;

		switch (para) {
		case 'a':
			strcpy(dst, Common::String::format("%d", _scriptTextParameter).c_str());
			dst += strlen(dst);
			break;

		case 'n':
			strcpy(dst, _vm->_characters[script ? script->stack[script->sp + paramIndex] : paramList[paramIndex]].name);
			dst += strlen(dst);
			break;

		case 's':
			strcpy(dst, _vm->getLangString(script ? script->stack[script->sp + paramIndex] : paramList[paramIndex]));
			dst += strlen(dst);
			break;

		case 'X':
		case 'd':
		case 'u':
		case 'x':
			strcpy(dst, Common::String::format("%d", script ? script->stack[script->sp + paramIndex] : paramList[paramIndex]).c_str());
			dst += strlen(dst);
			break;

		case '\0':
		default:
			continue;
		}
	}
	*dst = 0;
}

KyraRpgEngine *TextDisplayer_LoL::vm() {
	return _vm;
}

Screen *TextDisplayer_LoL::screen() {
	return _screen;
}

void TextDisplayer_LoL::textPageBreak() {
	strcpy(_pageBreakString, _vm->getLangString(0x4073));
	TextDisplayer_rpg::textPageBreak();
}

} // End of namespace Kyra

#endif // ENABLE_LOL
