"""A sheet as it goes to the press, and what each box a page states does to it.

The Python twin of the `write_press_sheet` example in Rust. A page has always had
a sheet. It now also has the four boxes a printer reads: what the ink runs to,
where the blade falls, what is worth keeping, and what a reader shows.

Usage: python examples/write_press_sheet.py [out.pdf] [font.ttf]
"""

from __future__ import annotations

import _licence
import _out

import hqf_pdf

# How far past the blade the ink runs.
BLEED_OVER = 9.0
# How much sheet is left outside the ink for the marks.
MARK_ROOM = 27.0
# How long one arm of a corner mark is.
MARK_LENGTH = 18.0

# How much sheet stands outside the finished page on every side.
MARGIN = BLEED_OVER + MARK_ROOM

# The finished page: where the blade falls, in the sheet's own coordinates.
TRIM = (MARGIN, MARGIN, 400.0, 560.0)

# The whole sheet: the finished page, the ink that runs past it, and the room the marks
# stand in.
SHEET = (TRIM[2] + MARGIN + MARGIN, TRIM[3] + MARGIN + MARGIN)

# How far inside the blade the drawing itself keeps.
ART_INSET = 40.0

# The colour the band across the top is laid in.
BAND = (0.11, 0.26, 0.44)

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


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


def trim():
    """Where the blade falls."""
    return hqf_pdf.Rect(TRIM[0], TRIM[1], TRIM[2], TRIM[3])


def bleed():
    """What the ink runs to."""
    return hqf_pdf.Rect(
        TRIM[0] - BLEED_OVER,
        TRIM[1] - BLEED_OVER,
        TRIM[2] + BLEED_OVER + BLEED_OVER,
        TRIM[3] + BLEED_OVER + BLEED_OVER,
    )


def art():
    """What is worth keeping of the page."""
    return hqf_pdf.Rect(
        TRIM[0] + ART_INSET,
        TRIM[1] + ART_INSET,
        TRIM[2] - ART_INSET - ART_INSET,
        TRIM[3] - ART_INSET - ART_INSET,
    )


def corner_marks(content):
    """Draw the four corner marks.

    Each pair of arms stands outside the ink and points at a corner of the
    finished page.
    """
    left, bottom, width, height = TRIM
    right = left + width
    top = bottom + height
    near = BLEED_OVER
    far = BLEED_OVER + MARK_LENGTH

    content.save_state()
    content.set_stroke(hqf_pdf.Color.gray(0.0))
    content.set_line_width(0.4)
    for x, from_x, to_x in [
        (left, left - near, left - far),
        (right, right + near, right + far),
    ]:
        for y, from_y, to_y in [
            (bottom, bottom - near, bottom - far),
            (top, top + near, top + far),
        ]:
            content.move_to(from_x, y)
            content.line_to(to_x, y)
            content.move_to(x, from_y)
            content.line_to(x, to_y)
    content.stroke()
    content.restore_state()


def listing(content, font, top, keep):
    """Draw the list itself, one row a line, each under a hairline."""
    right = keep.x + keep.width
    y = top
    for item, price in [
        ("Linen paper, ream", "18.40"),
        ("Bookbinder's thread", "6.90"),
        ("Corner mark punch", "42.00"),
        ("Trim gauge, steel", "31.50"),
        ("Bleed guide, acrylic", "12.75"),
        ("Press blanket wash", "9.20"),
    ]:
        content.save_state()
        content.set_fill(hqf_pdf.Color.gray(0.25))
        content.draw_text(font, 10.0, keep.x, y, item)
        content.draw_text(font, 10.0, right - 30.0, y, price)
        content.set_stroke(hqf_pdf.Color.gray(0.8))
        content.set_line_width(0.4)
        content.move_to(keep.x, y - 8.0)
        content.line_to(right, y - 8.0)
        content.stroke()
        content.restore_state()
        y -= 26.0


def artwork(content, font):
    """Draw the artwork: a band off the blade, a title, body, a list, a footer."""
    ink = bleed()
    keep = art()

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.96))
    content.rect(ink.x, ink.y, ink.width, ink.height)
    content.fill()
    content.set_fill(band())
    content.rect(ink.x, ink.y + ink.height - 150.0, ink.width, 150.0)
    content.fill()
    content.restore_state()

    content.save_state()
    content.set_fill(hqf_pdf.Rgb(1.0, 1.0, 1.0))
    content.draw_text(
        font, 22.0, keep.x, keep.y + keep.height - 30.0, "Autumn list"
    )
    content.set_fill(hqf_pdf.Rgb(0.82, 0.86, 0.92))
    content.draw_text(
        font,
        10.0,
        keep.x,
        keep.y + keep.height - 50.0,
        "The band above runs off the blade: no white edge is left.",
    )
    content.restore_state()

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.25))
    y = keep.y + keep.height - 130.0
    for line in [
        "The blade never falls exactly where it is",
        "aimed. A sheet allows for that twice over:",
        "the ink runs past the cut, and nothing that",
        "matters stands within a few points of it.",
        "",
        "The boxes say all three distances, so nobody",
        "has to measure the file to find out where the",
        "page really ends.",
    ]:
        content.draw_text(font, 10.0, keep.x, y, line)
        y -= 16.0
    content.restore_state()

    listing(content, font, keep.y + keep.height - 290.0, keep)

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.5))
    content.draw_text(
        font, 8.0, keep.x, keep.y, "HQF Development — one sheet, four boxes"
    )
    content.restore_state()


def guides(content, font):
    """Draw the guide showing where each box falls, and name it."""
    content.save_state()
    content.set_line_width(0.4)
    for box, color, label in [
        (bleed(), hqf_pdf.Rgb(0.85, 0.35, 0.20), "bleed"),
        (trim(), hqf_pdf.Rgb(0.20, 0.55, 0.35), "trim"),
        (art(), hqf_pdf.Rgb(0.45, 0.35, 0.65), "art"),
    ]:
        content.set_stroke(color)
        content.rect(box.x, box.y, box.width, box.height)
        content.stroke()
        content.set_fill(color)
        content.draw_text(font, 7.0, box.x + box.width - 30.0, box.y - 8.0, label)
    content.restore_state()


def sheet(font, note):
    """The whole sheet: artwork, marks, guides, and the note in the margin."""
    content = hqf_pdf.Content()
    artwork(content, font)
    corner_marks(content)
    guides(content, font)

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.35))
    y = 8.0
    for line in reversed(note):
        content.draw_text(font, 7.0, TRIM[0], y, line)
        y += 9.0
    content.restore_state()
    return content


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

    A sheet taller than it is wide is one the reader has not turned yet, so the
    head of the drawing runs down its left edge; a wide one has been turned, and
    the head is along its top.
    """
    x, y, width, height = corner
    if height > width:
        head = (x + 8.0, y + 8.0, 12.0, height - 16.0)
    else:
        head = (x + 8.0, y + height - 20.0, width - 16.0, 12.0)

    content.save_state()
    content.set_stroke(hqf_pdf.Color.gray(0.55))
    content.set_line_width(0.8)
    content.rect(x, y, width, height)
    content.stroke()
    content.set_fill(band())
    content.rect(head[0], head[1], head[2], head[3])
    content.fill()
    content.set_fill(hqf_pdf.Color.gray(0.45))
    content.draw_text(font, 8.0, x, y - 14.0, caption)
    content.restore_state()


def turned(font):
    """A landscape page inside an upright document.

    Everything is laid out in a space as wide as the sheet is tall, and the one
    transform at the head of the stream puts that space onto the upright sheet.
    """
    across, up = A4[1], A4[0]
    content = hqf_pdf.Content()
    content.transform((0.0, 1.0, -1.0, 0.0, A4[0], 0.0))

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.96))
    content.rect(0.0, 0.0, across, up)
    content.fill()
    content.set_fill(band())
    content.rect(0.0, up - 90.0, across, 90.0)
    content.fill()
    content.restore_state()

    content.save_state()
    content.set_fill(hqf_pdf.Rgb(1.0, 1.0, 1.0))
    content.draw_text(
        font, 18.0, 70.0, up - 55.0, "A landscape page inside an upright document"
    )
    content.restore_state()

    content.save_state()
    content.set_fill(hqf_pdf.Color.gray(0.3))
    y = up - 130.0
    for line in [
        "This page is the same upright sheet as the two before it: 595 points "
        "across, 842 up. What",
        "it adds is one number saying that a reader turns it a quarter clockwise "
        "before showing it.",
        "",
        "So the words are wider than the sheet they are written on, and nobody "
        "has to be handed a",
        "second page size to say so. A reader printing the file turns the paper "
        "rather than the",
        "drawing, and a reader showing it hands you the page the way round it "
        "was meant.",
    ]:
        content.draw_text(font, 10.0, 70.0, y, line)
        y -= 16.0
    content.restore_state()

    sketch(content, font, (150.0, 140.0, 110.0, 155.0), "as it sits in the file")
    sketch(content, font, (400.0, 165.0, 155.0, 110.0), "as a reader shows it")

    content.save_state()
    content.set_stroke(hqf_pdf.Color.gray(0.55))
    content.set_line_width(1.2)
    content.move_to(295.0, 218.0)
    content.line_to(360.0, 218.0)
    content.line_to(348.0, 226.0)
    content.move_to(360.0, 218.0)
    content.line_to(348.0, 210.0)
    content.stroke()
    content.set_fill(hqf_pdf.Color.gray(0.45))
    content.draw_text(font, 8.0, 288.0, 234.0, "a quarter clockwise")
    content.restore_state()
    return content


def main() -> None:
    out = _out.output_path("press")

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

    first = hqf_pdf.Page(SHEET[0], SHEET[1])
    first.set_content(
        sheet(
            font,
            [
                "Page 1 states the bleed, the trim and the art, and no crop: a "
                "reader shows the whole",
                "sheet, marks and all, which is what the press wants to see.",
            ],
        )
    )
    first.set_bleed_box(bleed())
    first.set_trim_box(trim())
    first.set_art_box(art())
    document.add_page(first)

    second = hqf_pdf.Page(SHEET[0], SHEET[1])
    second.set_content(
        sheet(
            font,
            [
                "Page 2 is the same drawing and the same boxes, plus a crop set "
                "to the trim: a reader",
                "shows the finished page alone. Nothing was removed — what is "
                "outside is still here.",
            ],
        )
    )
    second.set_crop_box(trim())
    second.set_bleed_box(bleed())
    second.set_trim_box(trim())
    second.set_art_box(art())
    document.add_page(second)

    third = hqf_pdf.Page.a4()
    third.set_content(turned(font))
    third.set_turn(hqf_pdf.PageTurn.Right)
    document.add_page(third)

    written = document.write(out)
    print(
        f"wrote {out}: {written} bytes, one drawing on {document.page_count} "
        f"pages, each stating its own boxes"
    )


if __name__ == "__main__":
    main()
