#!/usr/bin/env python
# SPDX-License-Identifier: BSD-3-Clause
#
# Script to generate menu and intermission screen 'text' graphics for
# Freedoom, by compositing individual font character graphics together.
#

from PIL import Image
from glob import glob
import re
import sys

from config import *
from image_dimensions import *
from tint import image_tint



class TextGenerator(object):
	def __init__(self, fontdir, kerning_table={}):
		self.fontdir = fontdir
		self.kerning_table = self.compile_kerning_table(kerning_table)
		self.get_font_widths()

	# Tinting parameters for colorizing text:
	COLOR_BLUE = "#000001"
	COLOR_RED = "#010000"
	COLOR_WHITE = None

	# Height of font in pixels.
	FONT_HEIGHT = 15
	FONT_LC_HEIGHT = 15  # 12

	# If true, the font only has uppercase characters.
	UPPERCASE_FONT = False

	# Width of a space character in pixels.
	SPACE_WIDTH = 7
	LOWERCASE_RE = re.compile(r'^[a-z\!\. ]*$')

	def compile_kerning_table(self, kerning_table):
		"""Given a dictionary of kerning patterns, compile Regexps."""

		result = {}
		for pattern, adjust in kerning_table.items():
			result[re.compile(pattern)] = adjust
		return result

	def get_font_widths(self):
		charfiles = glob('%s/font*.png' % self.fontdir)
		self.char_widths = {}
		for c in range(128):
			filename = self.char_filename(chr(c))
			if filename not in charfiles:
				continue
			w, _ = get_image_dimensions(filename)
			self.char_widths[chr(c)] = w

	def __contains__(self, c):
		return c in self.char_widths

	def char_width(self, c):
		return self.char_widths[c]

	def char_filename(self, c):
		return '%s/font%03d.png' % (self.fontdir, ord(c))

	def kerning_adjust(self, char_1, char_2):
		"""Get kerning adjustment for pair of characters.

		Zero means no adjustment. A negative value adjusts to the
		left and a positive value adjusts to the right.
		"""
		for pattern, adjust in self.kerning_table.items():
			if pattern.match(char_1 + char_2):
				return adjust
		else:
			return 0

	def iterate_char_positions(self, text):
		"""Iterate over characters in string, yielding character with
		   position it should be placed at in the output file.
		"""
		x = 0
		last_c = ' '
		for c in text:
			if c == ' ':
				x += self.SPACE_WIDTH

			if c in self:
				x += self.kerning_adjust(last_c, c)

				yield c, x

				# Characters overlap by one pixel.
				x += self.char_width(c) - 1

			last_c = c

		# We need to add back the missing pixel from the right side
		# of the last char.
		x += 1
		yield None, x

	def text_width(self, text):
		"""Given a string of text, get text width in pixels."""
		for c, x in self.iterate_char_positions(text):
			if c is None:
				return x

	def generate_graphic(self, text, color=None):
		"""Get command to render text to a file
		   with the given background color.
		"""

		if self.UPPERCASE_FONT:
			text = text.upper()
		"""Command line construction helper, used in render functions"""
		width = self.text_width(text)

		if self.LOWERCASE_RE.match(text):
			height = self.FONT_LC_HEIGHT
		else:
			height = self.FONT_HEIGHT

		txt_image = Image.new("RGBA", (width, height), (0, 0, 0, 0))
		for c, x in self.iterate_char_positions(text):
			if c is None:
				break

			filename = self.char_filename(c)
			char_image = Image.open(filename)
			char_image.load()
			int_image = Image.new("RGBA", txt_image.size, (0, 0, 0, 0))
			int_image.paste(char_image, (x, height - self.FONT_HEIGHT))
			txt_image = Image.alpha_composite(txt_image, int_image)

		txt_image = image_tint(txt_image, color)
		return txt_image


def generate_graphics(font, graphics, color=None):
	for name, text in sorted(graphics.items()):
		# write a makefile fragment
		target = '%s.png' % name
		image = font.generate_graphic(text, color=color)
		image.save(target)


def generate_kerning_test(font):
	pairs = []
	for c1 in sorted(font.char_widths):
		char1 = "%c" % c1
		for c2 in sorted(font.char_widths):
			char2 = "%c" % c2
			if font.kerning_adjust(char1, char2) != 0:
				pairs.append(char1 + char2)

	cmd = font.generate_graphic(" ".join(pairs), "kerning.png")

if __name__ == '__main__':

	font = TextGenerator('fontchars', kerning_table=FONT_KERNING_RULES)
	generate_graphics(font, red_graphics, color=font.COLOR_RED)
	generate_graphics(font, blue_graphics, color=font.COLOR_BLUE)
	generate_graphics(font, white_graphics, color=font.COLOR_WHITE)
