"""Fills text and a shape with a gradient, through a shading pattern.

The Python twin of the `write_gradient_fill` example in Rust. Where
`write_gradient` paints a gradient into a clipped box, this makes a gradient the
colour something is filled with: a headline whose letters are windows onto a
three-stop blend, and a panel filled with a radial one. The gradient lives in
the page's own space, so the letters show the part of it behind them.

A band at the foot of the page is filled with a gradient laid along the pattern's own
horizontal axis and turned upright by the pattern's matrix, and edged with the panel's
radial gradient. The panel's pattern carries a graphics state of its own, which
paints it at 70 % opacity.

The three captions are held in `Words`, once per language, and `HQF_PDF_LANG` picks which
set is drawn. The headline is the library's own name and reads the same in every
language.

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

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# The headline the gradient fills, which is the library's own name.
HEADLINE = "hqf-pdf"


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

    # The caption under the headline.
    letters: str
    # The caption under the panel.
    shape: str
    # The caption under the band.
    placed: str


# The page in English.
ENGLISH = Words(
    letters="Text filled with a gradient, through a shading pattern.",
    shape="A radial gradient, painted by its pattern at 70 % opacity.",
    placed="A gradient laid flat, stood upright by its pattern's matrix, edged in radial.",
)

# The page in French.
FRENCH = Words(
    letters="Du texte rempli par un dégradé, au moyen d’un motif.",
    shape="Un dégradé radial, peint par son motif à 70 % d’opacité.",
    placed=(
        "Un dégradé couché, redressé par la matrice de son motif, bordé en radial."
    ),
)

# The page in Dutch.
DUTCH = Words(
    letters="Tekst gevuld met een verloop, via een arceringspatroon.",
    shape="Een radiaal verloop, geschilderd door zijn patroon op 70 % dekking.",
    placed="Een plat verloop, rechtgezet door de patroonmatrix; radiale rand.",
)

# The page in Portuguese.
PORTUGUESE = Words(
    letters="Texto preenchido com um degradé, por um padrão de sombreado.",
    shape="Um degradé radial, pintado pelo seu padrão a 70 % de opacidade.",
    placed="Um degradé deitado, endireitado pela matriz do padrão, orlado em radial.",
)

# The page in Italian.
ITALIAN = Words(
    letters="Testo riempito con un gradiente, tramite un motivo di sfumatura.",
    shape="Un gradiente radiale, dipinto dal suo motivo al 70 % di opacità.",
    placed="Un gradiente disteso, raddrizzato dalla matrice del motivo; bordo radiale.",
)

# The page in Spanish.
SPANISH = Words(
    letters="Texto relleno con un degradado, mediante un patrón de sombreado.",
    shape="Un degradado radial, pintado por su patrón al 70 % de opacidad.",
    placed="Un degradado tumbado, enderezado por la matriz del patrón; borde radial.",
)

# The page in German.
GERMAN = Words(
    letters="Text, über ein Schattierungsmuster mit einem Verlauf gefüllt.",
    shape="Ein radialer Verlauf, vom Muster mit 70 % Deckkraft gemalt.",
    placed="Ein flacher Verlauf, von der Mustermatrix aufgerichtet, radial umrandet.",
)


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

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

    left = 70.0

    # A three-stop gradient spanning the width of the headline, set as a fill pattern so
    # the letters show it through their shapes.
    headline_size = 84.0
    headline_baseline = 660.0
    headline_width = handle.measure(HEADLINE, headline_size)
    ramp = hqf_pdf.Function.stitching(
        (0.0, 1.0),
        [
            hqf_pdf.Function.exponential(
                (0.0, 1.0), 1.0, ([0.85, 0.12, 0.12], [0.12, 0.55, 0.2])
            ),
            hqf_pdf.Function.exponential(
                (0.0, 1.0), 1.0, ([0.12, 0.55, 0.2], [0.12, 0.2, 0.8])
            ),
        ],
        [0.5],
        [(0.0, 1.0), (0.0, 1.0)],
    )
    letters = document.add_shading_pattern(
        hqf_pdf.Axial(
            (left, headline_baseline),
            (left + headline_width, headline_baseline),
            hqf_pdf.DeviceSpace.Rgb,
            ramp,
        )
    )

    # A radial gradient filling a panel below the headline, painted under a state of the
    # pattern's own.
    px, py, pw, ph = left, 350.0, 455.0, 190.0
    see_through = document.add_ext_gstate(hqf_pdf.ExtGState(fill_alpha=0.7))
    panel = document.add_shading_pattern(
        hqf_pdf.Radial.rgb(
            (px + pw / 2.0, py + ph / 2.0, 0.0),
            (px + pw / 2.0, py + ph / 2.0, pw / 2.0),
            hqf_pdf.Rgb(1.0, 1.0, 1.0),
            hqf_pdf.Rgb(0.1, 0.15, 0.45),
        ).extend(False, True),
        state=see_through,
    )

    # A gradient laid from red to blue along the pattern's own horizontal axis, over the
    # band's height; the matrix turns that axis upright and stands it at the band's
    # foot.
    bx, by, bw, bh = left, 150.0, 455.0, 120.0
    upright = document.add_shading_pattern(
        hqf_pdf.Axial.rgb(
            (0.0, 0.0),
            (bh, 0.0),
            hqf_pdf.Rgb(0.85, 0.12, 0.12),
            hqf_pdf.Rgb(0.12, 0.2, 0.8),
        ).extend(True, True),
        matrix=(0.0, 1.0, -1.0, 0.0, bx, by),
    )

    content = hqf_pdf.Content()

    # The headline, its letters filled with the gradient.
    content.save_state()
    content.set_fill_pattern(letters)
    content.draw_text(handle, headline_size, left, headline_baseline, HEADLINE)
    content.restore_state()

    # A caption, in plain black.
    content.draw_text(handle, 13.0, left, headline_baseline - 26.0, words.letters)

    # The panel, filled with the radial gradient.
    content.save_state()
    content.set_fill(hqf_pdf.Paint.pattern(panel))
    content.rect(px, py, pw, ph)
    content.fill()
    content.restore_state()

    content.draw_text(handle, 12.0, px, py - 16.0, words.shape)

    # The band, filled with the turned gradient and edged with the panel's.
    content.save_state()
    content.set_fill(hqf_pdf.Paint.pattern(upright))
    content.set_stroke_pattern(panel)
    content.set_line_width(6.0)
    content.rect(bx, by, bw, bh)
    content.fill_and_stroke()
    content.restore_state()

    content.draw_text(handle, 12.0, bx, by - 16.0, words.placed)

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

    written = document.write(out)
    print(f"wrote {out}: {written} bytes")


if __name__ == "__main__":
    main()
