/* 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 "sludge/allfiles.h"
#include "sludge/fonttext.h"
#include "sludge/graphics.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/sprites.h"
#include "sludge/sludge.h"
#include "sludge/version.h"

namespace Sludge {

TextManager::TextManager() {
	init();
}

TextManager::~TextManager() {
	kill();
}

void TextManager::init() {
	_theFont.total = 0;
	_theFont.sprites = nullptr;

	_fontHeight = 0;
	_numFontColours = 0;
	_loadedFontNum = 0;
	_fontSpace = -1;

	_pastePalette.init();
	_fontTable.clear();
}

void TextManager::kill() {
	GraphicsManager::forgetSpriteBank(_theFont);
	_pastePalette.kill();
}

bool TextManager::isInFont(const Common::String &theText) {
	if (_fontTable.empty())
		return 0;
	if (theText.empty())
		return 0;

	Common::U32String str32 = UTF8Converter::convertUtf8ToUtf32(theText);

	// We don't want to compare strings. Only single characters allowed!
	if (str32.size() > 1)
		return false;

	uint32 c = str32[0];

	// check if font order contains the utf8 char
	return _fontOrder.getU32String().contains(c);
}

int TextManager::stringLength(const Common::String &theText) {
	Common::U32String str32 = UTF8Converter::convertUtf8ToUtf32(theText);
	return str32.size();
}

int TextManager::stringWidth(const Common::String &theText) {
	int xOff = 0;

	if (_fontTable.empty())
		return 0;

	Common::U32String str32 = UTF8Converter::convertUtf8ToUtf32(theText);

	for (uint i = 0; i < str32.size(); ++i) {
		uint32 c = str32[i];
		xOff += _theFont.sprites[fontInTable(c)].surface.w + _fontSpace;
	}

	return xOff;
}

void TextManager::pasteString(const Common::String &theText, int xOff, int y, SpritePalette &thePal) {
	if (_fontTable.empty())
		return;

	xOff += (int)((float)(_fontSpace >> 1) / g_sludge->_gfxMan->getCamZoom());

	Common::U32String str32 = UTF8Converter::convertUtf8ToUtf32(theText);

	for (uint32 i = 0; i < str32.size(); ++i) {
		uint32 c = str32[i];
		Sprite *mySprite = &_theFont.sprites[fontInTable(c)];
		g_sludge->_gfxMan->fontSprite(xOff, y, *mySprite, thePal);
		xOff += (int)((double)(mySprite->surface.w + _fontSpace) / g_sludge->_gfxMan->getCamZoom());
	}
}

void TextManager::pasteStringToBackdrop(const Common::String &theText, int xOff, int y) {
	if (_fontTable.empty())
		return;

	Common::U32String str32 = UTF8Converter::convertUtf8ToUtf32(theText);

	xOff += _fontSpace >> 1;
	for (uint32 i = 0; i < str32.size(); ++i) {
		uint32 c = str32[i];
		Sprite *mySprite = &_theFont.sprites[fontInTable(c)];
		g_sludge->_gfxMan->pasteSpriteToBackDrop(xOff, y, *mySprite, _pastePalette);
		xOff += mySprite->surface.w + _fontSpace;
	}
}

void TextManager::burnStringToBackdrop(const Common::String &theText, int xOff, int y) {
	if (_fontTable.empty())
		return;

	Common::U32String str32 = UTF8Converter::convertUtf8ToUtf32(theText);

	xOff += _fontSpace >> 1;
	for (uint i = 0; i < str32.size(); ++i) {
		uint32 c = str32[i];
		Sprite *mySprite = &_theFont.sprites[fontInTable(c)];
		g_sludge->_gfxMan->burnSpriteToBackDrop(xOff, y, *mySprite, _pastePalette);
		xOff += mySprite->surface.w + _fontSpace;
	}
}

bool TextManager::loadFont(int filenum, const Common::String &charOrder, int h) {
	_fontOrder.setUTF8String(charOrder);

	g_sludge->_gfxMan->forgetSpriteBank(_theFont);

	_loadedFontNum = filenum;

	// get max value among all utf8 chars
	Common::U32String fontOrderString = _fontOrder.getU32String();

	// create an index table from utf8 char to the index
	if (!_fontTable.empty()) {
		_fontTable.clear();
	}

	for (uint i = 0; i < fontOrderString.size(); ++i) {
		uint32 c = fontOrderString[i];
		_fontTable[c] = i;
	}

	if (!g_sludge->_gfxMan->loadSpriteBank(filenum, _theFont, true)) {
		fatal("Can't load font");
		return false;
	}

	_numFontColours = _theFont.myPalette.total;
	_fontHeight = h;
	return true;
}

// load & save
void TextManager::saveFont(Common::WriteStream *stream) {
	stream->writeByte(!_fontTable.empty());
	if (!_fontTable.empty()) {
		stream->writeUint16BE(_loadedFontNum);
		stream->writeUint16BE(_fontHeight);
		writeString(_fontOrder.getUTF8String(), stream);
	}
	stream->writeSint16LE(_fontSpace);
}

void TextManager::loadFont(int ssgVersion, Common::SeekableReadStream *stream) {
	bool fontLoaded = stream->readByte();
	int fontNum = 0;
	Common::String charOrder = "";
	if (fontLoaded) {
		fontNum = stream->readUint16BE();
		_fontHeight = stream->readUint16BE();

		if (ssgVersion < VERSION(2, 2)) {
			char *tmp = new char[257];
			for (int a = 0; a < 256; a++) {
				int x = stream->readByte();
				tmp[x] = a;
			}
			tmp[256] = 0;
			charOrder = tmp;
			delete []tmp;
		} else {
			charOrder = readString(stream);
		}
	}
	loadFont(fontNum, charOrder, _fontHeight);

	_fontSpace = stream->readSint16LE();
}

} // End of namespace Sludge