"""
Code 128 encoder, subset B.

The barcode in the Auto SKUS mark is a real symbol, not decoration. It carries
a start character, the payload, a mod-103 checksum and a stop pattern, with
proper quiet zones, so a scanner reads it.

Each pattern is six width values (bar, space, bar, space, bar, space) totalling
11 modules. The stop pattern is seven values totalling 13.
"""

PATTERNS = [
    "212222","222122","222221","121223","121322","131222","122213","122312",
    "132212","221213","221312","231212","112232","122132","122231","113222",
    "123122","123221","223211","221132","221231","213212","223112","312131",
    "311222","321122","321221","312212","322112","322211","212123","212321",
    "232121","111323","131123","131321","112313","132113","132311","211313",
    "231113","231311","112133","112331","132131","113123","113321","133121",
    "313121","211331","231131","213113","213311","213131","311123","311321",
    "331121","312113","312311","332111","314111","221411","431111","111224",
    "111422","121124","121421","141122","141221","112214","112412","122114",
    "122411","142112","142211","241211","221114","413111","241112","134111",
    "111242","121142","121241","114212","124112","124211","411212","421112",
    "421211","212141","214121","412121","111143","111341","131141","114113",
    "114311","411113","411311","113141","114131","311141","411131","211412",
    "211214","211232","2331112",
]

START_B = 104
STOP = 106
QUIET_MODULES = 10          # ISO minimum quiet zone either side


def encode(text):
    """
    Return (elements, total_modules) where elements is a list of
    (width_in_modules, is_bar) covering start + data + checksum + stop.
    """
    for ch in text:
        if not (32 <= ord(ch) <= 126):
            raise ValueError(f"{ch!r} is not encodable in Code 128 subset B")

    values = [ord(c) - 32 for c in text]
    checksum = START_B
    for i, v in enumerate(values, start=1):
        checksum += v * i
    checksum %= 103

    sequence = [START_B] + values + [checksum, STOP]

    elements, total = [], 0
    for v in sequence:
        is_bar = True
        for w in PATTERNS[v]:
            w = int(w)
            elements.append((w, is_bar))
            total += w
            is_bar = not is_bar
    return elements, total


def decode_check(text):
    """Independent recomputation of the checksum, for verification."""
    c = START_B
    for i, ch in enumerate(text, start=1):
        c += (ord(ch) - 32) * i
    return c % 103


if __name__ == "__main__":
    for s in ("AUTOSKUS", "AUTOSKUS.COM", "EARN THE SHELF"):
        els, total = encode(s)
        bars = sum(1 for _, b in els if b)
        print(f"{s:<16} modules={total:4d}  elements={len(els):3d}  "
              f"bars={bars:3d}  checksum={decode_check(s)}")
