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

/*
 * This code is based on original Mortville Manor DOS source code
 * Copyright (c) 1987-1989 Lankhor
 */

#include "mortevielle/mortevielle.h"
#include "mortevielle/mouse.h"
#include "mortevielle/outtext.h"
#include "mortevielle/graphics.h"

#include "common/file.h"
#include "common/str.h"

namespace Mortevielle {

TextHandler::TextHandler(MortevielleEngine *vm) {
	_vm = vm;
}

/**
 * Next word
 * @remarks	Originally called 'l_motsuiv'
 */
int TextHandler::nextWord(int p, const char *ch, int &tab) {
	int c = p;

	while ((ch[p] != ' ') && (ch[p] != '$') && (ch[p] != '@'))
		++p;

	return tab * (p - c);
}

/**
 * Engine function - Display Text
 * @remarks	Originally called 'afftex'
 */
void TextHandler::displayStr(Common::String inputStr, int x, int y, int dx, int dy, int typ) {
	Common::String s;
	int i, j;

	// Safeguard: add $ just in case
	inputStr += '$';

	_vm->_screenSurface->putxy(x, y);
	int tab = 6;
	dx *= 6;
	dy *= 6;
	int xc = x;
	int yc = y;
	int xf = x + dx;
	int yf = y + dy;
	int p = 0;
	bool stringParsed = (inputStr[p] == '$');
	s = "";
	while (!stringParsed) {
		switch (inputStr[p]) {
		case '@':
			_vm->_screenSurface->drawString(s, typ);
			s = "";
			++p;
			xc = x;
			yc += 6;
			_vm->_screenSurface->putxy(xc, yc);
			break;
		case ' ':
			s += ' ';
			xc += tab;
			++p;
			if (nextWord(p, inputStr.c_str(), tab) + xc > xf) {
				_vm->_screenSurface->drawString(s, typ);
				s = "";
				xc = x;
				yc += 6;
				if (yc > yf) {
					while (!_vm->keyPressed())
						;
					i = y;
					do {
						j = x;
						do {
							_vm->_screenSurface->putxy(j, i);
							_vm->_screenSurface->drawString(" ", 0);
							j += 6;
						} while (j <= xf);
						i += 6;
					} while (i <= yf);
					yc = y;
				}
				_vm->_screenSurface->putxy(xc, yc);
			}
			break;
		case '$':
			stringParsed = true;
			_vm->_screenSurface->drawString(s, typ);
			break;
		default:
			s += inputStr[p];
			++p;
			xc += tab;
			break;
		}
	}
}

/**
 * Load DES (picture container) file
 * @remarks	Originally called 'chardes'
 */
void TextHandler::loadPictureFile(const Common::Path &filename, const Common::Path &altFilename, int32 skipSize, int length) {
	Common::File f;
	if (!f.open(filename)) {
		if (!f.open(altFilename))
			error("Missing file: Either %s or %s", filename.toString().c_str(), altFilename.toString().c_str());
	}
	// HACK: The original game contains a bug in the 2nd intro screen, in German DOS version.
	// The size specified in the fxx array is wrong (too short). In order to fix it, we are using
	// the value -1 to force a variable read length.
	if (length == -1)
		length = f.size() - skipSize;

	assert(skipSize + length <= f.size());

	free(_vm->_curPict);
	_vm->_curPict = (byte *)malloc(sizeof(byte) * length);
	f.seek(skipSize);
	f.read(_vm->_curPict, length);
	f.close();
}

/**
 * Load ANI file
 * @remarks	Originally called 'charani'
 */
void TextHandler::loadAniFile(const Common::Path &filename, int32 skipSize, int length) {
	Common::File f;
	if (!f.open(filename))
		error("Missing file - %s", filename.toString().c_str());

	assert(skipSize + length <= f.size());

	free(_vm->_curAnim);
	_vm->_curAnim = (byte *)malloc(sizeof(byte) * length);
	f.seek(skipSize);
	f.read(_vm->_curAnim, length);
	f.close();
}

void TextHandler::taffich() {
	static const byte tran1[] = { 121, 121, 138, 139, 120 };
	static const byte tran2[] = { 150, 150, 152, 152, 100, 110, 159, 100, 100 };

	int cx, drawingSize, npal;
	int32 drawingStartPos;

	int a = _vm->_caff;
	if ((a >= 153) && (a <= 161))
		a = tran2[a - 153];
	else if ((a >= 136) && (a <= 140))
		a = tran1[a - 136];
	int b = a;
	if (_vm->_maff == a)
		return;

	switch (a) {
	case 16:
		_vm->_coreVar._pctHintFound[9] = '*';
		_vm->_coreVar._availableQuestion[42] = '*';
		break;
	case 20:
		_vm->_coreVar._availableQuestion[39] = '*';
		if (_vm->_coreVar._availableQuestion[36] == '*') {
			_vm->_coreVar._pctHintFound[3] = '*';
			_vm->_coreVar._availableQuestion[38] = '*';
		}
		break;
	case 24:
		_vm->_coreVar._availableQuestion[37] = '*';
		break;
	case 30:
		_vm->_coreVar._availableQuestion[9] = '*';
		break;
	case 31: // Coat of arms
		_vm->_coreVar._pctHintFound[4] = '*';
		_vm->_coreVar._availableQuestion[35] = '*';
		break;
	case 118:
		_vm->_coreVar._availableQuestion[41] = '*';
		break;
	case 143:
		_vm->_coreVar._pctHintFound[1] = '*';
		break;
	case 150:
		_vm->_coreVar._availableQuestion[34] = '*';
		break;
	case 151:
		_vm->_coreVar._pctHintFound[2] = '*';
		break;
	default:
		break;
	}

	_vm->_destinationOk = true;
	_vm->_mouse->hideMouse();
	drawingStartPos = 0;
	Common::Path filename, altFilename;

	if ((a != 50) && (a != 51)) {
		int m = a + 2000;

		if ((m > 2001) && (m < 2010))
			m = 2001;
		else if (m == 2011)
			m = 2010;
		if (a == 32)
			m = 2034;
		else if ((a == 17) && (_vm->_maff == 14))
			m = 2018;
		else if (a > 99) {
			if ((_vm->_is == 1) || (_vm->_is == 0))
				m = 2031;
			else
				m = 2032;
		}

		if ( ((a > 69) && (a < 80)) || (a == 30) || (a == 31) || (a == 144) || (a == 147) || (a == 149) )
			m = 2030;
		else if ( ((a < 27) && ( ((_vm->_maff > 69) && (!_vm->_coreVar._alreadyEnteredManor)) || (_vm->_maff > 99) )) || ((_vm->_maff > 29) && (_vm->_maff < 33)) )
			m = 2033;

		_vm->displayInterScreenMessage(m);
		_vm->_maff = a;

		if (a == 159)
			a = 86;
		else if (a > 140)
			a -= 67;
		else if (a > 137)
			a -= 66;
		else if (a > 99)
			a -= 64;
		else if (a > 69)
			a -= 42;
		else if (a > 29)
			a -= 5;
		else if (a == 26)
			a = 24;
		else if (a > 18)
			--a;
		npal = a;

		for (cx = 0; cx <= (a - 1); ++cx)
			drawingStartPos += _vm->_drawingSizeArr[cx];
		drawingSize = _vm->_drawingSizeArr[a];

		altFilename = filename = "DXX.mor";
	} else {
		filename = "DZZ.mor";
		altFilename = "DZZALL";

		if (a == 50) {
			// First intro screen
			drawingStartPos = 0;
			drawingSize = _vm->_drawingSizeArr[87];
		} else { // a == 51
			// Second intro screen
			drawingStartPos = _vm->_drawingSizeArr[87];
			// HACK: Force a variable size in order to fix the wrong size used by the German version
			drawingSize = -1;
		}
		_vm->_maff = a;
		npal = a + 37;
	}
	loadPictureFile(filename, altFilename, drawingStartPos, drawingSize);
	_vm->_numpal = npal;
	_vm->setPal(npal);

	if ((b < 15) || (b == 16) || (b == 17) || (b == 24) || (b == 26) || (b == 50)) {
		drawingStartPos = 0;
		if ((b < 15) || (b == 16) || (b == 17) || (b == 24) || (b == 26)) {
			if (b == 26)
				b = 18;
			else if (b == 24)
				b = 17;
			else if (b > 15)
				--b;
			for (cx = 0; cx <= (b - 1); ++cx)
				drawingStartPos += _vm->_drawingSizeArr[cx + 89];
			drawingSize = _vm->_drawingSizeArr[b + 89];
			filename = "AXX.mor";
		} else { // b == 50
			// CHECKME: the size of AZZ.mor is 1280 for the DOS version
			//          and 1260 for the Amiga version. Maybe the 20 bytes
			//          are a filler (to get 10 blocks of 128 bytes),
			//          or the size should be variable.
			drawingSize = 1260;
			filename = "AZZ.mor";
		}
		loadAniFile(filename, drawingStartPos, drawingSize);
	}
	_vm->_mouse->showMouse();
	if ((a < COAT_ARMS) && ((_vm->_maff < COAT_ARMS) || (_vm->_coreVar._currPlace == LANDING)) && (_vm->_currAction != _vm->_menu->_opcodeEnter)) {
		if ((a == ATTIC) || (a == CELLAR))
			_vm->displayAloneText();
		else if (!_vm->_outsideOnlyFl)
			_vm->getPresence(_vm->_coreVar._currPlace);
		_vm->_savedBitIndex =  0;
	}
}

} // End of namespace Mortevielle
