"""Writes what three font files state about themselves: DejaVu Sans and Spectral, whose
outlines are quadratic, and IBM Plex Sans, whose outlines are cubic.

The Python twin of the `write_font_facts` example in Rust: the same page, through the
binding rather than through the library directly.

Each face is read from its file by the family the file names, and set once in its own
letters; under it, lines say what the file states: the names it goes by and how its
outlines are stored, how many units make its em and how many glyphs it holds, its
traits, where it rises and falls, where its underline goes, what its own flag allows of
embedding it, which code pages it claims, and how one glyph and one line measure across
and down the page. Not one of those figures is written by hand.

The last lines add one file twice, once to set across and once to set down the page, and
say how this document treats a font whose own flag forbids embedding it.

The words are held in `Words`, once per language, and `HQF_PDF_LANG` picks which set the
page is written in.

Usage: python examples/write_font_facts.py [out.pdf]
       HQF_PDF_LANG=fr python examples/write_font_facts.py
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# Where the fonts the page reads are committed.
FONTS = _out.ROOT / "crates" / "hqf-pdf" / "tests" / "fonts"

# The three files the page reads, in the order it reads them.
FILES = ("DejaVuSans.ttf", "IBMPlexSans-Regular.otf", "Spectral-Regular.ttf")

# The line each face is measured on, the same in every language.
SAMPLE = "Façade 2026"

# How far in from the left edge of the sheet everything starts, in points.
LEFT = 56.0

# How wide the lines run, in points.
WIDTH = 483.0

# The size the facts are set at, in points.
FACTS = 8.5


@dataclass(frozen=True)
class Words:
    """Every word the page says, in one language."""

    # The heading, and what the file says of itself.
    title: str
    # What the page says under its heading.
    lead: str
    # What a face is called and how it is stored; `{postscript}`, `{family}`,
    # `{outlines}`, `{units}` and `{glyphs}` stand for them.
    identity: str
    # How the outlines are stored: quadratic, then cubic.
    outlines: tuple[str, str]
    # The traits a face has; `{traits}` stands for them.
    traits: str
    # The five traits: serifs, one width, bold, italic, a symbol encoding.
    trait_names: tuple[str, str, str, str, str]
    # What a face with none of the five is said to have, and what a symbol code reaching
    # nothing is said to reach.
    none: str
    # What a figure the file does not state, or a glyph it does not name, is said to be.
    unknown: str
    # Where a face rises and falls at 10 points; `{ascent}`, `{descent}`, `{cap}`,
    # `{x}`, `{gap}`, `{slant}` and `{bbox}` stand for them.
    heights: str
    # Where the underline goes; `{position}`, `{thickness}` and `{stated}` stand for
    # them.
    underline: str
    # What the file states of its underline; `{position}` and `{thickness}` stand for
    # the two figures in units.
    stated: str
    # What a file stating nothing of its underline is said to state.
    unstated: str
    # What the font's flag allows; `{embedding}`, `{subsetting}` and `{bitmap}` stand
    # for them.
    permissions: str
    # The four things the flag may say of embedding.
    embeddings: tuple[str, str, str, str]
    # Whether the font may be cut down: yes, then no.
    subsetting: tuple[str, str]
    # Whether only its bitmaps may be carried: no, then yes.
    bitmap: tuple[str, str]
    # The code pages a face claims; `{pages}` stands for them.
    code_pages: str
    # How one glyph and the sample measure; `{across}`, `{down}`, `{drawn}`, `{sample}`,
    # `{count}`, `{width}` and `{height}` stand for them.
    measures: str
    # Whether the face states how its glyphs advance down the page: yes, then no.
    vertical: tuple[str, str]
    # What reading code 0x41 as a symbol font reaches; `{symbol}` stands for it.
    symbol: str
    # The variation selectors a face names sequences for, and the glyph a zero followed
    # by the first of them draws; `{count}` and `{variant}` stand for them.
    selectors: str
    # The last lines: one file added twice; `{first}` and `{second}` stand for the two
    # ways.
    twice: str
    # The two ways a font sets its text: across, then down the page.
    writings: tuple[str, str]
    # What this document does with a font whose flag forbids embedding it; `{policy}`
    # stands for it.
    policy: str
    # The three things it may do: carry it and name it, leave it out, refuse the
    # document.
    policies: tuple[str, str, str]
    # The character separating the whole part of a figure from its tenths.
    decimal: str


# The page in English.
ENGLISH = Words(
    title="What a font file states about itself",
    lead=(
        "Three faces read from their files. Each is set once in its own letters, and "
        "under it every figure is read out of the file, none written by hand."
    ),
    identity=(
        "{postscript}, of the family {family}: {outlines}; {units} units to the em; "
        "{glyphs} glyphs."
    ),
    outlines=(
        "quadratic outlines, a TrueType font",
        "cubic outlines, an OpenType font with CFF outlines",
    ),
    traits="Traits: {traits}.",
    trait_names=(
        "serifs",
        "one width for every glyph",
        "bold",
        "italic",
        "a symbol encoding",
    ),
    none="none",
    unknown="not stated",
    heights=(
        "At 10 pt it rises {ascent} and falls {descent}; capitals: {cap}; lower case: "
        "{x}; it asks {gap} between lines; it slants {slant}°; every glyph stands "
        "within [{bbox}] units."
    ),
    underline=(
        "An underline at 10 pt sits {position} pt from the baseline, {thickness} pt "
        "thick; the file states {stated}."
    ),
    stated="{position} and {thickness} units",
    unstated="nothing of it",
    permissions="Its own flag: {embedding}; {subsetting}; {bitmap}.",
    embeddings=(
        "it may be embedded and installed",
        "it must not be embedded without its owner's leave",
        "it may be embedded to view and print the document",
        "it may be embedded and the document edited",
    ),
    subsetting=(
        "it may be cut down",
        "it must be carried whole",
    ),
    bitmap=(
        "its outlines may be carried",
        "only its bitmaps may be carried",
    ),
    code_pages="Code pages it claims: {pages}.",
    measures=(
        "W advances {across} units across and {down} down the page; the glyph named "
        "Eacute: {drawn}; “{sample}” takes {count} glyphs, runs {width} pt at 10 pt "
        "and {height} pt down the page."
    ),
    vertical=(
        "it states how far each glyph advances down the page",
        "it states nothing of setting down the page",
    ),
    symbol="Read as a symbol font, code 0x41: {symbol}.",
    selectors=(
        "Variation selectors it names sequences for: {count}; a zero followed by "
        "U+FE00: {variant}."
    ),
    twice="The first file is added twice, {first} and {second}.",
    writings=(
        "to set across the page",
        "to set down the page",
    ),
    policy=(
        "This document is told to {policy} a font whose own flag forbids embedding it."
    ),
    policies=(
        "carry, and name in a warning,",
        "leave out",
        "refuse the document over",
    ),
    decimal=".",
)

# The page in French.
FRENCH = Words(
    title="Ce qu’un fichier de police dit de lui-même",
    lead=(
        "Trois polices lues dans leurs fichiers. Chacune s’affiche une fois avec ses "
        "propres caractères ; en dessous, chaque valeur est lue dans le fichier, aucune "
        "n’est saisie à la main."
    ),
    identity=(
        "{postscript}, de la famille {family} : {outlines} ; {units} unités par "
        "cadratin ; {glyphs} glyphes."
    ),
    outlines=(
        "contours quadratiques, une police TrueType",
        "contours cubiques, une police OpenType à contours CFF",
    ),
    traits="Traits : {traits}.",
    trait_names=(
        "empattements",
        "une même chasse pour tous les glyphes",
        "grasse",
        "italique",
        "un encodage de symboles",
    ),
    none="aucun",
    unknown="non indiqué",
    heights=(
        "À 10 pt elle monte de {ascent} et descend de {descent} ; capitales : {cap} ; "
        "bas de casse : {x} ; elle demande {gap} entre les lignes ; elle penche de "
        "{slant}° ; tout glyphe tient dans [{bbox}] unités."
    ),
    underline=(
        "À 10 pt, le soulignement se place à {position} pt de la ligne de base, épais "
        "de {thickness} pt ; ce qu’en dit le fichier : {stated}."
    ),
    stated="{position} et {thickness} unités",
    unstated="rien",
    permissions="Son indicateur de droits : {embedding} ; {subsetting} ; {bitmap}.",
    embeddings=(
        "elle peut être incorporée et installée",
        "elle ne doit pas être incorporée sans l’accord de son propriétaire",
        "elle peut être incorporée pour afficher et imprimer le document",
        "elle peut être incorporée et le document modifié",
    ),
    subsetting=(
        "elle peut être incorporée en sous-ensemble",
        "elle doit être incorporée entière",
    ),
    bitmap=(
        "ses contours peuvent être incorporés",
        "seules ses images matricielles peuvent être incorporées",
    ),
    code_pages="Pages de code qu’elle déclare : {pages}.",
    measures=(
        "W avance de {across} unités en largeur et de {down} en hauteur ; le glyphe "
        "nommé Eacute : {drawn} ; « {sample} » prend {count} glyphes, mesure "
        "{width} pt à 10 pt et {height} pt de haut en bas."
    ),
    vertical=(
        "elle indique de combien chaque glyphe avance de haut en bas",
        "elle ne dit rien de la composition de haut en bas",
    ),
    symbol="Lue comme une police de symboles, code 0x41 : {symbol}.",
    selectors=(
        "Sélecteurs de variante pour lesquels elle nomme des séquences : {count} ; un "
        "zéro suivi de U+FE00 : {variant}."
    ),
    twice="Le premier fichier est ajouté deux fois, {first} et {second}.",
    writings=(
        "pour composer en largeur",
        "pour composer de haut en bas",
    ),
    policy=(
        "Ce document a pour consigne de {policy} une police dont l’indicateur interdit "
        "l’incorporation."
    ),
    policies=(
        "quand même incorporer, en la nommant dans un avertissement,",
        "laisser de côté",
        "refuser le document pour",
    ),
    decimal=",",
)

# The page in Dutch.
DUTCH = Words(
    title="Wat een lettertypebestand over zichzelf zegt",
    lead=(
        "Drie letters, gelezen uit hun bestanden. Elk wordt één keer in de eigen "
        "letters gezet, en eronder wordt elk getal uit het bestand gelezen, geen "
        "enkel met de hand geschreven."
    ),
    identity=(
        "{postscript}, uit de familie {family}: {outlines}; {units} eenheden per em; "
        "{glyphs} glyphs."
    ),
    outlines=(
        "kwadratische contouren, een TrueType-lettertype",
        "kubische contouren, een OpenType-lettertype met CFF-contouren",
    ),
    traits="Kenmerken: {traits}.",
    trait_names=(
        "schreven",
        "één breedte voor elke glyph",
        "vet",
        "cursief",
        "een symboolcodering",
    ),
    none="geen",
    unknown="niet vermeld",
    heights=(
        "Op 10 pt stijgt het {ascent} en daalt het {descent}; hoofdletters: {cap}; "
        "kleine letters: {x}; het vraagt {gap} tussen regels; het helt {slant}°; elke "
        "glyph valt binnen [{bbox}] eenheden."
    ),
    underline=(
        "Een onderstreping op 10 pt ligt {position} pt van de basislijn, {thickness} "
        "pt dik; het bestand vermeldt {stated}."
    ),
    stated="{position} en {thickness} eenheden",
    unstated="niets daarvan",
    permissions="Eigen vlag: {embedding}; {subsetting}; {bitmap}.",
    embeddings=(
        "het mag ingesloten en geïnstalleerd worden",
        "het mag niet ingesloten worden zonder toestemming van de eigenaar",
        "het mag ingesloten worden om het document te bekijken en af te drukken",
        "het mag ingesloten worden en het document bewerkt",
    ),
    subsetting=(
        "het mag worden ingekort",
        "het moet in zijn geheel worden ingesloten",
    ),
    bitmap=(
        "de contouren mogen worden ingesloten",
        "alleen de bitmaps mogen worden ingesloten",
    ),
    code_pages="Codetabellen die het opgeeft: {pages}.",
    measures=(
        "W schuift {across} eenheden naar rechts en {down} omlaag; de glyph Eacute: "
        "{drawn}; „{sample}” neemt {count} glyphs, loopt {width} pt op 10 pt en "
        "{height} pt omlaag."
    ),
    vertical=(
        "het zegt hoe ver elke glyph omlaag opschuift",
        "het zegt niets over zetten langs de pagina omlaag",
    ),
    symbol="Gelezen als symboollettertype, code 0x41: {symbol}.",
    selectors=(
        "Variatiekiezers waarvoor het reeksen noemt: {count}; een nul gevolgd door "
        "U+FE00: {variant}."
    ),
    twice="Het eerste bestand wordt twee keer toegevoegd, {first} en {second}.",
    writings=(
        "om horizontaal te zetten",
        "om verticaal te zetten",
    ),
    policy=(
        "Voor een lettertype waarvan de eigen vlag insluiten verbiedt, krijgt dit document de opdracht: {policy}."
    ),
    policies=(
        "insluiten, en in een waarschuwing noemen",
        "weglaten",
        "het document weigeren",
    ),
    decimal=".",
)

# The page in Portuguese.
PORTUGUESE = Words(
    title="O que um ficheiro de tipo de letra diz de si mesmo",
    lead=(
        "Três tipos lidos dos seus ficheiros. Cada um é composto uma vez nas suas "
        "próprias letras, e por baixo cada número é lido do ficheiro, nenhum escrito "
        "à mão."
    ),
    identity=(
        "{postscript}, da família {family}: {outlines}; {units} unidades por eme; "
        "{glyphs} glifos."
    ),
    outlines=(
        "contornos quadráticos, um tipo de letra TrueType",
        "contornos cúbicos, um tipo de letra OpenType com contornos CFF",
    ),
    traits="Características: {traits}.",
    trait_names=(
        "serifas",
        "a mesma largura para todos os glifos",
        "negrito",
        "itálico",
        "uma codificação de símbolos",
    ),
    none="nenhuma",
    unknown="não indicado",
    heights=(
        "A 10 pt sobe {ascent} e desce {descent}; maiúsculas: {cap}; minúsculas: {x}; "
        "pede {gap} entre linhas; inclina {slant}°; cada glifo cabe em [{bbox}] "
        "unidades."
    ),
    underline=(
        "Um sublinhado a 10 pt fica a {position} pt da linha de base, com {thickness} "
        "pt de espessura; o ficheiro indica {stated}."
    ),
    stated="{position} e {thickness} unidades",
    unstated="nada disso",
    permissions="O seu indicador: {embedding}; {subsetting}; {bitmap}.",
    embeddings=(
        "pode ser incorporado e instalado",
        "não deve ser incorporado sem autorização do titular dos direitos",
        "pode ser incorporado para ver e imprimir o documento",
        "pode ser incorporado e o documento editado",
    ),
    subsetting=(
        "pode ser reduzido a um subconjunto",
        "tem de ser levado inteiro",
    ),
    bitmap=(
        "os seus contornos podem ser levados",
        "só os seus bitmaps podem ser levados",
    ),
    code_pages="Páginas de código que declara: {pages}.",
    measures=(
        "W avança {across} unidades na largura e {down} para baixo; o glifo chamado "
        "Eacute: {drawn}; «{sample}» ocupa {count} glifos, mede {width} pt a 10 pt e "
        "{height} pt para baixo."
    ),
    vertical=(
        "indica quanto avança cada glifo para baixo",
        "não indica nada sobre compor para baixo",
    ),
    symbol="Lido como tipo de letra de símbolos, código 0x41: {symbol}.",
    selectors=(
        "Seletores de variante para os quais nomeia sequências: {count}; um zero "
        "seguido de U+FE00: {variant}."
    ),
    twice="O primeiro ficheiro é acrescentado duas vezes, {first} e {second}.",
    writings=(
        "para compor na largura",
        "para compor para baixo",
    ),
    policy=(
        "Pede-se a este documento que {policy} um tipo de letra cujo indicador proíbe incorporá-lo."
    ),
    policies=(
        "leve, e nomeie num aviso,",
        "omita",
        "recuse o documento por",
    ),
    decimal=".",
)

# The page in Italian.
ITALIAN = Words(
    title="Ciò che un file di font dice di sé",
    lead=(
        "Tre font letti dai loro file. Ciascuno è composto una volta nelle proprie "
        "lettere, e sotto ogni cifra è letta dal file, nessuna scritta a mano."
    ),
    identity=(
        "{postscript}, della famiglia {family}: {outlines}; {units} unità per em; "
        "{glyphs} glifi."
    ),
    outlines=(
        "contorni quadratici, un font TrueType",
        "contorni cubici, un font OpenType con contorni CFF",
    ),
    traits="Tratti: {traits}.",
    trait_names=(
        "grazie",
        "una larghezza per ogni glifo",
        "grassetto",
        "corsivo",
        "una codifica di simboli",
    ),
    none="nessuno",
    unknown="non indicato",
    heights=(
        "A 10 pt sale {ascent} e scende {descent}; maiuscole: {cap}; minuscole: {x}; "
        "chiede {gap} tra le righe; inclina di {slant}°; ogni glifo sta in [{bbox}] "
        "unità."
    ),
    underline=(
        "Una sottolineatura a 10 pt sta a {position} pt dalla linea di base, spessa "
        "{thickness} pt; il file indica {stated}."
    ),
    stated="{position} e {thickness} unità",
    unstated="nulla di ciò",
    permissions="Il suo indicatore: {embedding}; {subsetting}; {bitmap}.",
    embeddings=(
        "può essere incorporato e installato",
        "non deve essere incorporato senza il permesso del proprietario",
        "può essere incorporato per vedere e stampare il documento",
        "può essere incorporato e il documento modificato",
    ),
    subsetting=(
        "può essere ridotto",
        "va portato intero",
    ),
    bitmap=(
        "i suoi contorni possono essere portati",
        "solo le sue bitmap possono essere portate",
    ),
    code_pages="Pagine di codici che dichiara: {pages}.",
    measures=(
        "W avanza di {across} unità in larghezza e {down} in basso; il glifo chiamato "
        "Eacute: {drawn}; «{sample}» occupa {count} glifi, misura {width} pt a 10 pt "
        "e {height} pt in basso."
    ),
    vertical=(
        "dice quanto avanza ogni glifo verso il basso",
        "non dice nulla della composizione verso il basso",
    ),
    symbol="Letto come font di simboli, codice 0x41: {symbol}.",
    selectors=(
        "Selettori di variante per cui nomina sequenze: {count}; uno zero seguito da "
        "U+FE00: {variant}."
    ),
    twice="Il primo file è aggiunto due volte, {first} e {second}.",
    writings=(
        "per comporre in larghezza",
        "per comporre verso il basso",
    ),
    policy=(
        "A questo documento si chiede di {policy} un font il cui indicatore ne vieta l’incorporazione."
    ),
    policies=(
        "portare, e nominare in un avviso,",
        "omettere",
        "rifiutare il documento per",
    ),
    decimal=".",
)

# The page in Spanish.
SPANISH = Words(
    title="Lo que un archivo de fuente dice de sí mismo",
    lead=(
        "Tres caras leídas de sus archivos. Cada una se compone una vez en sus "
        "propias letras, y debajo cada cifra se lee del archivo, ninguna escrita a "
        "mano."
    ),
    identity=(
        "{postscript}, de la familia {family}: {outlines}; {units} unidades por eme; "
        "{glyphs} glifos."
    ),
    outlines=(
        "contornos cuadráticos, una fuente TrueType",
        "contornos cúbicos, una fuente OpenType con contornos CFF",
    ),
    traits="Rasgos: {traits}.",
    trait_names=(
        "serifas",
        "un mismo ancho para cada glifo",
        "negrita",
        "cursiva",
        "una codificación de símbolos",
    ),
    none="ninguno",
    unknown="no indicado",
    heights=(
        "A 10 pt sube {ascent} y baja {descent}; mayúsculas: {cap}; minúsculas: {x}; "
        "pide {gap} entre líneas; se inclina {slant}°; cada glifo cabe en [{bbox}] "
        "unidades."
    ),
    underline=(
        "Un subrayado a 10 pt está a {position} pt de la línea base, con {thickness} "
        "pt de grosor; el archivo indica {stated}."
    ),
    stated="{position} y {thickness} unidades",
    unstated="nada de ello",
    permissions="Su propio indicador: {embedding}; {subsetting}; {bitmap}.",
    embeddings=(
        "puede incrustarse e instalarse",
        "no debe incrustarse sin permiso de su propietario",
        "puede incrustarse para ver e imprimir el documento",
        "puede incrustarse y el documento editarse",
    ),
    subsetting=(
        "puede recortarse",
        "debe llevarse entera",
    ),
    bitmap=(
        "sus contornos pueden llevarse",
        "solo sus mapas de bits pueden llevarse",
    ),
    code_pages="Páginas de códigos que declara: {pages}.",
    measures=(
        "W avanza {across} unidades a lo ancho y {down} hacia abajo; el glifo llamado "
        "Eacute: {drawn}; «{sample}» ocupa {count} glifos, mide {width} pt a 10 pt y "
        "{height} pt hacia abajo."
    ),
    vertical=(
        "indica cuánto avanza cada glifo hacia abajo",
        "no indica nada para componer hacia abajo",
    ),
    symbol="Leída como fuente de símbolos, código 0x41: {symbol}.",
    selectors=(
        "Selectores de variante para los que nombra secuencias: {count}; un cero "
        "seguido de U+FE00: {variant}."
    ),
    twice="El primer archivo se añade dos veces, {first} y {second}.",
    writings=(
        "para componer a lo ancho",
        "para componer hacia abajo",
    ),
    policy=(
        "A este documento se le pide {policy} una fuente cuyo propio indicador prohíbe incrustarla."
    ),
    policies=(
        "llevar, y nombrar en un aviso,",
        "omitir",
        "rechazar el documento por",
    ),
    decimal=".",
)

# The page in German.
GERMAN = Words(
    title="Was eine Schriftdatei über sich selbst sagt",
    lead=(
        "Drei Schnitte, aus ihren Dateien gelesen. Jeder wird einmal in seinen "
        "eigenen Buchstaben gesetzt, und darunter wird jede Zahl aus der Datei "
        "gelesen, keine von Hand geschrieben."
    ),
    identity=(
        "{postscript}, aus der Familie {family}: {outlines}; {units} Einheiten pro "
        "Geviert; {glyphs} Glyphen."
    ),
    outlines=(
        "quadratische Konturen, eine TrueType-Schrift",
        "kubische Konturen, eine OpenType-Schrift mit CFF-Konturen",
    ),
    traits="Merkmale: {traits}.",
    trait_names=(
        "Serifen",
        "dieselbe Breite für alle Glyphen",
        "fett",
        "kursiv",
        "eine Symbolkodierung",
    ),
    none="keine",
    unknown="nicht angegeben",
    heights=(
        "Bei 10 pt beträgt ihre Oberlänge {ascent} und ihre Unterlänge {descent}; "
        "Versalhöhe: {cap}; x-Höhe: {x}; sie verlangt {gap} Zwischenraum zwischen den "
        "Zeilen; sie neigt sich um {slant}°; jeder Glyph liegt innerhalb von [{bbox}] "
        "Einheiten."
    ),
    underline=(
        "Eine Unterstreichung bei 10 pt liegt {position} pt von der Grundlinie "
        "entfernt, {thickness} pt dick; die Datei gibt an: {stated}."
    ),
    stated="{position} und {thickness} Einheiten",
    unstated="nichts davon",
    permissions="Ihr eigenes Kennzeichen: {embedding}; {subsetting}; {bitmap}.",
    embeddings=(
        "sie darf eingebettet und installiert werden",
        "sie darf ohne Erlaubnis ihres Rechteinhabers nicht eingebettet werden",
        "sie darf eingebettet werden, um das Dokument anzuzeigen und zu drucken",
        "sie darf eingebettet und das Dokument bearbeitet werden",
    ),
    subsetting=(
        "sie darf als Teilmenge eingebettet werden",
        "sie muss vollständig mitgeführt werden",
    ),
    bitmap=(
        "ihre Konturen dürfen mitgeführt werden",
        "nur ihre Bitmaps dürfen mitgeführt werden",
    ),
    code_pages="Codepages, die sie beansprucht: {pages}.",
    measures=(
        "W rückt {across} Einheiten nach rechts und {down} die Seite hinunter vor; "
        "der Glyph namens Eacute: {drawn}; „{sample}“ braucht {count} Glyphen, läuft "
        "bei 10 pt {width} pt weit und {height} pt die Seite hinunter."
    ),
    vertical=(
        "sie gibt an, wie weit jeder Glyph im senkrechten Satz vorrückt",
        "sie sagt nichts über senkrechten Satz",
    ),
    symbol="Als Symbolschrift gelesen, Code 0x41: {symbol}.",
    selectors=(
        "Variantenselektoren, für die sie Folgen nennt: {count}; eine Null gefolgt "
        "von U+FE00: {variant}."
    ),
    twice="Die erste Datei wird zweimal hinzugefügt, {first} und {second}.",
    writings=(
        "für waagerechten Satz",
        "für senkrechten Satz",
    ),
    policy=(
        "Dieses Dokument soll eine Schrift, deren eigenes Kennzeichen das Einbetten verbietet, {policy}."
    ),
    policies=(
        "mitführen und in einer Warnung nennen",
        "weglassen",
        "zum Anlass nehmen, das Dokument abzulehnen",
    ),
    decimal=".",
)

# Every language the example is written in. A language is added by writing its own set
# of words and naming it here.
WORDS = {_language.ENGLISH: ENGLISH, _language.FRENCH: FRENCH, _language.GERMAN: GERMAN, _language.SPANISH: SPANISH, _language.ITALIAN: ITALIAN, _language.PORTUGUESE: PORTUGUESE, _language.DUTCH: DUTCH}

# What each code page is called on the page: its Windows code page number, or the name
# of the character set it stands for.
CODE_PAGE_NAMES = (
    (hqf_pdf.CodePage.Latin1, "1252"),
    (hqf_pdf.CodePage.Latin2, "1250"),
    (hqf_pdf.CodePage.Cyrillic, "1251"),
    (hqf_pdf.CodePage.Greek, "1253"),
    (hqf_pdf.CodePage.Turkish, "1254"),
    (hqf_pdf.CodePage.Hebrew, "1255"),
    (hqf_pdf.CodePage.Arabic, "1256"),
    (hqf_pdf.CodePage.Baltic, "1257"),
    (hqf_pdf.CodePage.Vietnamese, "1258"),
    (hqf_pdf.CodePage.Thai, "874"),
    (hqf_pdf.CodePage.Japanese, "932"),
    (hqf_pdf.CodePage.ChineseSimplified, "936"),
    (hqf_pdf.CodePage.KoreanWansung, "949"),
    (hqf_pdf.CodePage.ChineseTraditional, "950"),
    (hqf_pdf.CodePage.KoreanJohab, "1361"),
    (hqf_pdf.CodePage.Macintosh, "Mac"),
    (hqf_pdf.CodePage.Oem, "OEM"),
    (hqf_pdf.CodePage.Symbol, "Symbol"),
    (hqf_pdf.CodePage.IbmGreek, "869"),
    (hqf_pdf.CodePage.DosRussian, "866"),
    (hqf_pdf.CodePage.DosNordic, "865"),
    (hqf_pdf.CodePage.DosArabic, "864"),
    (hqf_pdf.CodePage.DosCanadianFrench, "863"),
    (hqf_pdf.CodePage.DosHebrew, "862"),
    (hqf_pdf.CodePage.DosIcelandic, "861"),
    (hqf_pdf.CodePage.DosPortuguese, "860"),
    (hqf_pdf.CodePage.IbmTurkish, "857"),
    (hqf_pdf.CodePage.IbmCyrillic, "855"),
    (hqf_pdf.CodePage.DosLatin2, "852"),
    (hqf_pdf.CodePage.DosBaltic, "775"),
    (hqf_pdf.CodePage.DosGreek, "737"),
    (hqf_pdf.CodePage.Asmo708, "708"),
    (hqf_pdf.CodePage.DosLatin1, "850"),
    (hqf_pdf.CodePage.UnitedStates, "437"),
)

# The four embedding permissions, in the order `Words.embeddings` names them.
EMBEDDINGS = (
    hqf_pdf.Embedding.installable(),
    hqf_pdf.Embedding.restricted(),
    hqf_pdf.Embedding.preview_and_print(),
    hqf_pdf.Embedding.editable(),
)

# The three policies, in the order `Words.policies` names them.
POLICIES = (
    hqf_pdf.FontPermissionPolicy.Warn,
    hqf_pdf.FontPermissionPolicy.LeaveOut,
    hqf_pdf.FontPermissionPolicy.Refuse,
)


def code_page_name(page) -> str:
    """What `page` is called on the page."""
    return next((name for each, name in CODE_PAGE_NAMES if each == page), "?")


def figure(value: float, words: Words) -> str:
    """`value` to one decimal, its decimal separator the language's own."""
    return f"{value:.1f}".replace(".", words.decimal)


def facts(font, handle, family_name: str, words: Words) -> list[str]:
    """What `font`, of the family `family_name`, states about its names, its outlines,
    its traits and its heights, one line each; `handle` is the font added to the
    document."""
    stored = words.outlines[0 if font.outlines == hqf_pdf.OutlineFormat.TrueType else 1]
    identity = (
        words.identity.replace("{postscript}", font.postscript_name)
        .replace("{family}", family_name)
        .replace("{outlines}", stored)
        .replace("{units}", str(font.units_per_em))
        .replace("{glyphs}", str(font.glyph_count))
    )

    flags = font.traits
    named = [
        name
        for held, name in zip(
            (flags.serif, flags.fixed_pitch, flags.bold, flags.italic, flags.symbolic),
            words.trait_names,
        )
        if held
    ]
    held = ", ".join(named) if named else words.none

    metrics = font.metrics
    edges = " ".join(str(edge) for edge in metrics.bbox)
    x_height = font.x_height(10.0)
    heights = (
        words.heights.replace("{ascent}", figure(font.ascent(10.0), words))
        .replace("{descent}", figure(font.descent(10.0), words))
        .replace("{cap}", figure(font.cap_height(10.0), words))
        .replace("{x}", words.unknown if x_height is None else figure(x_height, words))
        .replace("{gap}", figure(font.line_gap(10.0), words))
        .replace("{slant}", figure(metrics.italic_angle, words))
        .replace("{bbox}", edges)
    )

    position, thickness = handle.underline(10.0)
    if metrics.underline is None:
        said_of = words.unstated
    else:
        said_of = words.stated.replace("{position}", str(metrics.underline[0])).replace(
            "{thickness}", str(metrics.underline[1])
        )
    underline = (
        words.underline.replace("{position}", figure(position, words))
        .replace("{thickness}", figure(thickness, words))
        .replace("{stated}", said_of)
    )
    return [identity, words.traits.replace("{traits}", held), heights, underline]


def uses(font, words: Words) -> list[str]:
    """What `font` states of what may be done with it, which code pages it claims, and
    how one glyph and one line measure, one line each."""
    flag = font.permissions
    permissions = (
        words.permissions.replace(
            "{embedding}", words.embeddings[EMBEDDINGS.index(flag.embedding)]
        )
        .replace("{subsetting}", words.subsetting[0 if flag.subsetting else 1])
        .replace("{bitmap}", words.bitmap[1 if flag.bitmap_only else 0])
    )

    claimed = font.claimed_code_pages()
    if claimed is None:
        claimed_list = words.none
    else:
        claimed_list = ", ".join(code_page_name(page) for page in claimed)
    code_pages = words.code_pages.replace("{pages}", claimed_list)

    w = font.glyph("W") or 0
    eacute_glyph = font.glyph_named("Eacute")
    if eacute_glyph is None:
        eacute = words.unknown
    else:
        eacute = "".join(font.characters_of(eacute_glyph))
    measures = (
        words.measures.replace("{across}", str(font.advance(w)))
        .replace("{down}", str(font.vertical_advance(w)))
        .replace("{drawn}", eacute)
        .replace("{sample}", SAMPLE)
        .replace("{count}", str(len(font.try_glyphs(SAMPLE))))
        .replace("{width}", figure(font.try_measure(SAMPLE, 10.0), words))
        .replace("{height}", figure(font.measure_vertically(SAMPLE, 10.0), words))
    )
    vertical = words.vertical[0 if font.sets_vertically else 1]
    reached = font.symbol_character(0x41)
    symbol_line = words.symbol.replace(
        "{symbol}", words.none if reached is None else reached
    )

    variant = font.variant_glyph("0", "︀")
    sequence = words.unknown if variant is None else str(variant)
    selectors = words.selectors.replace(
        "{count}", str(len(font.variation_selectors()))
    ).replace("{variant}", sequence)

    return [
        permissions,
        code_pages,
        f"{measures} {vertical[:1].upper()}{vertical[1:]}.",
        symbol_line,
        selectors,
    ]


def set_lines(content, handle, size: float, top: float, lines) -> float:
    """Set `lines` from `top` down in `handle`, each broken to the page's width; hand
    back where the last ends."""
    flow = hqf_pdf.TextFlow(handle, size, leading=size * 1.3)
    y = top
    for line in lines:
        broken = flow.break_lines(line, WIDTH)
        flow.draw(content, broken, LEFT, y, WIDTH)
        y -= flow.height(broken) + 1.5
    return y


def build(words: Words) -> hqf_pdf.Document:
    """The document: the three faces, each set in its own letters over what its file
    states, and the first file added twice."""
    doc = hqf_pdf.Document()
    doc.set_license(_licence.licensed())
    doc.set_info("Title", words.title)
    told_policy = hqf_pdf.FontPermissionPolicy.Warn
    doc.set_font_permission_policy(told_policy)

    faces = []
    for place, file in enumerate(FILES):
        data = (FONTS / file).read_bytes()
        family = (hqf_pdf.Font.families(data) or [""])[0]
        if place == 2:
            font = hqf_pdf.Font.face_at(data, 0)
        else:
            font = hqf_pdf.Font.face_named(data, family)
        faces.append((family, font))
    text = doc.add_font(faces[0][1])
    upright = doc.add_vertical_font(faces[0][1])

    content = hqf_pdf.Content()
    content.set_fill(hqf_pdf.Rgb.gray(0.0))
    top = set_lines(content, text, 16.0, 790.0, [words.title]) - 4.0
    top = set_lines(content, text, 9.5, top, [words.lead]) - 14.0
    for family, font in faces:
        own = doc.add_font(font)
        said = facts(font, own, family, words) + uses(font, words)
        top = set_lines(content, own, 14.0, top, [family]) - 2.0
        content.set_fill(hqf_pdf.Rgb.gray(0.3))
        top = set_lines(content, text, FACTS, top, said) - 12.0
        content.set_fill(hqf_pdf.Rgb.gray(0.0))

    writings = (hqf_pdf.WritingMode.Horizontal, hqf_pdf.WritingMode.Vertical)
    twice = words.twice.replace(
        "{first}", words.writings[writings.index(text.writing)]
    ).replace("{second}", words.writings[writings.index(upright.writing)])
    told = words.policy.replace("{policy}", words.policies[POLICIES.index(told_policy)])
    set_lines(content, text, 9.5, top, [twice, told])

    page = hqf_pdf.Page.a4()
    page.set_content(content)
    doc.add_page(page)
    return doc


def main() -> None:
    language = _language.from_environment()
    words = _language.words_of(WORDS, language)

    # A named file is written as named; the default one carries the language, so the two
    # languages do not overwrite each other in `tmp/`.
    out = _out.output_path(Path(_language.file_name("font_facts.pdf", language)).stem)

    written = build(words).write(out)
    print(f"wrote {out} ({written} bytes)")


if __name__ == "__main__":
    main()
