#!/bin/bash
# Does every desktop show the classroom's wallpaper — including one Plasma
# makes by itself after the layout has run?
#
# Tiny Pebbles came through the 0.2.2 upgrade with its desktop numbered 10
# and nothing configured on it, and showed Plasma's own purple wallpaper.
# The layout only reaches the desktops that exist while it runs, and a
# room whose updater reboots it at three in the morning with the
# television off has none then. The lab cannot switch a television on, so
# it makes Plasma create a desktop the other way it does, through a new
# activity: the same code in the shell, and measured to give the same
# bare containment.
#
#   tools/lab/wallpaper-check      against the running lab session
#
# Each answer is read off the screen, not out of a file: a configuration
# can say anything, and the question is what the room sees. The sky at the
# top of the classroom's picture is pale blue; Plasma's is purple.
set -uo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
LAB="$ROOT/tools/lab/lab"
NAME="${LAB_NAME:-classroom-v2-lab}"
APPLETS=/home/classroom/.config/plasma-org.kde.plasma.desktop-appletsrc

PASS=0
FAIL=0

check() {
    if [[ "$2" == "$3" ]]; then
        printf '  \033[32mPASS\033[0m  %-58s %s\n' "$1" "$3"
        PASS=$((PASS + 1))
    else
        printf '  \033[31mFAIL\033[0m  %-58s got [%s] want [%s]\n' "$1" "$3" "$2"
        FAIL=$((FAIL + 1))
    fi
}

section() { printf '\n%s\n' "$1"; }
in_lab() { docker exec "$NAME" bash -c "$1" 2>/dev/null; }
# The same, with this script's input handed through — for a program on a
# here-document. Without -i docker gives it nothing to read, and it runs
# on nothing and says nothing.
in_lab_fed() { docker exec -i "$NAME" bash -c "$1"; }
user() { "$LAB" run "$@" 2>/dev/null; }
activities() {
    user busctl --user call org.kde.ActivityManager /ActivityManager/Activities \
        org.kde.ActivityManager.Activities "$@"
}

# What is on the screen at the top middle, where the classroom's picture
# is sky and Plasma's is purple: "classroom", "plasma", or the colour.
screen() {
    "$LAB" outer grim -t ppm - 2>/dev/null | python3 -c '
import sys
data = sys.stdin.buffer.read()
fields, at = [], 0
while len(fields) < 4:
    while data[at:at + 1].isspace():
        at += 1
    end = at
    while not data[end:end + 1].isspace():
        end += 1
    fields.append(data[at:end])
    at = end
width, height = int(fields[1]), int(fields[2])
pixels = data[at + 1:]
total = [0, 0, 0]
count = 0
for y in range(20, 140, 4):
    for x in range(width * 2 // 5, width * 3 // 5, 8):
        offset = (y * width + x) * 3
        for channel in range(3):
            total[channel] += pixels[offset + channel]
        count += 1
r, g, b = (value / count for value in total)
if b > r + 25 and g > r + 10:
    print("classroom")
elif r > g + 25 and b > g + 25:
    print("plasma")
else:
    print(f"rgb({r:.0f},{g:.0f},{b:.0f})")
'
}

# The shell writes its file a few seconds after a change, not at once.
settle() { sleep "${1:-35}"; }

# The shell's file, read as groups rather than grepped, so nothing here
# can pick a line out of the wrong containment.
#
#   applets panels     each panel's number, its applets' numbers and plugins
#                      and their order. Not the panel's text: the shell adds
#                      keys of its own to applets as soon as it runs (popup
#                      sizes, the volume's migration), and that is Plasma,
#                      not the repair. tests/ checks the repair's own
#                      output byte for byte.
#   applets desktops   the desktop containments as "id:image" or "id:none",
#                      found by plugin and never by number
applets() {
    in_lab_fed "python3 - $1 $APPLETS" <<'PY'
import re, sys
mode, path = sys.argv[1], sys.argv[2]
groups, name = {}, None
for line in open(path).read().splitlines():
    if line.startswith("[") and line.endswith("]"):
        name = line
        groups[name] = []
    elif name and line:
        groups[name].append(line)
def top(cid):
    return groups.get(f"[Containments][{cid}]", [])
ids = [m.group(1) for g in groups for m in [re.match(r"^\[Containments\]\[(\d+)\]$", g)] if m]
if mode == "panels":
    for c in ids:
        if "plugin=org.kde.panel" not in top(c):
            continue
        applets = sorted(
            (int(m.group(1)), line[len("plugin=org.kde.plasma."):])
            for g in groups
            for m in [re.match(r"^\[Containments\]\[%s\]\[Applets\]\[(\d+)\]$" % c, g)] if m
            for line in groups[g] if line.startswith("plugin=")
        )
        order = [l[len("AppletOrder="):] for l in groups.get(f"[Containments][{c}][General]", [])
                 if l.startswith("AppletOrder=")]
        print(f"panel {c}:", " ".join(f"{n}={name}" for n, name in applets), "order", *order)
else:
    image = "Image=file:///usr/share/backgrounds/ekklesia/classroom-calm.png"
    out = []
    for c in ids:
        if {"plugin=org.kde.plasma.folder", "plugin=org.kde.desktopcontainment"} & set(top(c)):
            wallpaper = groups.get(f"[Containments][{c}][Wallpaper][org.kde.image][General]", [])
            out.append(f"{c}:{'image' if image in wallpaper else 'none'}")
    print(" ".join(out))
PY
}

panel_groups() { applets panels; }
desktops() { applets desktops; }

last_repair() {
    user journalctl --user -u plasma-plasmashell.service --no-pager -o cat \
        | grep '^classroom-desktop-wallpaper:' | tail -1
}

restart_shell() {
    user systemctl --user restart plasma-plasmashell.service
    for _ in $(seq 1 30); do
        in_lab 'pgrep -x plasmashell >/dev/null' && break
        sleep 1
    done
    sleep 10
}

section "the package"
check "the look and feel's default names a package" EkklesiaClassroom \
    "$(in_lab 'sed -n "/^\[Wallpaper\]/,/^\[/s/^Image=//p" /usr/share/plasma/look-and-feel/org.ekklesia.classroom.desktop/contents/defaults')"
check "which is installed, and is the classroom's picture" /usr/share/backgrounds/ekklesia/classroom-calm.png \
    "$(in_lab 'readlink -f /usr/share/wallpapers/EkklesiaClassroom/contents/images/*.png')"
check "the repair runs before every shell start" 1 \
    "$(in_lab 'grep -c "^ExecStartPre=-/usr/local/bin/classroom-desktop-wallpaper" /etc/systemd/user/plasma-plasmashell.service.d/ekklesia-classroom.conf')"

section "the session as it came up"
check "the room shows the classroom's picture" classroom "$(screen)"
original=$(activities CurrentActivity | cut -d'"' -f2)

section "a desktop Plasma makes by itself (Tiny Pebbles' television)"
panels_before=$(panel_groups)
late=$(activities AddActivity s "Late screen" | cut -d'"' -f2)
activities SetCurrentActivity s "$late" >/dev/null
settle
now=$(desktops)
check "Plasma made a second desktop" 2 "$(wc -w <<< "$now")"
check "and wrote no wallpaper into it, as on Tiny Pebbles" 1 "$(grep -o ':none' <<< "$now" | wc -l)"
check "the room still shows the classroom's picture" classroom "$(screen)"

section "the shell restarted, without a login"
restart_shell
check "the repair wrote it in" "classroom-desktop-wallpaper: the wallpaper is now configured on desktop $(tr ' ' '\n' <<< "$now" | cut -d: -f1 | paste -sd, | sed 's/,/, /g')" \
    "$(last_repair)"
check "every desktop now names the picture" 0 "$(desktops | grep -o ':none' | wc -l)"
check "the panel keeps its numbers, applets and order" "$panels_before" "$(panel_groups)"
check "the room shows the classroom's picture" classroom "$(screen)"
restart_shell
check "a second restart finds nothing to do" \
    "classroom-desktop-wallpaper: desktop $(desktops | tr ' ' '\n' | cut -d: -f1 | paste -sd, | sed 's/,/, /g'): the classroom wallpaper already" \
    "$(last_repair)"
check "and still does" "$panels_before" "$(panel_groups)"

activities SetCurrentActivity s "$original" >/dev/null
activities RemoveActivity s "$late" >/dev/null
sleep 3

section "Tiny Pebbles' own file: desktop 10, panel 1, no wallpaper"
user systemctl --user stop plasma-plasmashell.service
in_lab_fed "python3 - '$original' $APPLETS" <<'PY'
import sys
activity, path = sys.argv[1], sys.argv[2]
applets = ["quicklaunch", "panelspacer", "icontasks", "panelspacer",
           "networkmanagement", "volume", "notifications", "digitalclock"]
out = ["[Containments][1]", "activityId=", "formfactor=2", "immutability=1",
       "lastScreen=0", "location=4", "plugin=org.kde.panel",
       "wallpaperplugin=org.kde.image", ""]
for number, applet in enumerate(applets, start=2):
    out += [f"[Containments][1][Applets][{number}]", "immutability=1",
            f"plugin=org.kde.plasma.{applet}", ""]
out += ["[Containments][1][Applets][4][Configuration][General]",
        "launchers=applications:ekklesia-wonderink.desktop,applications:google-chrome.desktop,applications:ekklesia-dvd.desktop",
        "sortingStrategy=1", "",
        "[Containments][1][General]", "AppletOrder=2;3;4;5;6;7;8;9", "",
        "[Containments][10]", f"activityId={activity}", "formfactor=0",
        "immutability=1", "lastScreen=0", "location=0",
        "plugin=org.kde.plasma.folder", "wallpaperplugin=org.kde.image", "",
        "[Containments][10][General]", 'positions={"1920x1080":[]}', ""]
open(path, "w").write("\n".join(out))
PY
in_lab "chown classroom:classroom $APPLETS"
panels_before=$(panel_groups)
user systemctl --user start plasma-plasmashell.service
sleep 12
check "the repair found desktop 10 and wrote it" \
    "classroom-desktop-wallpaper: the wallpaper is now configured on desktop 10" "$(last_repair)"
check "desktop 10 names the picture" "10:image" "$(desktops)"
check "the panel is still containment 1, applets 2 to 9, in order" "$panels_before" "$(panel_groups)"
check "the room shows the classroom's picture" classroom "$(screen)"

section "and at the next login"
"$LAB" plasma-down >/dev/null
"$LAB" plasma-up >/dev/null
settle 10
check "the reset left the repair nothing to do" \
    "classroom-desktop-wallpaper: no desktop configuration yet; the layout writes the wallpaper" \
    "$(last_repair)"
check "the layout rebuilt one desktop with the picture" 1 "$(desktops | grep -o ':image' | wc -l)"
check "the room shows the classroom's picture" classroom "$(screen)"

printf '\n%s passed, %s failed\n' "$PASS" "$FAIL"
[[ "$FAIL" -eq 0 ]]
