"""Text that has to be printed on the page to be kept.

The vetting agent copies a table's caption and title off the page. A copy is
accepted only when the page's text layer contains it, the rule values already
follow: anything the page does not print was read off nothing.

`printed_key` folds what rendering changes and reading does not. Whitespace,
dashes and colons are dropped, so a title printed over two lines or a footnote
digit set as a superscript still matches; curly quotes and apostrophes become
straight; case is dropped. Two strings with the same key are the same printed
words.
"""

from __future__ import annotations

import re
from typing import List, Sequence, Tuple

_FOLD_RE = re.compile(r"[\s—–:\-]+")
_QUOTES = str.maketrans({"’": "'", "‘": "'", "“": '"', "”": '"', "„": '"'})

#: One word of the page text layer: x0, top, x1, bottom in points with a
#: top-left origin, then the word.
WordBox = Tuple[float, float, float, float, str]

#: Words whose top edges fall within one band this tall are one printed line.
LINE_BAND_PTS = 4.0


def printed_key(text: str) -> str:
    """The comparison form of printed text."""
    return _FOLD_RE.sub("", text.translate(_QUOTES)).lower()


def is_printed(value: str, page_text: str) -> bool:
    """Whether `value` occurs in `page_text`, compared by printed key. Empty
    text is not printed."""
    key = printed_key(value)
    return bool(key) and key in printed_key(page_text)


def page_lines(words: Sequence[WordBox]) -> List[str]:
    """The page's words as printed lines in reading order, top to bottom and
    left to right. Two tables printed side by side share lines, which is how
    the page prints them."""
    ordered = sorted(words, key=lambda w: (round(w[1] / LINE_BAND_PTS), w[0]))
    lines: List[str] = []
    current: List[str] = []
    band = None
    for w in ordered:
        b = round(w[1] / LINE_BAND_PTS)
        if band is not None and b != band:
            lines.append(" ".join(current))
            current = []
        current.append(w[4])
        band = b
    if current:
        lines.append(" ".join(current))
    return lines
