#!/usr/bin/env python3

"""Read the classroom bar off the screen and say what order it is in.

The launcher-order bug of 0.2.4 got past a full set of configuration
tests, because the configuration was right and the applet did something
else with it. So this asks the picture.

It captures the panel strip as a PPM — no image library anywhere in this
lab, and PPM is a length, three numbers and the bytes — finds the icons by
looking for columns that are not the bar's own background, and names each
one by its colour. Three icons, three colours that are nothing like each
other:

    Wonder Ink   orange and blue, and orange is what a column of it
                 averages to
    Browser      Chrome's wheel: red, green, yellow and blue, so its
                 average is unusually grey for something this bright
    the player   one flat purple disc

Usage:  panel-order [STRIP]        default "0,990 1920x90"
Prints one name per icon, left to right.
"""

import subprocess
import sys

CONTAINER = "classroom-v2-lab"
STRIP = sys.argv[1] if len(sys.argv) > 1 else "0,990 1920x90"


def capture():
    socket = subprocess.run(
        ["docker", "exec", CONTAINER, "sh", "-c",
         "ls /run/user/1000/sway-ipc.* 2>/dev/null | head -1"],
        capture_output=True, text=True, check=True).stdout.strip()

    raw = subprocess.run(
        ["docker", "exec", "-u", "classroom",
         "-e", "XDG_RUNTIME_DIR=/run/user/1000",
         "-e", "WAYLAND_DISPLAY=wayland-1",
         "-e", f"SWAYSOCK={socket}",
         CONTAINER, "grim", "-t", "ppm", "-g", STRIP, "-"],
        capture_output=True, check=True).stdout

    return raw


def pixels(raw):
    """(width, height, rows) from a binary PPM."""
    fields = []
    index = 0

    while len(fields) < 4:
        while raw[index:index + 1].isspace():
            index += 1

        if raw[index:index + 1] == b"#":
            while raw[index:index + 1] not in (b"\n", b""):
                index += 1
            continue

        start = index

        while not raw[index:index + 1].isspace():
            index += 1

        fields.append(raw[start:index])

    index += 1
    width, height = int(fields[1]), int(fields[2])
    body = raw[index:]
    rows = [
        body[y * width * 3:(y + 1) * width * 3]
        for y in range(height)
    ]

    return width, height, rows


def columns(width, height, rows):
    """Average colour and brightness of each column."""
    found = []

    for x in range(width):
        r = g = b = 0

        for row in rows:
            r += row[x * 3]
            g += row[x * 3 + 1]
            b += row[x * 3 + 2]

        found.append((r // height, g // height, b // height))

    return found


def name(colour):
    r, g, b = colour

    # The disc: blue and red well above green.
    if b > g + 25 and r > g + 15:
        return "player"

    # Wonder Ink: warm, red clearly ahead of blue.
    if r > b + 25:
        return "wonderink"

    return "browser"


def main():
    width, height, rows = pixels(capture())
    found = columns(width, height, rows)

    # The bar is dark and flat; an icon is a run of brighter columns.
    floor = sorted(sum(c) for c in found)[len(found) // 2] + 60
    runs = []
    run = None

    for x, colour in enumerate(found):
        if sum(colour) > floor:
            if run is None:
                run = [x, x]
            else:
                run[1] = x
        elif run is not None:
            if run[1] - run[0] >= 12:
                runs.append(run)
            run = None

    if run is not None and run[1] - run[0] >= 12:
        runs.append(run)

    # The applications live in the middle third; the corners are Parent
    # Call on the left and the status icons on the right.
    middle = [
        item for item in runs
        if width // 3 < (item[0] + item[1]) // 2 < (width * 2) // 3
    ]

    for first, last in middle:
        centre = (first + last) // 2
        window = found[max(first, centre - 8):min(last, centre + 8) + 1]
        r = sum(c[0] for c in window) // max(1, len(window))
        g = sum(c[1] for c in window) // max(1, len(window))
        b = sum(c[2] for c in window) // max(1, len(window))
        print(name((r, g, b)))

    return 0


if __name__ == "__main__":
    sys.exit(main())
