"""Shows what a cell can do with its own box: the margin around it, the border on
each of its sides, and the padding within it.

The Python twin of the `write_table_borders` example in Rust. The table declares no
rule of its own, so every line on the page is drawn by the cell it belongs to. That
is the whole point of a cell border: it is the cell's, not the grid's, and a cell
can carry one on a single side.

Every word the sheet draws is held in `Words`, once per language, and `HQF_PDF_LANG`
picks which one is drawn.

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

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# The margins, and the box the table is fitted into.
MARGIN = 56.0
TOP = 780.0
PAGE_WIDTH = 595.276
TABLE_WIDTH = PAGE_WIDTH - 2 * MARGIN


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

    # The line set over the sheet.
    title: str
    # The word drawn inside every demonstration cell.
    cell: str
    # What each sample demonstrates, in the order ``samples`` builds them.
    samples: tuple[str, ...]


# The sheet in English.
ENGLISH = Words(
    title="Borders, margins and padding",
    cell="Cell",
    samples=(
        "The top, and nothing else",
        "The bottom, and nothing else",
        "The left",
        "The right",
        "The top and the bottom",
        "All four sides",
        "A 0.25 pt rule",
        "A 2.5 pt rule",
        "A weight of its own on each side",
        "A rule in colour",
        "A margin holds the cell off its column",
        "A negative margin runs it past its column instead",
        "Padding holds the text off the rule",
    ),
)

# The sheet in French.
FRENCH = Words(
    title="Bordures, marges et retraits",
    cell="Cellule",
    samples=(
        "Le haut, et rien d'autre",
        "Le bas, et rien d'autre",
        "La gauche",
        "La droite",
        "Le haut et le bas",
        "Les quatre côtés",
        "Un filet de 0.25 pt",
        "Un filet de 2.5 pt",
        "Une épaisseur par côté",
        "Un filet en couleur",
        "Une marge écarte la cellule de sa colonne",
        "Une marge négative la fait déborder de sa colonne",
        "Un retrait écarte le texte du filet",
    ),
)


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


@dataclass(frozen=True)
class Sample:
    """One line of the sheet: the cell that shows a sample, and how it is built."""

    border: hqf_pdf.Border
    margin: hqf_pdf.Margin
    padding: hqf_pdf.Padding
    fill: hqf_pdf.Rgb | None = None


def samples() -> list[Sample]:
    """The samples, in the order ``Words.samples`` names them."""
    rule = hqf_pdf.Stroke(0.8)
    hairline = hqf_pdf.Stroke(0.25)
    heavy = hqf_pdf.Stroke(2.5)
    ink = hqf_pdf.Stroke(1.0, hqf_pdf.Rgb(0.78, 0.14, 0.12))

    def plain(border: hqf_pdf.Border) -> Sample:
        return Sample(
            border,
            hqf_pdf.Margin.symmetric(0.0, 3.0),
            hqf_pdf.Padding.symmetric(6.0, 4.0),
        )

    shade = hqf_pdf.Rgb.gray(0.92)
    pad = hqf_pdf.Padding.symmetric(6.0, 4.0)

    return [
        plain(hqf_pdf.Border(top=rule)),
        plain(hqf_pdf.Border(bottom=rule)),
        plain(hqf_pdf.Border(left=rule)),
        plain(hqf_pdf.Border(right=rule)),
        plain(hqf_pdf.Border(top=rule, bottom=rule)),
        plain(hqf_pdf.Border.uniform(rule)),
        plain(hqf_pdf.Border.uniform(hairline)),
        plain(hqf_pdf.Border.uniform(heavy)),
        plain(hqf_pdf.Border(top=hairline, bottom=heavy, left=rule, right=rule)),
        plain(hqf_pdf.Border.uniform(ink)),
        Sample(
            hqf_pdf.Border.uniform(rule),
            hqf_pdf.Margin.uniform(10.0),
            pad,
            shade,
        ),
        Sample(
            hqf_pdf.Border.uniform(rule),
            hqf_pdf.Margin.symmetric(-10.0, 3.0),
            pad,
            shade,
        ),
        Sample(
            hqf_pdf.Border.uniform(rule),
            hqf_pdf.Margin.symmetric(0.0, 3.0),
            hqf_pdf.Padding.uniform(14.0),
            shade,
        ),
    ]


def border_sheet(font: hqf_pdf.FontHandle, words: Words) -> hqf_pdf.Table:
    """The sheet: a line per sample, its name on the left and the cell that shows
    it on the right."""
    # No rule is declared on this table: every line the page shows is a cell's own
    # border.
    columns = hqf_pdf.Columns(
        [hqf_pdf.ColumnWidth.fraction(1.0), hqf_pdf.ColumnWidth.points(210.0)],
        TABLE_WIDTH,
    )
    table = hqf_pdf.Table(columns)

    for sample, label in zip(samples(), words.samples):
        table.push(
            hqf_pdf.Row(
                [
                    hqf_pdf.Cell(
                        font,
                        9.0,
                        label,
                        valign=hqf_pdf.VAlign.Middle,
                        padding=hqf_pdf.Padding.symmetric(0.0, 4.0),
                    ),
                    hqf_pdf.Cell(
                        font,
                        9.0,
                        words.cell,
                        align=hqf_pdf.Align.Center,
                        valign=hqf_pdf.VAlign.Middle,
                        border=sample.border,
                        margin=sample.margin,
                        padding=sample.padding,
                        fill=sample.fill,
                    ),
                ],
                min_height=34.0,
            )
        )

    return table


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

    document = hqf_pdf.Document()
    document.set_license(_licence.licensed())
    font = document.add_font(hqf_pdf.Font.from_path(_out.font_path()))

    table = border_sheet(font, words)

    content = hqf_pdf.Content()
    content.draw_text(font, 14.0, MARGIN, TOP + 24.0, words.title)

    placed = table.fit(MARGIN, TOP, TOP - MARGIN)
    placed.draw(content)

    page = hqf_pdf.Page.a4()
    page.set_content(content)
    document.add_page(page)

    written = document.write(out)
    print(f"wrote {out}: {written} bytes, 1 page, {table.row_count} rows")


if __name__ == "__main__":
    main()
