"""A handbook that says how it would like to be opened, shown and printed.

The Python twin of the `write_reading_preferences` example in Rust. None of what
this document states changes a single mark on its pages. It changes what happens
the moment somebody double-clicks the file: which page comes up, how much of it
fills the window, what stands beside it, and what the print dialogue is already
set to when it opens.

What the handbook says is written in the language `HQF_PDF_LANG` names. The address
it is published under is not, and neither is the name of the file its one relative
link points at.

It also says, in so many words, that the toolbar, the menu bar and the window's controls
stay shown, and that its pages are read from left to right.

Usage: python examples/write_reading_preferences.py [out.pdf] [font.ttf]
       HQF_PDF_LANG=fr python examples/write_reading_preferences.py
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# A4, in points.
SHEET = (595.276, 841.890)

# How far in from the edge of the sheet everything is set.
MARGIN = 64.0

# The colour the band across the head of a page is laid in.
BAND = (0.13, 0.29, 0.36)

# The address this document is published under, and the address its relative links are
# read against.
BASE = "https://example.org/handbook/"

# The file the one relative link on the contents page points at.
TERMS_FILE = "terms.html"

# Who publishes the handbook, which no language renames.
PUBLISHER = "HQF Development"

# How many copies the print dialogue is asked to offer, which a row of the table spells
# out in words.
COPIES = 2

# The run of pages the print dialogue is asked to offer, counting from zero, which a row
# of the table spells out in words.
PRINT_RUN = (1, 3)

# The sizes the handbook is set in, in points.
COVER_TITLE_SIZE = 34.0
COVER_SUBJECT_SIZE = 13.0
PUBLISHER_SIZE = 10.0
HEAD_SIZE = 20.0
BODY_SIZE = 10.5
SECTION_SIZE = 11.0
SETTING_SIZE = 9.5
NOTE_SIZE = 9.5
FOOT_SIZE = 8.0
SKETCH_SIZE = 8.0

# How far in from the left of a settings row what the setting does is drawn.
SETTING_GAP = 190.0

# Where the underlined words of the link sit, and how tall the rectangle a reader may
# click stands. How wide it runs is not here: it is the width of the words themselves,
# so nothing a language writes there can fall outside what a reader may click.
LINK = (290.0, 16.0)

# The page a reader is shown for each section, in the order they are listed.
SECTION_PAGES = ("1", "2", "3", "4")

# Where the two sheets of the little diagram stand.
SKETCHES = ((MARGIN + 40.0, 216.0), (MARGIN + 260.0, 216.0))


@dataclass(frozen=True)
class Words:
    """The words the handbook is written in, one set per language.

    The address the file is published under, the name of the file its link points at
    and the name of the publisher are not among them.
    """

    # What the handbook is called, on its cover, at the foot of every page and in what
    # the file says of itself.
    handbook: str
    # What the handbook is about, under the title and in the metadata.
    subject: str
    # What each section is called. One tuple, read three times over: the list on the
    # contents page, the heading of the two pages that have one, and the bookmarks a
    # reader is shown beside the page. No language can make the three disagree.
    sections: tuple[str, ...]
    # The paragraph on the cover.
    cover_body: tuple[str, ...]
    # The paragraph under the list of sections.
    contents_body: tuple[str, ...]
    # The two lines above the link, the first of which names the file it points at.
    terms_lead: tuple[str, ...]
    # The words the link is laid over.
    terms_link: str
    # The paragraph that says what a base address is for.
    base_note: tuple[str, ...]
    # The paragraph above the table of what the file asks of reading software.
    screen_lead: tuple[str, ...]
    # What each row of that table asks for, and what it does.
    screen_settings: tuple[tuple[str, str], ...]
    # What the last row of it asks for, whose answer is the address itself.
    relative_links: str
    # The paragraph under it.
    screen_note: tuple[str, ...]
    # The paragraph above the table of what the file asks of a printer.
    printer_lead: tuple[str, ...]
    # What each row of that table asks for, and what it does.
    printer_settings: tuple[tuple[str, str], ...]
    # What the sheet drawn front-side-up is called.
    front: str
    # What the sheet drawn back-side-up is called.
    back: str
    # What the arrow between the two says.
    long_edge: str
    # The paragraph under them.
    printer_note: tuple[str, ...]


# The handbook in English.
ENGLISH = Words(
    handbook="Field handbook",
    subject="How a document asks to be opened, shown and printed",
    sections=(
        "The cover",
        "Contents",
        "What this file asks of reading software",
        "What it asks of a print dialogue",
    ),
    cover_body=(
        "This cover is page one, and it is not the page this document opens on. "
        "Reading software",
        "that honours what the file states turns straight to the contents, shows the "
        "bookmarks",
        "beside it, and stands the cover on its own — the way a book falls open with "
        "its first page",
        "facing nothing.",
    ),
    contents_body=(
        "This is the page the file opens on, and it opens showing what is drawn "
        "on it",
        "rather than the whole sheet: the words fill the window, not the paper "
        "around",
        "them. Turn to page three for the whole list of what this file asks for, "
        "and to",
        "page four for what it asks of a printer.",
    ),
    terms_lead=(
        "The link below goes to {}, and to nothing else. It works because this",
        "file states the address it was published under:",
    ),
    terms_link="Read the full terms",
    base_note=(
        "Move this file to another address and that link breaks — unless the address",
        "moves with it. That is all a base address is for: one line to restate, "
        "instead",
        "of every relative link in the document to rewrite.",
    ),
    screen_lead=(
        "Every line below is a wish, not an instruction. Reading software whose owner "
        "has said",
        "otherwise does what its owner said, and reading software that has never heard "
        "of one",
        "of these entries ignores it and shows the file all the same.",
    ),
    screen_settings=(
        ("Opens on", "the contents page, not the cover"),
        ("Shows", "what is drawn, filling the window"),
        ("Beside the page", "the list of bookmarks"),
        ("Arranges the pages", "two at a time, page one on its own"),
        ("Window", "resized to the first page, centred on the screen"),
        ("Title bar", "the title this file states, not its file name"),
        ("Leaving full screen", "back to the bookmarks"),
    ),
    relative_links="Relative links",
    screen_note=(
        "Nothing here is drawn on a page. Print this file and not one of these lines "
        "leaves a mark: they live",
        "in the catalogue, which is the first thing reading software reads and the "
        "last thing a printer cares",
        "about.",
    ),
    printer_lead=(
        "A print dialogue opens with something already filled in. A file may say "
        "what,",
        "which saves whoever prints it from setting the same four boxes every time.",
    ),
    printer_settings=(
        ("Scaling", "none: every page prints at the size it was drawn"),
        ("Sides", "both, the sheet turned on its long edge"),
        ("Paper tray", "chosen by the size of the page"),
        ("Copies", "two"),
        ("Pages", "two to four: the cover is not worth the toner"),
    ),
    front="front: page two",
    back="back: page three",
    long_edge="turned on the long edge",
    printer_note=(
        "Printing at actual size is the one that matters on a document meant to be",
        "measured: a form, a label sheet, a plan. A dialogue left to shrink the "
        "page to",
        "fit the paper is a dialogue that quietly makes every distance on it wrong.",
    ),
)

# The handbook in French.
FRENCH = Words(
    handbook="Manuel de terrain",
    subject="Comment un document demande à être ouvert, affiché et imprimé",
    sections=(
        "La couverture",
        "Sommaire",
        "Ce qu’il demande au logiciel de lecture",
        "Ce qu’il demande à la fenêtre d’impression",
    ),
    cover_body=(
        ("Cette couverture est la page un, mais ce document ne s’ouvre pas sur elle. "
         "Un logiciel"),
        (("de lecture qui suit ce que le fichier déclare va droit au sommaire, affiche"
          " les signets")),
        ("à côté et laisse la couverture seule — comme un livre ouvert dont la "
         "première page"),
        "n’a rien en regard.",
    ),
    contents_body=(
        ("C’est la page sur laquelle le fichier s’ouvre, et elle s’affiche en montrant"
         " ce qui"),
        "y figure plutôt que la feuille entière : les mots remplissent la fenêtre, pas",
        ("le papier autour. Voir la page trois pour la liste complète de ce que ce "
         "fichier"),
        "demande, et la page quatre pour ce qu’il demande à une imprimante.",
    ),
    terms_lead=(
        ("Le lien ci-dessous va vers {}, et nulle part ailleurs. Il fonctionne parce "
         "que"),
        "ce fichier déclare l’adresse sous laquelle il a été publié :",
    ),
    terms_link="Lire les conditions",
    base_note=(
        ("Déplacez ce fichier à une autre adresse et ce lien est rompu — sauf si "
         "l’adresse"),
        ("déclarée suit. C’est tout le rôle d’une adresse de base : une seule ligne à "
         "corriger,"),
        "au lieu de réécrire chaque lien relatif du document.",
    ),
    screen_lead=(
        (("Chaque ligne ci-dessous est un souhait, pas un ordre. Un logiciel de "
          "lecture que son")),
        (("utilisateur a réglé autrement obéit à ce réglage, et un logiciel qui ne "
          "connaît pas l’une")),
        "de ces entrées l’ignore et affiche le fichier malgré tout.",
    ),
    screen_settings=(
        ("S’ouvre sur", "le sommaire, pas la couverture"),
        ("Affiche", "le contenu seul, à pleine fenêtre"),
        ("À côté de la page", "la liste des signets"),
        ("Dispose les pages", "deux par deux, la page un seule"),
        ("Fenêtre", "à la taille de la première page, centrée à l’écran"),
        ("Barre de titre", "le titre déclaré par le fichier, pas son nom"),
        ("En quittant le plein écran", "retour aux signets"),
    ),
    relative_links="Liens relatifs",
    screen_note=(
        ("Aucun de ces réglages n’est tracé sur une page. Imprimez ce fichier : pas un"
         " ne laisse de"),
        ("trace. Ils vivent dans le catalogue, la première chose que lit un logiciel "
         "de lecture et la dernière"),
        "dont se soucie une imprimante.",
    ),
    printer_lead=(
        "Une fenêtre d’impression s’ouvre avec des réglages déjà remplis. Un fichier",
        ("peut dire lesquels, ce qui évite de régler les quatre mêmes cases à chaque "
         "fois."),
    ),
    printer_settings=(
        ("Mise à l’échelle", "aucune : chaque page s’imprime à sa taille d’origine"),
        ("Faces", "les deux, feuille retournée sur le bord long"),
        ("Bac papier", "choisi selon la taille de la page"),
        ("Copies", "deux"),
        ("Pages", "deux à quatre : la couverture ne vaut pas l’encre"),
    ),
    front="recto : page deux",
    back="verso : page trois",
    long_edge="retournée sur le bord long",
    printer_note=(
        "L’impression à taille réelle est celle qui compte pour un document destiné à",
        ("être mesuré : un formulaire, une planche d’étiquettes, un plan. Une fenêtre "
         "qui"),
        ("réduit la page au format du papier fausse en silence chacune de ses "
         "distances."),
    ),
)

# The handbook in Dutch.
DUTCH = Words(
    handbook="Veldhandboek",
    subject="Hoe een document vraagt geopend, getoond en afgedrukt te worden",
    sections=(
        "De omslag",
        "Inhoud",
        "Wat dit bestand van leessoftware vraagt",
        "Wat het van een afdrukvenster vraagt",
    ),
    cover_body=(
        "Deze omslag is pagina één, maar het document opent niet hier. Leessoftware",
        "die respecteert wat het bestand zegt, gaat meteen naar de inhoud, toont de "
        "bladwijzers",
        "ernaast en laat de omslag alleen, zoals een boek dat openvalt met de eerste "
        "pagina",
        "tegenover niets.",
    ),
    contents_body=(
        "Dit is de pagina waarop het bestand opent, en het opent met wat erop "
        "getekend staat",
        "in plaats van het hele blad: de woorden vullen het venster, niet het papier "
        "eromheen.",
        "Ga naar pagina drie voor de volledige lijst van wat dit bestand vraagt, en "
        "naar",
        "pagina vier voor wat het van een printer vraagt.",
    ),
    terms_lead=(
        "De link hieronder gaat naar {}, en nergens anders heen. Hij werkt omdat dit",
        "bestand het adres noemt waaronder het is gepubliceerd:",
    ),
    terms_link="De volledige voorwaarden lezen",
    base_note=(
        "Verplaats dit bestand naar een ander adres en die link breekt, tenzij het adres",
        "meeverhuist. Daar is een basisadres voor: één regel om aan te passen, in "
        "plaats",
        "van elke relatieve link in het document te herschrijven.",
    ),
    screen_lead=(
        "Elke regel hieronder is een wens, geen bevel. Leessoftware waarvan de "
        "eigenaar iets",
        "anders heeft ingesteld, doet wat de eigenaar zei, en leessoftware die nooit "
        "van een",
        "van deze gegevens heeft gehoord, negeert ze en toont het bestand toch.",
    ),
    screen_settings=(
        ("Opent op", "de inhoudspagina, niet de omslag"),
        ("Toont", "wat getekend is, het venster vullend"),
        ("Naast de pagina", "de lijst met bladwijzers"),
        ("Schikt de pagina’s", "twee tegelijk, pagina één apart"),
        ("Venster", "passend op de eerste pagina, midden op het scherm"),
        ("Titelbalk", "de titel die dit bestand noemt, niet de bestandsnaam"),
        ("Bij verlaten van volledig scherm", "terug naar de bladwijzers"),
    ),
    relative_links="Relatieve links",
    screen_note=(
        "Niets hiervan wordt op een pagina getekend. Druk dit bestand af en geen van "
        "deze regels",
        "laat een spoor na: ze staan in de catalogus, het eerste wat leessoftware "
        "leest en het",
        "laatste waar een printer om geeft.",
    ),
    printer_lead=(
        "Een afdrukvenster opent met iets al ingevuld. Een bestand kan zeggen wat,",
        "zodat wie afdrukt niet elke keer dezelfde vier vakjes hoeft in te stellen.",
    ),
    printer_settings=(
        ("Schaal", "geen: elke pagina op ware grootte"),
        ("Zijden", "beide, het blad gekeerd over de lange kant"),
        ("Papierlade", "gekozen naar het paginaformaat"),
        ("Exemplaren", "twee"),
        ("Pagina’s", "twee tot vier: de omslag is de toner niet waard"),
    ),
    front="voorkant: pagina twee",
    back="achterkant: pagina drie",
    long_edge="gekeerd over de lange kant",
    printer_note=(
        "Afdrukken op ware grootte telt bij een document dat bedoeld is om",
        "gemeten te worden: een formulier, een etikettenvel, een plattegrond. Een "
        "venster dat",
        "de pagina tot het papier laat krimpen, vervalst stilletjes elke afstand.",
    ),
)

# The handbook in Portuguese.
PORTUGUESE = Words(
    handbook="Manual de campo",
    subject="Como um documento pede para ser aberto, mostrado e impresso",
    sections=(
        "A capa",
        "Índice",
        "O que o ficheiro pede ao programa de leitura",
        "O que pede a uma janela de impressão",
    ),
    cover_body=(
        "Esta capa é a página um, mas o documento não abre nela. Um programa de "
        "leitura",
        "que respeite o que o ficheiro indica vai direto ao índice, mostra os "
        "marcadores",
        "ao lado e deixa a capa sozinha, como um livro que abre com a primeira página",
        "de frente para nada.",
    ),
    contents_body=(
        "Esta é a página em que o ficheiro abre, e abre a mostrar o que nela está "
        "desenhado",
        "em vez da folha inteira: as palavras enchem a janela, não o papel à volta",
        "delas. Vá à página três para a lista completa do que este ficheiro pede, e à",
        "página quatro para o que pede a uma impressora.",
    ),
    terms_lead=(
        "A ligação abaixo leva a {}, e a mais nada. Funciona porque este",
        "ficheiro indica o endereço com que foi publicado:",
    ),
    terms_link="Ler as condições completas",
    base_note=(
        "Mude este ficheiro para outro endereço e essa ligação parte-se, salvo se o endereço",
        "se mudar com ele. Para isso serve um endereço base: uma linha a reescrever, "
        "em vez",
        "de cada ligação relativa do documento.",
    ),
    screen_lead=(
        "Cada linha abaixo é um desejo, não uma ordem. Um programa de leitura cujo "
        "utilizador",
        "disse outra coisa faz o que o utilizador disse, e um que nunca ouviu falar "
        "de uma",
        "destas entradas ignora-a e mostra o ficheiro na mesma.",
    ),
    screen_settings=(
        ("Abre em", "a página do índice, não a capa"),
        ("Mostra", "o que está desenhado, a encher a janela"),
        ("Ao lado da página", "a lista de marcadores"),
        ("Dispõe as páginas", "duas de cada vez, a página um sozinha"),
        ("Janela", "ajustada à primeira página, centrada no ecrã"),
        ("Barra de título", "o título que este ficheiro indica, não o nome do ficheiro"),
        ("Ao sair do ecrã inteiro", "volta aos marcadores"),
    ),
    relative_links="Ligações relativas",
    screen_note=(
        "Nada disto é desenhado numa página. Imprima este ficheiro e nenhuma destas "
        "linhas",
        "deixa marca: vivem no catálogo, a primeira coisa que um programa de leitura "
        "lê e a",
        "última com que uma impressora se importa.",
    ),
    printer_lead=(
        "Uma janela de impressão abre com algo já preenchido. Um ficheiro pode dizer "
        "o quê,",
        "o que poupa a quem imprime acertar as mesmas quatro caixas de cada vez.",
    ),
    printer_settings=(
        ("Escala", "nenhuma: cada página em tamanho real"),
        ("Faces", "as duas, a folha virada pelo lado maior"),
        ("Tabuleiro de papel", "escolhido pelo tamanho da página"),
        ("Cópias", "duas"),
        ("Páginas", "da dois à quatro: a capa não vale o toner"),
    ),
    front="frente: página dois",
    back="verso: página três",
    long_edge="virada pelo lado maior",
    printer_note=(
        "Imprimir em tamanho real é o que conta num documento feito para ser",
        "medido: um formulário, uma folha de etiquetas, uma planta. Uma janela que "
        "reduz a página",
        "ao papel é uma janela que falseia em silêncio cada distância.",
    ),
)

# The handbook in Italian.
ITALIAN = Words(
    handbook="Manuale da campo",
    subject="Come un documento chiede di essere aperto, mostrato e stampato",
    sections=(
        "La copertina",
        "Indice",
        "Cosa chiede il file al programma di lettura",
        "Cosa chiede a una finestra di stampa",
    ),
    cover_body=(
        "Questa copertina è la pagina uno, ma il documento non si apre qui. Un "
        "programma",
        "di lettura che rispetta il file passa subito all’indice, mostra i segnalibri",
        "accanto e lascia la copertina da sola, come un libro che si apre con la "
        "prima pagina",
        "di fronte al nulla.",
    ),
    contents_body=(
        "Questa è la pagina su cui si apre il file, e si apre mostrando ciò che vi è "
        "disegnato",
        "anziché il foglio intero: le parole riempiono la finestra, non la carta "
        "intorno",
        "a esse. Andate a pagina tre per l’elenco completo di ciò che chiede questo "
        "file, e a",
        "pagina quattro per ciò che chiede a una stampante.",
    ),
    terms_lead=(
        "Il collegamento qui sotto porta a {}, e a nient’altro. Funziona perché questo",
        "file indica l’indirizzo con cui è stato pubblicato:",
    ),
    terms_link="Leggere le condizioni complete",
    base_note=(
        "Spostate questo file a un altro indirizzo e quel collegamento si rompe, a meno che l’indirizzo",
        "non si sposti con esso. È tutto ciò a cui serve un indirizzo di base: una "
        "riga da riscrivere, anziché",
        "ogni collegamento relativo del documento.",
    ),
    screen_lead=(
        "Ogni riga qui sotto è un desiderio, non un ordine. Un programma di lettura a "
        "cui l’utente",
        "ha detto altro fa ciò che ha detto l’utente, e uno che non ha mai sentito "
        "parlare di una",
        "di queste voci la ignora e mostra il file lo stesso.",
    ),
    screen_settings=(
        ("Si apre su", "la pagina dell’indice, non la copertina"),
        ("Mostra", "ciò che è disegnato, riempiendo la finestra"),
        ("Accanto alla pagina", "l’elenco dei segnalibri"),
        ("Dispone le pagine", "due alla volta, la pagina uno da sola"),
        ("Finestra", "adattata alla prima pagina, centrata sullo schermo"),
        ("Barra del titolo", "il titolo che indica questo file, non il nome del file"),
        ("Uscendo dallo schermo intero", "torna ai segnalibri"),
    ),
    relative_links="Collegamenti relativi",
    screen_note=(
        "Niente di tutto questo è disegnato su una pagina. Stampate il file e nessuna "
        "di queste righe",
        "lascia traccia: vivono nel catalogo, la prima cosa che legge un programma di "
        "lettura e l’ultima",
        "che interessa a una stampante.",
    ),
    printer_lead=(
        "Una finestra di stampa si apre con qualcosa già compilato. Un file può dire "
        "cosa,",
        "il che risparmia a chi stampa di impostare ogni volta le stesse quattro caselle.",
    ),
    printer_settings=(
        ("Scala", "nessuna: ogni pagina si stampa a grandezza reale"),
        ("Lati", "entrambi, il foglio girato sul lato lungo"),
        ("Vassoio della carta", "scelto in base al formato della pagina"),
        ("Copie", "due"),
        ("Pagine", "dalla due alla quattro: la copertina non vale il toner"),
    ),
    front="fronte: pagina due",
    back="retro: pagina tre",
    long_edge="girato sul lato lungo",
    printer_note=(
        "Stampare in dimensione reale è ciò che conta in un documento fatto per essere",
        "misurato: un modulo, un foglio di etichette, una pianta. Una finestra "
        "lasciata a ridurre la pagina",
        "alla carta è una finestra che falsa in silenzio ogni distanza.",
    ),
)

# The handbook in Spanish.
SPANISH = Words(
    handbook="Manual de campo",
    subject="Cómo pide un documento que se abra, se muestre y se imprima",
    sections=(
        "La cubierta",
        "Índice",
        "Lo que el archivo pide al programa de lectura",
        "Lo que pide a un cuadro de impresión",
    ),
    cover_body=(
        "Esta cubierta es la página uno, pero el documento no se abre en ella. Un "
        "programa",
        "de lectura que respeta lo que indica el archivo pasa directamente al índice, "
        "muestra",
        "los marcadores a su lado y deja la cubierta sola, como un libro que se abre "
        "con su",
        "primera página sin nada enfrente.",
    ),
    contents_body=(
        "Esta es la página en que se abre el archivo, y se abre mostrando lo que "
        "tiene dibujado",
        "y no la hoja entera: las palabras llenan la ventana, no el papel que las",
        "rodea. Vaya a la página tres para ver la lista completa de lo que pide el "
        "archivo, y a la",
        "página cuatro para ver lo que pide a una impresora.",
    ),
    terms_lead=(
        "El enlace de abajo lleva a {}, y a nada más. Funciona porque este",
        "archivo indica la dirección con la que se publicó:",
    ),
    terms_link="Leer las condiciones completas",
    base_note=(
        "Mueva este archivo a otra dirección y ese enlace se rompe, salvo que la dirección",
        "se mueva con él. Para eso sirve una dirección base: una línea que cambiar en "
        "lugar",
        "de reescribir cada enlace relativo del documento.",
    ),
    screen_lead=(
        "Cada línea de abajo es un deseo, no una orden. Un programa de lectura cuyo "
        "dueño",
        "ha dicho otra cosa hace lo que dijo su dueño, y uno que nunca ha oído hablar "
        "de una",
        "de estas entradas la ignora y muestra el archivo igualmente.",
    ),
    screen_settings=(
        ("Se abre en", "la página del índice, no la cubierta"),
        ("Muestra", "lo dibujado, llenando la ventana"),
        ("Junto a la página", "la lista de marcadores"),
        ("Coloca las páginas", "de dos en dos, la página uno sola"),
        ("Ventana", "ajustada a la primera página, centrada en la pantalla"),
        ("Barra de título", "el título que indica este archivo, no su nombre de archivo"),
        ("Al salir de pantalla completa", "vuelve a los marcadores"),
    ),
    relative_links="Enlaces relativos",
    screen_note=(
        "Nada de esto se dibuja en una página. Imprima este archivo y ninguna de "
        "estas líneas deja",
        "huella: viven en el catálogo, que es lo primero que lee un programa de "
        "lectura y lo último",
        "que le importa a una impresora.",
    ),
    printer_lead=(
        "Un cuadro de impresión se abre con algo ya rellenado. Un archivo puede decir "
        "qué,",
        "lo que ahorra a quien lo imprime marcar las mismas cuatro casillas cada vez.",
    ),
    printer_settings=(
        ("Escala", "ninguna: cada página se imprime a su tamaño real"),
        ("Caras", "las dos, la hoja volteada por el borde largo"),
        ("Bandeja de papel", "elegida por el tamaño de la página"),
        ("Copias", "dos"),
        ("Páginas", "de la dos a la cuatro: la cubierta no merece el tóner"),
    ),
    front="anverso: página dos",
    back="reverso: página tres",
    long_edge="volteada por el borde largo",
    printer_note=(
        "Imprimir a tamaño real es lo que importa en un documento hecho para",
        "medirse: un formulario, una hoja de etiquetas, un plano. Un cuadro que "
        "reduce la página para",
        "que quepa en el papel es un cuadro que falsea en silencio cada distancia.",
    ),
)

# The handbook in German.
GERMAN = Words(
    handbook="Feldhandbuch",
    subject="Wie ein Dokument geöffnet, gezeigt und gedruckt werden möchte",
    sections=(
        "Der Umschlag",
        "Inhalt",
        "Was diese Datei von der Lesesoftware erbittet",
        "Was sie von einem Druckdialog erbittet",
    ),
    cover_body=(
        "Dieser Umschlag ist Seite eins, doch die Datei öffnet nicht hier. Eine "
        "Lesesoftware,",
        "die befolgt, was die Datei angibt, schlägt gleich den Inhalt auf, zeigt "
        "daneben",
        "die Lesezeichen und stellt den Umschlag allein — wie ein Buch aufklappt, die "
        "erste Seite",
        "gegenüber von nichts.",
    ),
    contents_body=(
        "Auf dieser Seite öffnet die Datei, und sie zeigt, was darauf gezeichnet ist,",
        "statt des ganzen Bogens: Die Wörter füllen das Fenster, nicht das Papier um "
        "sie.",
        "Auf Seite drei steht die ganze Liste dessen, was diese Datei erbittet, und "
        "auf",
        "Seite vier, was sie von einem Drucker erbittet.",
    ),
    terms_lead=(
        "Der Link unten führt zu {} und nirgendwohin sonst. Er funktioniert, weil diese",
        "Datei die Adresse angibt, unter der sie veröffentlicht wurde:",
    ),
    terms_link="Die vollständigen Bedingungen lesen",
    base_note=(
        "Zieht die Datei an eine andere Adresse, bricht der Link — außer die Adresse",
        "zieht mit. Mehr leistet eine Basisadresse nicht: eine Zeile neu angeben, "
        "statt jeden",
        "relativen Link im Dokument umzuschreiben.",
    ),
    screen_lead=(
        "Jede Zeile unten ist ein Wunsch, keine Anweisung. Eine Lesesoftware, deren "
        "Besitzer",
        "anderes festlegte, folgt ihm, und eine, die einen dieser Einträge nicht "
        "kennt,",
        "übergeht ihn und zeigt die Datei trotzdem.",
    ),
    screen_settings=(
        ("Öffnet auf", "der Inhaltsseite, nicht dem Umschlag"),
        ("Zeigt", "das Gezeichnete, fensterfüllend"),
        ("Neben der Seite", "die Liste der Lesezeichen"),
        ("Ordnet die Seiten an", "zu zweit, Seite eins für sich"),
        ("Fenster", "auf die erste Seite angepasst, mittig auf dem Bildschirm"),
        ("Titelleiste", "der Titel, den die Datei angibt, nicht ihr Dateiname"),
        ("Beim Verlassen des Vollbilds", "zurück zu den Lesezeichen"),
    ),
    relative_links="Relative Links",
    screen_note=(
        "Nichts davon ist auf eine Seite gezeichnet. Wer diese Datei druckt, sieht "
        "keine dieser Zeilen: Sie",
        "stehen im Katalog, den eine Lesesoftware zuerst liest und der einen Drucker "
        "am wenigsten",
        "kümmert.",
    ),
    printer_lead=(
        "Ein Druckdialog öffnet sich mit bereits ausgefüllten Angaben. Eine Datei kann",
        "sagen, welche, und erspart so, jedes Mal dieselben vier Felder zu setzen.",
    ),
    printer_settings=(
        ("Skalierung", "keine: Jede Seite druckt in Originalgröße"),
        ("Duplex", "beidseitig, Bogen über die lange Kante gewendet"),
        ("Papierfach", "nach der Seitengröße gewählt"),
        ("Exemplare", "zwei"),
        ("Seiten", "zwei bis vier: Der Umschlag ist den Toner nicht wert"),
    ),
    front="Vorderseite: Seite zwei",
    back="Rückseite: Seite drei",
    long_edge="über die lange Kante gewendet",
    printer_note=(
        "Der Druck in Originalgröße zählt bei einem Dokument, das gemessen werden soll:",
        "ein Formular, ein Etikettenbogen, ein Plan. Ein Dialog, der die Seite aufs "
        "Papier",
        "verkleinern darf, macht still und leise jeden Abstand darauf falsch.",
    ),
)

# 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}


def terms_first_line(words: Words) -> str:
    """The first line above the link, which names the file the link points at."""
    return words.terms_lead[0].replace("{}", TERMS_FILE)


def screen_rows(words: Words) -> tuple[tuple[str, str], ...]:
    """Every row of the table of what the file asks of reading software.

    The last of them answers with the address itself.
    """
    return words.screen_settings + ((words.relative_links, BASE),)


def band():
    """The colour the band across the head of a page is laid in."""
    return hqf_pdf.Rgb(BAND[0], BAND[1], BAND[2])


def head(content, font, heading):
    """Draw the band across the head of a page and the heading standing in it."""
    content.save_state()
    content.set_fill(band())
    content.rect(0.0, SHEET[1] - 96.0, SHEET[0], 96.0)
    content.fill()
    content.set_fill(hqf_pdf.Rgb(1.0, 1.0, 1.0))
    content.draw_text(font, HEAD_SIZE, MARGIN, SHEET[1] - 58.0, heading)
    content.restore_state()


def foot(content, font, words, number):
    """Draw the hairline and the line of small print that close a page."""
    content.save_state()
    content.set_stroke(hqf_pdf.Color.gray(0.82))
    content.set_line_width(0.4)
    content.move_to(MARGIN, 78.0)
    content.line_to(SHEET[0] - MARGIN, 78.0)
    content.stroke()
    content.set_fill(hqf_pdf.Color.gray(0.5))
    content.draw_text(font, FOOT_SIZE, MARGIN, 62.0, words.handbook)
    content.draw_text(font, FOOT_SIZE, SHEET[0] - MARGIN - 6.0, 62.0, number)
    content.restore_state()


def lines(content, font, top, size, step, body):
    """Draw a run of lines down the page from `top`.

    Hands back the baseline the next thing would go on.
    """
    y = top
    for line in body:
        if line:
            content.draw_text(font, size, MARGIN, y, line)
        y -= step
    return y


def setting(content, font, y, asked, does):
    """Draw a row of the settings table: what was asked for, and what it does."""
    content.save_state()
    content.set_fill(band())
    content.draw_text(font, SETTING_SIZE, MARGIN, y, asked)
    content.set_fill(hqf_pdf.Color.gray(0.3))
    content.draw_text(font, SETTING_SIZE, MARGIN + SETTING_GAP, y, does)
    content.set_stroke(hqf_pdf.Color.gray(0.85))
    content.set_line_width(0.4)
    content.move_to(MARGIN, y - 7.0)
    content.line_to(SHEET[0] - MARGIN, y - 7.0)
    content.stroke()
    content.restore_state()


def cover(font, words):
    """The cover: the one page nobody is meant to land on."""
    content = hqf_pdf.Content()
    content.save_state()
    content.set_fill(band())
    content.rect(0.0, 0.0, SHEET[0], SHEET[1])
    content.fill()
    content.restore_state()

    content.save_state()
    content.set_fill(hqf_pdf.Rgb(1.0, 1.0, 1.0))
    content.draw_text(font, COVER_TITLE_SIZE, MARGIN, 540.0, words.handbook)
    content.set_fill(hqf_pdf.Rgb(0.72, 0.83, 0.86))
    content.draw_text(font, COVER_SUBJECT_SIZE, MARGIN, 504.0, words.subject)
    content.draw_text(font, PUBLISHER_SIZE, MARGIN, 120.0, PUBLISHER)
    content.restore_state()

    content.save_state()
    content.set_fill(hqf_pdf.Rgb(0.72, 0.83, 0.86))
    lines(content, font, 420.0, BODY_SIZE, 16.0, words.cover_body)
    content.restore_state()
    return content


def section_list(content, font, words):
    """Draw the list of sections, each under a hairline.

    Hands back the baseline the next thing would go on.
    """
    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.25))
    y = SHEET[1] - 160.0
    for item, page in zip(words.sections, SECTION_PAGES):
        content.draw_text(font, SECTION_SIZE, MARGIN, y, item)
        content.draw_text(font, SECTION_SIZE, SHEET[0] - MARGIN - 10.0, y, page)
        content.save_state()
        content.set_stroke(hqf_pdf.Color.gray(0.85))
        content.set_line_width(0.4)
        content.move_to(MARGIN, y - 7.0)
        content.line_to(SHEET[0] - MARGIN, y - 7.0)
        content.stroke()
        content.restore_state()
        y -= 34.0
    content.restore_state()
    return y


def terms(content, font, words):
    """Draw the base address, and the underlined words the link is laid over."""
    y, _height = LINK
    width = font.measure(words.terms_link, SECTION_SIZE)
    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.35))
    content.draw_text(font, BODY_SIZE, MARGIN, y + 72.0, terms_first_line(words))
    content.draw_text(font, BODY_SIZE, MARGIN, y + 56.0, words.terms_lead[1])
    content.set_fill(band())
    content.draw_text(font, BODY_SIZE, MARGIN, y + 34.0, BASE)
    content.set_fill(hqf_pdf.Rgb(0.10, 0.35, 0.65))
    content.draw_text(font, SECTION_SIZE, MARGIN, y + 4.0, words.terms_link)
    content.set_stroke(hqf_pdf.Rgb(0.10, 0.35, 0.65))
    content.set_line_width(0.6)
    content.move_to(MARGIN, y)
    content.line_to(MARGIN + width, y)
    content.stroke()
    content.restore_state()


def contents(font, words):
    """The contents page: what the document opens on, and the one relative link."""
    content = hqf_pdf.Content()
    head(content, font, words.sections[1])
    y = section_list(content, font, words)

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.35))
    lines(content, font, y - 66.0, BODY_SIZE, 16.0, words.contents_body)
    content.restore_state()

    terms(content, font, words)

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.45))
    lines(content, font, 170.0, NOTE_SIZE, 14.0, words.base_note)
    content.restore_state()
    foot(content, font, words, SECTION_PAGES[1])
    return content


def on_screen(font, words):
    """What the file asks of reading software on the screen."""
    content = hqf_pdf.Content()
    head(content, font, words.sections[2])

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.35))
    y = lines(content, font, SHEET[1] - 148.0, BODY_SIZE, 16.0, words.screen_lead)
    content.restore_state()

    y -= 24.0
    for asked, does in screen_rows(words):
        setting(content, font, y, asked, does)
        y -= 44.0

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.45))
    lines(content, font, 160.0, NOTE_SIZE, 14.0, words.screen_note)
    content.restore_state()
    foot(content, font, words, SECTION_PAGES[2])
    return content


def sheet_sketch(content, font, corner, caption):
    """Draw one sheet of the little diagram.

    An outline, a band marking its head, and a caption under it.
    """
    x, y = corner
    content.save_state()
    content.set_stroke(hqf_pdf.Color.gray(0.55))
    content.set_line_width(0.8)
    content.rect(x, y, 84.0, 118.0)
    content.stroke()
    content.set_fill(band())
    content.rect(x + 8.0, y + 96.0, 68.0, 14.0)
    content.fill()
    content.set_fill(hqf_pdf.Color.gray(0.45))
    content.draw_text(font, SKETCH_SIZE, x, y - 14.0, caption)
    content.restore_state()


def long_edge(content, font, words):
    """Draw what turning a sheet on its long edge does.

    The back of the sheet stands the same way up as its front.
    """
    sheet_sketch(content, font, SKETCHES[0], words.front)
    sheet_sketch(content, font, SKETCHES[1], words.back)

    content.save_state()
    content.set_stroke(hqf_pdf.Color.gray(0.55))
    content.set_line_width(1.2)
    content.move_to(MARGIN + 146.0, 275.0)
    content.line_to(MARGIN + 246.0, 275.0)
    content.line_to(MARGIN + 234.0, 283.0)
    content.move_to(MARGIN + 246.0, 275.0)
    content.line_to(MARGIN + 234.0, 267.0)
    content.stroke()
    content.set_fill(hqf_pdf.Color.gray(0.45))
    content.draw_text(font, SKETCH_SIZE, MARGIN + 148.0, 291.0, words.long_edge)
    content.restore_state()


def at_the_printer(font, words):
    """What the file asks of the print dialogue."""
    content = hqf_pdf.Content()
    head(content, font, words.sections[3])

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.35))
    y = lines(content, font, SHEET[1] - 148.0, BODY_SIZE, 16.0, words.printer_lead)
    content.restore_state()

    y -= 24.0
    for asked, does in words.printer_settings:
        setting(content, font, y, asked, does)
        y -= 44.0

    long_edge(content, font, words)

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.45))
    lines(content, font, 160.0, NOTE_SIZE, 14.0, words.printer_note)
    content.restore_state()
    foot(content, font, words, SECTION_PAGES[3])
    return content


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("handbook.pdf", language)).stem)

    document = hqf_pdf.Document()
    document.set_license(_licence.licensed())
    document.set_metadata(
        hqf_pdf.Metadata(
            title=words.handbook,
            author=PUBLISHER,
            subject=words.subject,
        )
    )
    font = document.add_font(hqf_pdf.Font.from_path(_out.font_path()))

    first = hqf_pdf.Page(SHEET[0], SHEET[1])
    first.set_content(cover(font, words))
    document.add_page(first)

    second = hqf_pdf.Page(SHEET[0], SHEET[1])
    second.set_content(contents(font, words))
    second.add_link(
        hqf_pdf.Link.to_uri(
            MARGIN,
            LINK[0],
            font.measure(words.terms_link, SECTION_SIZE),
            LINK[1],
            TERMS_FILE,
        )
    )
    document.add_page(second)

    third = hqf_pdf.Page(SHEET[0], SHEET[1])
    third.set_content(on_screen(font, words))
    document.add_page(third)

    fourth = hqf_pdf.Page(SHEET[0], SHEET[1])
    fourth.set_content(at_the_printer(font, words))
    document.add_page(fourth)

    for page, title in enumerate(words.sections):
        document.add_bookmark(hqf_pdf.Bookmark(title, page))

    # The document opens on its contents, filled with what is drawn there, with the
    # bookmarks beside it and the cover standing on its own.
    document.set_open_action(
        hqf_pdf.OpenAction(1).view(hqf_pdf.PageFit.whole_drawing())
    )
    document.set_open_mode(hqf_pdf.OpenMode.Bookmarks)
    document.set_page_layout(hqf_pdf.PageLayout.TwoPagesOddRight)
    document.set_base_uri(BASE)
    document.set_viewer_preferences(
        hqf_pdf.ViewerPreferences()
        .hide_toolbar(False)
        .hide_menu_bar(False)
        .hide_window_controls(False)
        .reading_order(hqf_pdf.ReadingOrder.LeftToRight)
        .fit_window(True)
        .center_window(True)
        .show_title(True)
        .after_full_screen(hqf_pdf.SidePanel.Bookmarks)
        .print_scaling(hqf_pdf.PrintScaling.ActualSize)
        .duplex(hqf_pdf.Duplex.LongEdge)
        .tray_by_page_size(True)
        .copies(COPIES)
        .print_run(PRINT_RUN[0], PRINT_RUN[1])
    )

    written = document.write(out)
    print(
        f"wrote {out}: {written} bytes, {document.page_count} pages, and a "
        f"catalogue that says how to open, show and print them"
    )


if __name__ == "__main__":
    main()
