module coneneko.font;
import
	std.string,
	coneneko.image,
	sdl,
	sdl_ttf;

extern (C) int TTF_WasInit();

private string getSdlError()
{
	return std.string.toString(SDL_GetError());
}

///
class Font
{
	private const DEFAULT_FILE_NAME = `C:\WINDOWS\Fonts\msgothic.ttc`;
	private const DEFAULT_SIZE = 32;
	private static Font defaultInstance;
	
	static Font getDefault() ///
	{
		if (!defaultInstance) defaultInstance = new Font(DEFAULT_FILE_NAME, DEFAULT_SIZE);
		return defaultInstance;
	}
	
	static void setDefault(Font font) ///
	{
		delete defaultInstance;
		defaultInstance = font;
	}
	
	static ~this()
	{
		delete defaultInstance;
		TTF_Quit();
	}
	
	private TTF_Font* handle;
	
	///
	this(string ttfFileName, uint fontSize)
	{
		if (!TTF_WasInit()) TTF_Init();
		handle = TTF_OpenFont(cast(char*)ttfFileName.toStringz(), fontSize); // d2
	}
	
	/// リソース開放
	~this()
	{
		TTF_CloseFont(cast(TTF_Font*)handle);
	}
	
	uint height() ///
	{
		return TTF_FontHeight(cast(TTF_Font*)handle);
	}
	
	void computeSize(string text, out int width, out int height) ///
	{
		auto r = TTF_SizeUTF8(handle, cast(char*)text.toStringz(), &width, &height); // d2
		if (r == -1) throw new Error("Font.computeSize:" ~ text ~ " " ~ getSdlError());
	}
	
	uint[] createTextImage(string text, ubyte r, ubyte g, ubyte b, ubyte a) ///
	{
		SDL_Surface* textSurface;
		try
		{
			textSurface = TTF_RenderUTF8_Blended(
				handle, cast(char*)text.toStringz(), sdlColor(r, g, b, a)
			); // d2
		}
		catch (Object e)
		{
			// 時々作成に失敗するらしい、原因はよくわからない
			throw new Error(
				"Font.createTextImage:" ~ text ~ " " ~ getSdlError()
				~ " failed TTF_RenderUTF8_Blended"
			);
		}
		if (!textSurface) throw new Error("Font.createTextImage:" ~ text ~ " " ~ getSdlError());
		
		uint[] result = createRgba32Pixels(textSurface);
		SDL_FreeSurface(textSurface);
		return result;
	}
	
	private static SDL_Color sdlColor(ubyte r, ubyte g, ubyte b, ubyte a)
	{
		SDL_Color result;
		result.r = r;
		result.g = g;
		result.b = b;
		result.unused = a;
		return result;
	}
	
	string[] splitLimit(string text, uint widthLimit) ///
	{
		string[] result;
		int b, e;
		while (b < text.length)
		{
			while (e < text.length)
			{
				int w, h;
				computeSize(text[b..e + 1], w, h);
				if (widthLimit < w) break;
				e++;
			}
			result ~= text[b..e];
			b = e;
		}
		return result;
	}
}
