<?php
/**
 * staff.php
 *
 * Moodle-launched staff print queue for requests created in search.php.
 * Moodle is the only identity and access authority. This page has no local
 * accounts, passwords, registration, or staff-user repository.
 */

declare(strict_types=1);

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/lib.php';

header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: no-referrer');
header('Content-Type: text/html; charset=UTF-8');
header("Content-Security-Policy: frame-ancestors 'self' https://www.maxxlms.com https://maxxlms.com");

error_reporting(E_ALL);
ini_set('display_errors', '0');

session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);
session_start();

function valid_moodle_identifier(mixed $value): ?string
{
    if (!is_string($value)) {
        return null;
    }

    $value = trim($value);
    if ($value === '' || !preg_match('/^[A-Za-z0-9._@-]{1,128}$/', $value)) {
        return null;
    }

    return $value;
}

function staff_csrf_ok(): bool
{
    $posted = $_POST['csrf_token'] ?? '';
    $stored = $_SESSION['staff_csrf_token'] ?? '';

    return is_string($posted)
        && is_string($stored)
        && $posted !== ''
        && hash_equals($stored, $posted);
}

function current_moodle_staff_identifier(): ?string
{
    if (($_SESSION['staff_launch_authorized'] ?? false) !== true) {
        return null;
    }

    return valid_moodle_identifier($_SESSION['moodle_staff_identifier'] ?? null);
}

/** Return a unique, bounded list of positive print-request IDs. */
function valid_print_request_ids(mixed $value): array
{
    if (!is_array($value)) {
        return [];
    }

    $ids = [];
    foreach ($value as $candidate) {
        $id = filter_var($candidate, FILTER_VALIDATE_INT, [
            'options' => ['min_range' => 1],
        ]);
        if ($id !== false) {
            $ids[(int) $id] = (int) $id;
        }
        if (count($ids) >= 100) {
            break;
        }
    }

    return array_values($ids);
}

// ---------------------------------------------------------------------------
// Initial launch from the hidden Moodle staff URL activity
// ---------------------------------------------------------------------------

$hasLaunchParameters = array_key_exists('staff_key', $_GET) || array_key_exists('username', $_GET);
if ($hasLaunchParameters) {
    $providedKey = $_GET['staff_key'] ?? null;
    $moodleStaffIdentifier = valid_moodle_identifier($_GET['username'] ?? null);
    $validKey = is_string($providedKey)
        && defined('STAFF_LAUNCH_TOKEN')
        && STAFF_LAUNCH_TOKEN !== ''
        && hash_equals(STAFF_LAUNCH_TOKEN, $providedKey);

    if ($validKey && $moodleStaffIdentifier !== null) {
        session_regenerate_id(true);
        $_SESSION['staff_launch_authorized'] = true;
        $_SESSION['moodle_staff_identifier'] = $moodleStaffIdentifier;
        $_SESSION['staff_csrf_token'] = bin2hex(random_bytes(32));

        // Remove the private key from the visible iframe address after the
        // session has been established.
        header('Location: https://lawlibrary.maxxlms.com/staff.php');
        exit;
    }

    unset(
        $_SESSION['staff_launch_authorized'],
        $_SESSION['moodle_staff_identifier'],
        $_SESSION['staff_csrf_token']
    );
}

$staffIdentifier = current_moodle_staff_identifier();
$accessDenied = $staffIdentifier === null;
if ($accessDenied) {
    http_response_code(403);
}

if (!$accessDenied && empty($_SESSION['staff_csrf_token'])) {
    $_SESSION['staff_csrf_token'] = bin2hex(random_bytes(32));
}

// ---------------------------------------------------------------------------
// Authenticated staff actions
// ---------------------------------------------------------------------------

$actionError = null;
$batchPrintIds = [];
$postAction = is_string($_POST['action'] ?? null) ? $_POST['action'] : '';
$allowedPostActions = [
    'mark_printed',
    'mark_cancelled',
    'bulk_mark_printed',
    'bulk_mark_cancelled',
    'print_selected',
];

if (
    !$accessDenied
    && $_SERVER['REQUEST_METHOD'] === 'POST'
    && in_array($postAction, $allowedPostActions, true)
) {
    if (!staff_csrf_ok()) {
        $actionError = 'Your staff session expired. Please reopen this activity from Moodle.';
    } elseif ($postAction === 'print_selected') {
        $batchPrintIds = valid_print_request_ids($_POST['request_ids'] ?? []);
        if ($batchPrintIds === []) {
            $actionError = 'Select at least one pending print request.';
        }
    } else {
        if (str_starts_with($postAction, 'bulk_')) {
            $requestIds = valid_print_request_ids($_POST['request_ids'] ?? []);
        } else {
            $singleId = filter_var($_POST['request_id'] ?? '', FILTER_VALIDATE_INT, [
                'options' => ['min_range' => 1],
            ]);
            $requestIds = $singleId === false ? [] : [(int) $singleId];
        }

        if ($requestIds === []) {
            $actionError = 'Select at least one pending print request.';
        } else {
            $newStatus = str_contains($postAction, 'printed') ? 'printed' : 'cancelled';
            foreach ($requestIds as $requestId) {
                $request = get_print_request($requestId);
                if ($request !== null && ($request['status'] ?? '') === 'pending') {
                    update_print_request_status($requestId, $newStatus, (string) $staffIdentifier);
                }
            }

            $returnStatus = $_GET['status'] ?? 'pending';
            if (!in_array($returnStatus, ['pending', 'printed', 'cancelled', 'all'], true)) {
                $returnStatus = 'pending';
            }
            header('Location: https://lawlibrary.maxxlms.com/staff.php?status=' . urlencode($returnStatus));
            exit;
        }
    }
}

// ---------------------------------------------------------------------------
// Queue data
// ---------------------------------------------------------------------------

$requestedStatus = $_GET['status'] ?? 'pending';
$statusFilter = in_array($requestedStatus, ['pending', 'printed', 'cancelled', 'all'], true)
    ? (string) $requestedStatus
    : 'pending';

$printRequests = [];
$printDoc = null;
$printRequestRow = null;
$printError = null;
$batchPrintRows = [];
$isBatchPrint = $batchPrintIds !== [];

if (!$accessDenied) {
    if ($isBatchPrint) {
        if (!file_exists(VENDOR_AUTOLOAD)) {
            $printError = 'The search backend is not configured on this server.';
        } else {
            require_once VENDOR_AUTOLOAD;
            try {
                $client = new \Meilisearch\Client(
                    MEILI_HOST,
                    MEILI_API_KEY !== '' ? MEILI_API_KEY : null
                );
                $index = $client->index(MEILI_INDEX);
                foreach ($batchPrintIds as $requestId) {
                    $request = get_print_request($requestId);
                    if ($request === null || ($request['status'] ?? '') !== 'pending') {
                        continue;
                    }
                    try {
                        $document = $index->getDocument($request['opinion_id']);
                        $batchPrintRows[] = [
                            'request' => $request,
                            'document' => $document,
                        ];
                    } catch (\Throwable $exception) {
                        error_log('[staff.php] batch getDocument error: ' . $exception->getMessage());
                    }
                }
                if ($batchPrintRows === []) {
                    $printError = 'None of the selected opinions could be loaded for printing.';
                }
            } catch (\Throwable $exception) {
                error_log('[staff.php] batch Meilisearch error: ' . $exception->getMessage());
                $printError = 'Could not load the selected opinions right now.';
            }
        }
    } else {
        $printId = filter_var($_GET['print'] ?? null, FILTER_VALIDATE_INT);
        if ($printId !== false) {
            $printRequestRow = get_print_request((int) $printId);
            if ($printRequestRow === null) {
                $printError = 'That print request could not be found.';
            } elseif (!file_exists(VENDOR_AUTOLOAD)) {
                $printError = 'The search backend is not configured on this server.';
            } else {
                require_once VENDOR_AUTOLOAD;
                try {
                    $client = new \Meilisearch\Client(
                        MEILI_HOST,
                        MEILI_API_KEY !== '' ? MEILI_API_KEY : null
                    );
                    $printDoc = $client->index(MEILI_INDEX)->getDocument($printRequestRow['opinion_id']);
                } catch (\Throwable $exception) {
                    error_log('[staff.php] getDocument error: ' . $exception->getMessage());
                    $printError = 'Could not load the full opinion text right now.';
                }
            }
        } else {
            $printRequests = list_print_requests($statusFilter);
        }
    }
}

$pendingRequestCount = 0;
foreach ($printRequests as $request) {
    if (($request['status'] ?? '') === 'pending') {
        $pendingRequestCount++;
    }
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
<title>Staff Print Queue</title>
<style>
  :root {
    --color-bg: #f7f7f5;
    --color-surface: #ffffff;
    --color-border: #d6d3ce;
    --color-text: #1a1a1a;
    --color-muted: #4b4b4b;
    --color-primary: #1c4e80;
    --color-primary-dark: #123452;
    --color-focus: #ff8c00;
    --color-warn: #b3261e;
    --radius: 6px;
  }
  * { box-sizing: border-box; }
  html, body {
    margin: 0;
    padding: 0;
    background: var(--color-bg);
    color: var(--color-text);
    font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    font-size: 17px;
    line-height: 1.5;
  }
  a { color: var(--color-primary); }
  *:focus-visible { outline: 3px solid var(--color-focus); outline-offset: 2px; }
  header.site-header {
    background: var(--color-primary-dark);
    color: #fff;
    padding: 16px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
  }
  header.site-header h1 { margin: 0; font-size: 1.4rem; }
  .wrap { max-width: 1100px; margin: 24px auto; padding: 0 16px 40px; }
  .notice, .empty-state {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 24px;
    text-align: center;
    color: var(--color-muted);
  }
  .notice.denied { border-color: var(--color-warn); color: var(--color-warn); }
  .error-text { color: var(--color-warn); font-weight: 600; }
  .tabs { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
  .tabs a {
    padding: 8px 14px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    text-decoration: none;
    background: var(--color-surface);
  }
  .tabs a.active {
    background: var(--color-primary);
    color: #fff;
    border-color: var(--color-primary);
  }
  table.queue { width: 100%; border-collapse: collapse; background: var(--color-surface); }
  table.queue th, table.queue td {
    text-align: left;
    padding: 10px 12px;
    border-bottom: 1px solid var(--color-border);
    vertical-align: top;
  }
  table.queue th { background: #eef1f4; }
  .select-column { width: 48px; text-align: center !important; }
  .select-column input { width: 22px; height: 22px; cursor: pointer; }
  .status-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 700;
  }
  .status-pending { background: #fff1a8; color: #6b5900; }
  .status-printed { background: #d4edda; color: #1e6b3c; }
  .status-cancelled { background: #f1f1f1; color: #666; }
  .row-actions, .print-toolbar, .bulk-toolbar {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: center;
  }
  .row-actions form { margin: 0; }
  .bulk-toolbar {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 12px;
    margin-bottom: 12px;
  }
  .selection-count { color: var(--color-muted); margin-left: auto; }
  .btn {
    padding: 8px 12px;
    border-radius: var(--radius);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    cursor: pointer;
    font-size: 0.9rem;
    text-decoration: none;
    color: var(--color-text);
    min-height: 44px;
  }
  .btn-primary { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
  .btn-danger { background: #fdecea; color: var(--color-warn); border-color: var(--color-warn); }
  .opinion-detail {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 24px;
  }
  .opinion-text { white-space: pre-wrap; line-height: 1.7; margin-top: 16px; }
  .back-link { display: inline-block; margin-bottom: 16px; font-weight: 600; }
  .print-toolbar { margin-bottom: 16px; }
  .print-confirmation {
    background: #fff8d8;
    border: 2px solid #c79b00;
    border-radius: var(--radius);
    padding: 16px;
    margin: 16px 0;
  }
  .print-confirmation p { margin-top: 0; font-weight: 700; }
  .batch-summary { margin: 0 0 16px; color: var(--color-muted); }
  .batch-opinion { margin-bottom: 24px; }
  @media (max-width: 760px) {
    table.queue, table.queue thead, table.queue tbody, table.queue th, table.queue td, table.queue tr {
      display: block;
    }
    table.queue thead { position: absolute; left: -9999px; }
    table.queue tr { border: 1px solid var(--color-border); margin-bottom: 12px; }
    table.queue td { border-bottom: 1px solid var(--color-border); }
  }
  @media print {
    header.site-header, .back-link, .print-toolbar, .print-confirmation, .tabs, .bulk-toolbar { display: none; }
    .wrap { max-width: none; margin: 0; padding: 0; }
    .opinion-detail { border: 0; padding: 0; }
    .batch-opinion { break-after: page; page-break-after: always; }
    .batch-opinion:last-child { break-after: auto; page-break-after: auto; }
  }
</style>
</head>
<body>

<header class="site-header">
  <h1>Staff Print Queue</h1>
  <?php if (!$accessDenied): ?>
    <div>Moodle staff: <strong><?= h($staffIdentifier) ?></strong></div>
  <?php endif; ?>
</header>

<div class="wrap">
<?php if ($accessDenied): ?>

  <div class="notice denied">
    <h2>Access denied</h2>
    <p>Open the hidden Staff Print Queue activity from Moodle.</p>
  </div>

<?php elseif ($isBatchPrint): ?>

  <a class="back-link" href="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">&larr; Back to queue</a>

  <?php if ($printError !== null): ?>
    <div class="empty-state"><p><?= h($printError) ?></p></div>
  <?php else: ?>
    <div class="print-toolbar">
      <button class="btn btn-primary" onclick="printAndConfirm()" type="button">Print <?= count($batchPrintRows) ?> Selected Opinions</button>
    </div>

    <div id="print-confirmation" class="print-confirmation" hidden>
      <p>Did all <?= count($batchPrintRows) ?> selected opinions print successfully?</p>
      <form method="post" action="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">
        <input type="hidden" name="csrf_token" value="<?= h($_SESSION['staff_csrf_token']) ?>">
        <input type="hidden" name="action" value="bulk_mark_printed">
        <?php foreach ($batchPrintRows as $item): ?>
          <input type="hidden" name="request_ids[]" value="<?= (int) $item['request']['id'] ?>">
        <?php endforeach; ?>
        <button class="btn btn-primary" type="submit">Yes — Mark All Printed</button>
        <a class="btn" href="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">No — Keep Pending</a>
      </form>
    </div>

    <p class="batch-summary">
      <?= count($batchPrintRows) ?> opinions are included. Your browser's print window will show the exact total page count.
    </p>

    <?php foreach ($batchPrintRows as $item): ?>
      <?php $request = $item['request']; $document = $item['document']; ?>
      <article class="opinion-detail batch-opinion">
        <h2><?= h($document['case_name'] ?? $request['case_name'] ?? 'Untitled opinion') ?></h2>
        <p>
          <strong>Court:</strong> <?= h($document['court_name'] ?? $request['court_name'] ?? 'Unknown') ?>
          &nbsp;|&nbsp;
          <strong>Date filed:</strong> <?= h($document['date_filed'] ?? $request['date_filed'] ?? 'Unknown') ?>
          &nbsp;|&nbsp;
          <strong>Requested by:</strong> <?= h($request['username']) ?>
        </p>
        <div class="opinion-text"><?= h(strip_external_references($document['text'] ?? $document['html_lawbox'] ?? null) ?? 'Full text is not available for this opinion.') ?></div>
      </article>
    <?php endforeach; ?>
  <?php endif; ?>

<?php elseif ($printRequestRow !== null): ?>

  <a class="back-link" href="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">&larr; Back to queue</a>

  <?php if ($printError !== null): ?>
    <div class="empty-state"><p><?= h($printError) ?></p></div>
  <?php else: ?>
    <div class="print-toolbar">
      <button class="btn btn-primary" onclick="printAndConfirm()" type="button">Print this opinion</button>
    </div>

    <?php if ($printRequestRow['status'] === 'pending'): ?>
      <div id="print-confirmation" class="print-confirmation" hidden>
        <p>Did this opinion print successfully?</p>
        <form method="post" action="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">
          <input type="hidden" name="csrf_token" value="<?= h($_SESSION['staff_csrf_token']) ?>">
          <input type="hidden" name="request_id" value="<?= (int) $printRequestRow['id'] ?>">
          <input type="hidden" name="action" value="mark_printed">
          <button class="btn btn-primary" type="submit">Yes — Mark Printed</button>
          <a class="btn" href="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">No — Keep Pending</a>
        </form>
      </div>
    <?php endif; ?>

    <article class="opinion-detail">
      <h2><?= h($printDoc['case_name'] ?? $printRequestRow['case_name'] ?? 'Untitled opinion') ?></h2>
      <p>
        <strong>Court:</strong> <?= h($printDoc['court_name'] ?? $printRequestRow['court_name'] ?? 'Unknown') ?>
        &nbsp;|&nbsp;
        <strong>Date filed:</strong> <?= h($printDoc['date_filed'] ?? $printRequestRow['date_filed'] ?? 'Unknown') ?>
        &nbsp;|&nbsp;
        <strong>Requested by:</strong> <?= h($printRequestRow['username']) ?>
      </p>
      <div class="opinion-text"><?= h(strip_external_references($printDoc['text'] ?? $printDoc['html_lawbox'] ?? null) ?? 'Full text is not available for this opinion.') ?></div>
    </article>
  <?php endif; ?>

<?php else: ?>

  <?php if ($actionError !== null): ?><p class="error-text"><?= h($actionError) ?></p><?php endif; ?>

  <nav class="tabs" aria-label="Print-request status">
    <a href="https://lawlibrary.maxxlms.com/staff.php?status=pending" class="<?= $statusFilter === 'pending' ? 'active' : '' ?>">Pending</a>
    <a href="https://lawlibrary.maxxlms.com/staff.php?status=printed" class="<?= $statusFilter === 'printed' ? 'active' : '' ?>">Printed</a>
    <a href="https://lawlibrary.maxxlms.com/staff.php?status=cancelled" class="<?= $statusFilter === 'cancelled' ? 'active' : '' ?>">Cancelled</a>
    <a href="https://lawlibrary.maxxlms.com/staff.php?status=all" class="<?= $statusFilter === 'all' ? 'active' : '' ?>">All</a>
  </nav>

  <?php if ($pendingRequestCount > 0): ?>
    <form id="bulk-form" class="bulk-toolbar" method="post" action="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">
      <input type="hidden" name="csrf_token" value="<?= h($_SESSION['staff_csrf_token']) ?>">
      <button class="btn" type="submit" name="action" value="print_selected">Print Selected</button>
      <button class="btn btn-primary" type="submit" name="action" value="bulk_mark_printed">Mark Selected Printed</button>
      <button class="btn btn-danger" type="submit" name="action" value="bulk_mark_cancelled" onclick="return confirm('Cancel the selected print requests?');">Cancel Selected</button>
      <span id="selection-count" class="selection-count" aria-live="polite">0 selected</span>
    </form>
  <?php endif; ?>

  <?php if (empty($printRequests)): ?>
    <div class="empty-state"><p>No <?= $statusFilter === 'all' ? '' : h($statusFilter) . ' ' ?>print requests right now.</p></div>
  <?php else: ?>
    <table class="queue">
      <thead>
        <tr>
          <th class="select-column">
            <?php if ($pendingRequestCount > 0): ?>
              <input id="select-all" type="checkbox" aria-label="Select all pending requests">
            <?php endif; ?>
          </th>
          <th>Learner</th><th>Case</th><th>Court</th><th>Date filed</th><th>Requested</th><th>Status</th><th></th>
        </tr>
      </thead>
      <tbody>
      <?php foreach ($printRequests as $request): ?>
        <tr>
          <td class="select-column">
            <?php if ($request['status'] === 'pending'): ?>
              <input
                class="request-checkbox"
                type="checkbox"
                name="request_ids[]"
                value="<?= (int) $request['id'] ?>"
                form="bulk-form"
                aria-label="Select <?= h($request['case_name'] ?? 'untitled opinion') ?>"
              >
            <?php endif; ?>
          </td>
          <td><?= h($request['username']) ?></td>
          <td><?= h($request['case_name'] ?? 'Untitled opinion') ?></td>
          <td><?= h($request['court_name'] ?? '') ?></td>
          <td><?= h($request['date_filed'] ?? '') ?></td>
          <td><?= h(substr((string) $request['requested_at'], 0, 16)) ?></td>
          <td><span class="status-badge status-<?= h($request['status']) ?>"><?= h($request['status']) ?></span></td>
          <td>
            <div class="row-actions">
              <a class="btn" href="https://lawlibrary.maxxlms.com/staff.php?print=<?= (int) $request['id'] ?>&amp;status=<?= h($statusFilter) ?>">View / Print</a>
              <?php if ($request['status'] === 'pending'): ?>
                <form method="post" action="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">
                  <input type="hidden" name="csrf_token" value="<?= h($_SESSION['staff_csrf_token']) ?>">
                  <input type="hidden" name="request_id" value="<?= (int) $request['id'] ?>">
                  <input type="hidden" name="action" value="mark_printed">
                  <button class="btn btn-primary" type="submit">Mark Printed</button>
                </form>
                <form method="post" action="https://lawlibrary.maxxlms.com/staff.php?status=<?= h($statusFilter) ?>">
                  <input type="hidden" name="csrf_token" value="<?= h($_SESSION['staff_csrf_token']) ?>">
                  <input type="hidden" name="request_id" value="<?= (int) $request['id'] ?>">
                  <input type="hidden" name="action" value="mark_cancelled">
                  <button class="btn btn-danger" type="submit">Cancel</button>
                </form>
              <?php endif; ?>
            </div>
          </td>
        </tr>
      <?php endforeach; ?>
      </tbody>
    </table>
  <?php endif; ?>

<?php endif; ?>
</div>
<script>
  function printAndConfirm() {
    window.print();
    var confirmation = document.getElementById('print-confirmation');
    if (confirmation) {
      confirmation.hidden = false;
      confirmation.setAttribute('tabindex', '-1');
      confirmation.focus();
    }
  }

  (function () {
    var selectAll = document.getElementById('select-all');
    var checkboxes = document.querySelectorAll('.request-checkbox');
    var countLabel = document.getElementById('selection-count');

    if (!checkboxes.length || !countLabel) {
      return;
    }

    function updateSelection() {
      var selected = 0;
      for (var i = 0; i < checkboxes.length; i++) {
        if (checkboxes[i].checked) {
          selected++;
        }
      }
      countLabel.textContent = selected + ' selected';
      if (selectAll) {
        selectAll.checked = selected === checkboxes.length;
        selectAll.indeterminate = selected > 0 && selected < checkboxes.length;
      }
    }

    if (selectAll) {
      selectAll.addEventListener('change', function () {
        for (var i = 0; i < checkboxes.length; i++) {
          checkboxes[i].checked = selectAll.checked;
        }
        updateSelection();
      });
    }

    for (var i = 0; i < checkboxes.length; i++) {
      checkboxes[i].addEventListener('change', updateSelection);
    }
  })();
</script>
</body>
</html>
