
"""
Here is a few fonts availible on my computer

/Library/Fonts/Andale Mono.ttf
/Library/Fonts/Apple Chancery.ttf
/Library/Fonts/AppleGothic.ttf
/Library/Fonts/AppleMyungjo.ttf
/Library/Fonts/Arial Black.ttf
/Library/Fonts/Arial Narrow Bold Italic.ttf
/Library/Fonts/Arial Narrow Bold.ttf
/Library/Fonts/Arial Narrow Italic.ttf
/Library/Fonts/Arial Narrow.ttf
/Library/Fonts/Arial Rounded Bold.ttf
/Library/Fonts/Arial Unicode.ttf
/Library/Fonts/Ayuthaya.ttf
/Library/Fonts/BigCaslon.ttf
/Library/Fonts/Bodoni 72 Smallcaps Book.ttf
/Library/Fonts/Bodoni Ornaments.ttf
/Library/Fonts/Bradley Hand Bold.ttf
/Library/Fonts/Chalkduster.ttf
/Library/Fonts/Comic Sans MS Bold.ttf
/Library/Fonts/Comic Sans MS.ttf
/Library/Fonts/Courier New Bold Italic.ttf
/Library/Fonts/Courier New Bold.ttf
/Library/Fonts/Courier New Italic.ttf
/Library/Fonts/Courier New.ttf
/Library/Fonts/DIN Alternate Bold.ttf
/Library/Fonts/DIN Condensed Bold.ttf
/Library/Fonts/Diwan Thuluth.ttf
/Library/Fonts/Farisi.ttf
/Library/Fonts/Georgia Bold Italic.ttf
/Library/Fonts/Georgia Bold.ttf
/Library/Fonts/Georgia Italic.ttf
/Library/Fonts/Georgia.ttf
/Library/Fonts/Gungseouche.ttf
/Library/Fonts/Gurmukhi.ttf
/Library/Fonts/HeadlineA.ttf
/Library/Fonts/Herculanum.ttf
/Library/Fonts/Hoefler Text Ornaments.ttf
/Library/Fonts/Impact.ttf
/Library/Fonts/InaiMathi.ttf
/Library/Fonts/Khmer Sangam MN.ttf
/Library/Fonts/Kokonor.ttf
/Library/Fonts/Krungthep.ttf
/Library/Fonts/Lao Sangam MN.ttf
/Library/Fonts/Luminari.ttf
/Library/Fonts/Microsoft Sans Serif.ttf
/Library/Fonts/Mishafi Gold.ttf
/Library/Fonts/Mishafi.ttf
/Library/Fonts/NISC18030.ttf
/Library/Fonts/Osaka.ttf
/Library/Fonts/OsakaMono.ttf
/Library/Fonts/PCmyoungjo.ttf
/Library/Fonts/Pilgiche.ttf
/Library/Fonts/PlantagenetCherokee.ttf
/Library/Fonts/Sathu.ttf
/Library/Fonts/Silom.ttf
/Library/Fonts/Skia.ttf
/Library/Fonts/Tahoma Bold.ttf
/Library/Fonts/Tahoma.ttf
/Library/Fonts/Trattatello.ttf
/Library/Fonts/Trebuchet MS Bold Italic.ttf
/Library/Fonts/Trebuchet MS Bold.ttf
/Library/Fonts/Trebuchet MS Italic.ttf
/Library/Fonts/Trebuchet MS.ttf
/Library/Fonts/Webdings.ttf
/Library/Fonts/Zapfino.ttf
/Library/Fonts/儷宋 Pro.ttf
/Library/Fonts/儷黑 Pro.ttf
/Library/Fonts/华文仿宋.ttf
/Library/Fonts/华文细黑.ttf
/Library/Fonts/华文黑体.ttf
/Library/Fonts Disabled/Arial Bold Italic.ttf
/Library/Fonts Disabled/Arial Bold.ttf
/Library/Fonts Disabled/Arial Italic.ttf
/Library/Fonts Disabled/Arial.ttf
/Library/Fonts Disabled/Brush Script.ttf
/Library/Fonts Disabled/Times New Roman Bold Italic.ttf
/Library/Fonts Disabled/Times New Roman Bold.ttf
/Library/Fonts Disabled/Times New Roman Italic.ttf
/Library/Fonts Disabled/Times New Roman.ttf
/Library/Fonts Disabled/Verdana Bold Italic.ttf
/Library/Fonts Disabled/Verdana Bold.ttf
/Library/Fonts Disabled/Verdana Italic.ttf
/Library/Fonts Disabled/Verdana.ttf
/Library/Fonts Disabled/Wingdings 2.ttf
/Library/Fonts Disabled/Wingdings 3.ttf
/Library/Fonts Disabled/Wingdings.ttf
/Library/Fonts/Microsoft/Arial Bold Italic.ttf
/Library/Fonts/Microsoft/Arial Bold.ttf
/Library/Fonts/Microsoft/Arial Italic.ttf
/Library/Fonts/Microsoft/Arial.ttf
/Library/Fonts/Microsoft/Batang.ttf
/Library/Fonts/Microsoft/Bookshelf Symbol 7.ttf
/Library/Fonts/Microsoft/Brush Script.ttf
/Library/Fonts/Microsoft/Calibri Bold Italic.ttf
/Library/Fonts/Microsoft/Calibri Bold.ttf
/Library/Fonts/Microsoft/Calibri Italic.ttf
/Library/Fonts/Microsoft/Calibri.ttf
/Library/Fonts/Microsoft/Cambria Bold Italic.ttf
/Library/Fonts/Microsoft/Cambria Bold.ttf
/Library/Fonts/Microsoft/Cambria Italic.ttf
/Library/Fonts/Microsoft/Cambria Math.ttf
/Library/Fonts/Microsoft/Cambria.ttf
/Library/Fonts/Microsoft/Candara Bold Italic.ttf
/Library/Fonts/Microsoft/Candara Bold.ttf
/Library/Fonts/Microsoft/Candara Italic.ttf
/Library/Fonts/Microsoft/Candara.ttf
/Library/Fonts/Microsoft/Consolas Bold Italic.ttf
/Library/Fonts/Microsoft/Consolas Bold.ttf
/Library/Fonts/Microsoft/Consolas Italic.ttf
/Library/Fonts/Microsoft/Consolas.ttf
/Library/Fonts/Microsoft/Constantia Bold Italic.ttf
/Library/Fonts/Microsoft/Constantia Bold.ttf
/Library/Fonts/Microsoft/Constantia Italic.ttf
/Library/Fonts/Microsoft/Constantia.ttf
/Library/Fonts/Microsoft/Corbel Bold Italic.ttf
/Library/Fonts/Microsoft/Corbel Bold.ttf
/Library/Fonts/Microsoft/Corbel Italic.ttf
/Library/Fonts/Microsoft/Corbel.ttf
/Library/Fonts/Microsoft/Franklin Gothic Book Italic.ttf
/Library/Fonts/Microsoft/Franklin Gothic Book.ttf
/Library/Fonts/Microsoft/Franklin Gothic Medium Italic.ttf
/Library/Fonts/Microsoft/Franklin Gothic Medium.ttf
/Library/Fonts/Microsoft/Gabriola.ttf
/Library/Fonts/Microsoft/Gill Sans MT Bold Italic.ttf
/Library/Fonts/Microsoft/Gill Sans MT Bold.ttf
/Library/Fonts/Microsoft/Gill Sans MT Italic.ttf
/Library/Fonts/Microsoft/Gill Sans MT.ttf
/Library/Fonts/Microsoft/Gulim.ttf
/Library/Fonts/Microsoft/Lucida Console.ttf
/Library/Fonts/Microsoft/Lucida Sans Unicode.ttf
/Library/Fonts/Microsoft/Marlett.ttf
/Library/Fonts/Microsoft/Meiryo Bold Italic.ttf
/Library/Fonts/Microsoft/Meiryo Bold.ttf
/Library/Fonts/Microsoft/Meiryo Italic.ttf
/Library/Fonts/Microsoft/Meiryo.ttf
/Library/Fonts/Microsoft/MS Gothic.ttf
/Library/Fonts/Microsoft/MS Mincho.ttf
/Library/Fonts/Microsoft/MS PGothic.ttf
/Library/Fonts/Microsoft/MS PMincho.ttf
/Library/Fonts/Microsoft/MS Reference Sans Serif.ttf
/Library/Fonts/Microsoft/MS Reference Specialty.ttf
/Library/Fonts/Microsoft/Palatino Linotype Bold Italic.ttf
/Library/Fonts/Microsoft/Palatino Linotype Bold.ttf
/Library/Fonts/Microsoft/Palatino Linotype Italic.ttf
/Library/Fonts/Microsoft/Palatino Linotype.ttf
/Library/Fonts/Microsoft/Perpetua Bold Italic.ttf
/Library/Fonts/Microsoft/Perpetua Bold.ttf
/Library/Fonts/Microsoft/Perpetua Italic.ttf
/Library/Fonts/Microsoft/Perpetua.ttf
/Library/Fonts/Microsoft/PMingLiU.ttf
/Library/Fonts/Microsoft/SimSun.ttf
/Library/Fonts/Microsoft/Times New Roman Bold Italic.ttf
/Library/Fonts/Microsoft/Times New Roman Bold.ttf
/Library/Fonts/Microsoft/Times New Roman Italic.ttf
/Library/Fonts/Microsoft/Times New Roman.ttf
/Library/Fonts/Microsoft/Tw Cen MT Bold Italic.ttf
/Library/Fonts/Microsoft/Tw Cen MT Bold.ttf
/Library/Fonts/Microsoft/Tw Cen MT Italic.ttf
/Library/Fonts/Microsoft/Tw Cen MT.ttf
/Library/Fonts/Microsoft/Verdana Bold Italic.ttf
/Library/Fonts/Microsoft/Verdana Bold.ttf
/Library/Fonts/Microsoft/Verdana Italic.ttf
/Library/Fonts/Microsoft/Verdana.ttf
/Library/Fonts/Microsoft/Wingdings 2.ttf
/Library/Fonts/Microsoft/Wingdings 3.ttf
/Library/Fonts/Microsoft/Wingdings.ttf
/System/Library/Fonts/Apple Braille Outline 6 Dot.ttf
/System/Library/Fonts/Apple Braille Outline 8 Dot.ttf
/System/Library/Fonts/Apple Braille Pinpoint 6 Dot.ttf
/System/Library/Fonts/Apple Braille Pinpoint 8 Dot.ttf
/System/Library/Fonts/Apple Braille.ttf
/System/Library/Fonts/Apple Color Emoji.ttf
/System/Library/Fonts/Keyboard.ttf
/System/Library/Fonts/LastResort.ttf
/System/Library/Fonts/Symbol.ttf
/System/Library/Fonts/ZapfDingbats.ttf
"""


import glob
import pygame
from baopig.pybao.issomething import is_color
from pygame.locals import *
from baopig.ressources import *
from baopig.io import LOGGER
from baopig.ressources import ressources


class Font:

    def __init__(self,
        file=None,
        height=None,
        color=None,
        bold=None,
        italic=None,
        underline=None,
        text_owner=None
    ):

        if file is None: file = ressources.font.file
        if height is None: height = ressources.font.height
        if color is None: color = ressources.font.color

        assert file is None or isinstance(file, str)

        self._file = None
        self._filepath = None
        self._height = None
        self._ascent = None
        self._font = None
        self._color = None
        self._text_owner_wkref = (lambda: None) if text_owner is None else text_owner.get_weakref()

        self.config(file=file, height=height, color=color, bold=bold, italic=italic, underline=underline, update_owner=False)

        # for i in range(30):
        #     f = pygame.font.Font(self.file, i)
        #     print(i, f.size(" ")[1])

    def __str__(self):

        return f"Font(height:{self.height}, ascent:{self._ascent}, file={self.file})"
    __repr__ = __str__

    color = property(lambda self: self._color)
    file = property(lambda self: self._file)
    filepath = property(lambda self: self._filepath)
    height = property(lambda self: self._height)
    text_owner = property(lambda self: self._text_owner_wkref())

    def config(self, file=None, height=None, color=None, bold=None, italic=None, underline=None, update_owner=True):

        if file is not None:
            self._file = file

            if file == "monospace":
                file = "JetBrainsMono-Medium.ttf"
            elif not file.endswith(".ttf"):
                if file.count("."):
                    LOGGER.warning("Can only look for tff fonts, not " + file)
                    self._file = file = ressources.font.file
                else:
                    file += ".ttf"

            if file not in filepaths:
                # print("get_filepath(", file, end=") -> ", sep="")
                filepaths[file] = get_filepath(file)
                # print(filepaths[file])
            self._filepath = filepaths[file]

        if height is not None:
            assert height > 1, "A font height must be higher than 1"
            self._height = height
        if file is not None or height is not None:

            """if self.height in _all[file]._fonts:
                ascent = _all[file].get_font(self.height)._ascent
            else:
                ascent = self.height
                all_from_file = _all[self.file]

                little_brother = self.height - 1
                if not all_from_file._fonts:
                    little_brother = 0
                while little_brother > 0 and little_brother not in all_from_file._fonts:
                    little_brother -= 1
                if little_brother > 0:
                    ascent = all_from_file.get_font(little_brother)._ascent

                elif all_from_file._fonts and little_brother == 0:
                    big_brother = self.height + 1
                    while big_brother not in all_from_file._fonts:
                        big_brother += 1
                    ascent = all_from_file.get_font(big_brother)._ascent
                    while height < all_from_file.get_font(ascent=ascent).size("")[1]:
                    while height < pygame.font.Font(self.font, ascent).size("")[1]:
                        ascent -= 1
                        if ascent <= 0:
                            raise PermissionError("Too small value for font height : " + str(self.height))

                while self.height < pygame.font.Font(self.file, ascent).size("")[1]:
                    ascent -= 1
                while self.height > pygame.font.Font(self.file, ascent).size("")[1]:
                    ascent += 1
                if ascent <= 0:
                    raise PermissionError("Too small value for font height : " + str(self.height))
                
            self._ascent = ascent
            self._font = pygame.font.Font(self.file, self._ascent)"""

            self._font = _all[self.filepath].get_font(height=self.height)
            self._ascent = self._font.get_ascent()

        if color is not None:
            try:               color = pygame.Color(color)
            except ValueError: color = pygame.Color(*color)
            self._color = color
        if bold is not None:
            self._font.set_bold(bold)
        if italic is not None:
            self._font.set_italic(italic)
        if underline is not None:
            self._font.set_underline(underline)

        if update_owner and self.text_owner is not None:
            self.text_owner.set_text(self.text_owner.text)

    def copy(self, text_owner=None):

        return Font(
            file=self.file,
            height=self.height,
            color=self.color,
            bold=self._font.get_bold(),
            italic=self._font.get_italic(),
            underline=self._font.get_underline(),
            text_owner=text_owner
        )

    def get_width(self, text):

        return self._font.size(text)[0]

    def render(self, text, background_color=None):

        assert background_color is None or len(background_color) == 3, \
            "Don't like rendering a text with a transparent background color"

        rendering = self._font.render(text, 1, self._color, background_color)
        if rendering.get_height() != self._height:
            assert rendering.get_height() > self._height
            rendering = rendering.subsurface((0, 0, rendering.get_width(), self._height)).copy()
        return rendering


# NOTE : use TypedDict(pygame.font.Font)
class _Fonts:
    """
    Pour plus de clarte, il a ete decide que Font(30) cree une ploice de taille 30
    En effet, pygame.font.Font(30) cree une police de hauteur 21
    Afin de trouver efficacement quelle valeur faut-il donner à pygame.font.Font
    pour obtenir une police de taille 30, on enregistre les polices auparavent crees
    dans _fonts

    Exemple :

    """

    def __init__(self, filepath):

        if filepath == "default":
            filepath = None
        pygame.font.init()
        self._fonts = {}
        self._fonts_by_ascent = {}
        self._filepath = filepath

    def get_font(self, height=None, ascent=None):
        """
        Methode qui renvoie une police de hauteur 'height' en pixels ou une police cree
        avec la hauteur bizarre de pygame, appelee ici 'ascent'
        """
        if ascent is None:
            assert isinstance(height, int), "height must be an integer (it's a font size)"
            assert height > 0, "A text must have a positive height"

            try:
                # Si le dictionnaire des polices contient deja la taille de police demandee
                return self._fonts[height]
            except KeyError:
                pass

            # Sinon on l'ajoute au dictionnaire
            ascent = height

            while height < self.get_font(ascent=ascent).get_height():
                ascent -= 1
            while height > self.get_font(ascent=ascent).get_height():
                ascent += 1
            if ascent <= 0:
                raise PermissionError("Too small value for font height : " + str(height))

            try:
                # Si le dictionnaire des polices contient deja la taille de police demandee
                return self._fonts[height]
            except KeyError:
                pass

            if self.get_font(ascent=ascent).get_height() < height:
                # print(self._fonts, self.get_font(ascent=ascent).get_height(), height)
                raise AssertionError
            slightly_higher_font = self.get_font(ascent=ascent)
            for i in range(self.get_font(ascent=ascent).get_height() - height):
                self._fonts[height+i+1] = slightly_higher_font
            self._fonts_by_ascent[ascent] = slightly_higher_font
            return slightly_higher_font

        else:
            assert height is None

            try:
                # Si le dictionnaire des polices contient deja la taille de police demandee
                return self._fonts_by_ascent[ascent]
            except KeyError:
                pass

            new_font = pygame.font.Font(self._filepath, ascent)
            self._fonts[new_font.get_height()] = new_font
            self._fonts_by_ascent[ascent] = new_font
            return new_font


class _All(dict):
    def __getitem__(self, filepath):
        if filepath not in self:
            self[filepath] = _Fonts(filepath)
        return super().__getitem__(filepath)
_all = _All()


def get_filepath(file):
    import os
    exec_dir = os.getcwd()
    for path in glob.iglob(exec_dir + "/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob(exec_dir + "/*/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob(exec_dir + "/*/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob(exec_dir + "/*/*/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob(__file__[:-7] + "lib/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob(__file__[:-7] + "lib/*/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob(__file__[:-7] + "lib/*/*/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob("/System/Library/Fonts/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob("/System/Library/Fonts/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob("/Library/Fonts/Microsoft/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob("/Library/Fonts Disabled/*.ttf"):
        if path.endswith(file): return path
    for path in glob.iglob("/Library/Fonts/*.ttf"):
        if path.endswith(file): return path
    LOGGER.warning("Font not found : {} (the font {} will be used instaed)".format(file, ressources.font.file))


filepaths = {}


if __name__ == "__main__":
    import os
    exec_dir = os.getcwd()
    for path in glob.iglob(__file__[:-7] + "lib/*.ttf"):
        print(path)
    for path in glob.iglob(__file__[:-7] + "lib/*/*.ttf"):
        print(path)
    for path in glob.iglob(__file__[:-7] + "lib/*/*/*.ttf"):
        print(path)
    for path in glob.iglob("/System/Library/Fonts/*.ttf"):
        print(path)
    for path in glob.iglob("/System/Library/Fonts/*.ttf"):
        print(path)
    for path in glob.iglob("/Library/Fonts/Microsoft/*.ttf"):
        print(path)
    for path in glob.iglob("/Library/Fonts Disabled/*.ttf"):
        print(path)
    for path in glob.iglob("/Library/Fonts/*.ttf"):
        print(path)

    h = 100
    font = Font('monospace', height=h)
    assert font.height == h == font._font.get_height()
    print(font)
