#!/usr/bin/env python3
# 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)
