/* 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/file.h"
#include "common/str.h"
#include "scumm/scumm.h"
#include "scumm/util.h"

#include "scumm/smush/smush_font.h"

namespace Scumm {

SmushFont::SmushFont(ScummEngine *vm, const char *filename, bool use_original_colors, bool new_colors) :
	NutRenderer(vm, filename),
	_color(-1),
	_new_colors(new_colors),
	_original(use_original_colors) {
}

int SmushFont::getStringWidth(const char *str) {
	assert(str);

	int width = 0;
	while (*str) {
		if (*str & 0x80 && _vm->_useCJKMode) {
			width += _vm->_2byteWidth + 1;
			str += 2;
		} else
			width += getCharWidth(*str++);
	}
	return width;
}

int SmushFont::getStringHeight(const char *str) {
	assert(str);

	int height = 0;
	while (*str) {
		int charHeight = getCharHeight(*str++);
		if (height < charHeight)
			height = charHeight;
	}
	return height;
}

int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) {
	int w = _chars[chr].width;
	int h = _chars[chr].height;
	const byte *src = unpackChar(chr);
	byte *dst = buffer + dst_width * y + x;

	assert(dst_width == _vm->_screenWidth);

	if (_original) {
		for (int j = 0; j < h; j++) {
			for (int i = 0; i < w; i++) {
				int8 value = *src++;
				if (value != _chars[chr].transparency)
					dst[i] = value;
			}
			dst += dst_width;
		}
	} else {
		char color = (_color != -1) ? _color : 1;
		if (_new_colors) {
			for (int j = 0; j < h; j++) {
				for (int i = 0; i < w; i++) {
					int8 value = *src++;
					if (value == -color) {
						dst[i] = 0xFF;
					} else if (value == -31) {
						dst[i] = 0;
					} else if (value != _chars[chr].transparency) {
						dst[i] = value;
					}
				}
				dst += dst_width;
			}
		} else {
			for (int j = 0; j < h; j++) {
				for (int i = 0; i < w; i++) {
					int8 value = *src++;
					if (value == 1) {
						dst[i] = color;
					} else if (value != _chars[chr].transparency) {
						dst[i] = 0;
					}
				}
				dst += dst_width;
			}
		}
	}
	return w;
}

int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
	int w = _vm->_2byteWidth;
	int h = _vm->_2byteHeight;
	const byte *src = _vm->get2byteCharPtr(idx);
	byte bits = 0;

	char color = (_color != -1) ? _color : 1;

	if (_new_colors)
		color = (char)0xff;

	if (_vm->_game.id == GID_FT)
		color = 1;

	enum ShadowMode {
		kNone,
		kNormalShadowMode,
		kKoreanV7ShadowMode,
		kKoreanV8ShadowMode
	};

	ShadowMode shadowMode = kNone;

	if (_vm->_language == Common::KO_KOR) {
		if (_vm->_game.version == 8)
			shadowMode = kKoreanV8ShadowMode;
		else
			shadowMode = kKoreanV7ShadowMode;
	}

	int shadowOffsetXTable[4] = {-1, 0, 1, 0};
	int shadowOffsetYTable[4] = {0, 1, 0, 0};
	int shadowOffsetColorTable[4] = {0, 0, 0, color};

	int shadowIdx = 3;
	if (shadowMode == kKoreanV8ShadowMode)
		shadowIdx = 0;
	else if (shadowMode == kKoreanV7ShadowMode)
		shadowIdx = 2;

	const byte *origSrc = src;

	for (; shadowIdx < 4; shadowIdx++) {
		int offX = x + shadowOffsetXTable[shadowIdx];
		int offY = y + shadowOffsetYTable[shadowIdx];
		byte drawColor = shadowOffsetColorTable[shadowIdx];

		src = origSrc;

		byte *dst = buffer + dst_width * (offY + (_vm->_game.id == GID_CMI ? 7 : (_vm->_game.id == GID_DIG ? 2 : 0))) + offX;

		for (int j = 0; j < h; j++) {
			for (int i = 0; i < w; i++) {
				if (offX + i < 0)
					continue;
				if ((i % 8) == 0)
					bits = *src++;
				if (bits & revBitMask(i % 8)) {
					if (shadowMode == kNormalShadowMode) {
						dst[i + 1] = 0;
						dst[dst_width + i] = 0;
						dst[dst_width + i + 1] = 0;
					}
					dst[i] = drawColor;
				}
			}
			dst += dst_width;
		}
	}
	return w + 1;
}

void SmushFont::drawSubstring(const char *str, byte *buffer, int dst_width, int x, int y) {
	// This happens in the Full Throttle intro. I don't know if our
	// text-drawing functions are buggy, or if this function is supposed
	// to have to check for it.
	if (x < 0)
		x = 0;

	for (int i = 0; str[i] != 0; i++) {
		if ((byte)str[i] >= 0x80 && _vm->_useCJKMode) {
			x += draw2byte(buffer, dst_width, x, y, (byte)str[i] + 256 * (byte)str[i+1]);
			i++;
		} else
			x += drawChar(buffer, dst_width, x, y, str[i]);
	}
}

#define MAX_WORDS	60


void SmushFont::drawString(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, bool center) {
	debugC(DEBUG_SMUSH, "SmushFont::drawString(%s, %d, %d, %d)", str, x, y, center);

	while (str) {
		char line[256];
		const char *pos = strchr(str, '\n');
		if (pos) {
			memcpy(line, str, pos - str - 1);
			line[pos - str - 1] = 0;
			str = pos + 1;
		} else {
			strcpy(line, str);
			str = 0;
		}
		drawSubstring(line, buffer, dst_width, center ? (x - getStringWidth(line) / 2) : x, y);
		y += getStringHeight(line);
	}
}

void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int dst_height, int x, int y, int left, int right, bool center) {
	debugC(DEBUG_SMUSH, "SmushFont::drawStringWrap(%s, %d, %d, %d, %d, %d)", str, x, y, left, right, center);

	const int width = right - left;
	Common::String s(str);
	char *words[MAX_WORDS];
	int word_count = 0;

	Common::String::iterator tmp = s.begin();
	while (tmp) {
		assert(word_count < MAX_WORDS);
		words[word_count++] = tmp;
		tmp = strpbrk(tmp, " \t\r\n");
		if (tmp == 0)
			break;
		*tmp++ = 0;
	}

	int i = 0, max_width = 0, height = 0, line_count = 0;

	char *substrings[MAX_WORDS];
	int substr_widths[MAX_WORDS];
	const int space_width = getCharWidth(' ');

	i = 0;
	while (i < word_count) {
		char *substr = words[i++];
		int substr_width = getStringWidth(substr);

		while (i < word_count) {
			int word_width = getStringWidth(words[i]);
			if ((substr_width + space_width + word_width) >= width)
				break;
			substr_width += word_width + space_width;
			*(words[i]-1) = ' ';	// Convert 0 byte back to space
			i++;
		}

		substrings[line_count] = substr;
		substr_widths[line_count++] = substr_width;
		if (max_width < substr_width)
			max_width = substr_width;
		height += getStringHeight(substr);
	}

	if (y > dst_height - height) {
		y = dst_height - height;
	}

	if (center) {
		max_width = (max_width + 1) / 2;
		x = left + width / 2;

		if (x < left + max_width)
			x = left + max_width;
		if (x > right - max_width)
			x = right - max_width;

		for (i = 0; i < line_count; i++) {
			drawSubstring(substrings[i], buffer, dst_width, x - substr_widths[i] / 2, y);
			y += getStringHeight(substrings[i]);
		}
	} else {
		if (x > dst_width - max_width)
			x = dst_width - max_width;

		for (i = 0; i < line_count; i++) {
			drawSubstring(substrings[i], buffer, dst_width, x, y);
			y += getStringHeight(substrings[i]);
		}
	}
}

} // End of namespace Scumm
