From 4acd83630f04c0982d9b455206b67b4ebeaac2da Mon Sep 17 00:00:00 2001
From: Noah Loomans <noahloomans@gmail.com>
Date: Sun, 15 Apr 2018 16:49:30 +0200
Subject: Add .json endpoint for parsed schedule

---
 src/server/lib/schools/hetmml/parseSchedule.js | 100 +++++++++++++++++++++++++
 1 file changed, 100 insertions(+)
 create mode 100644 src/server/lib/schools/hetmml/parseSchedule.js

(limited to 'src/server/lib/schools/hetmml')

diff --git a/src/server/lib/schools/hetmml/parseSchedule.js b/src/server/lib/schools/hetmml/parseSchedule.js
new file mode 100644
index 0000000..14e861e
--- /dev/null
+++ b/src/server/lib/schools/hetmml/parseSchedule.js
@@ -0,0 +1,100 @@
+const { JSDOM } = require('jsdom');
+
+function fixFirstLargeScheduleItem(trNodeList) {
+  return Array.from(trNodeList).some((trNode, timeOfDay) => {
+    const tdNodeList = trNode.children;
+
+    return Array.from(tdNodeList).some((tdNode, dayOfWeek) => {
+      const height = tdNode.rowSpan / 2;
+      if (height === 1) {
+        return false;
+      }
+
+      tdNode.rowSpan = 2; // eslint-disable-line no-param-reassign
+
+      for (let i = 1; i < height; i += 1) {
+        // Are we at the end of the table?
+        if (dayOfWeek === 4) {
+          // If so, we cannot use insertBefore, because the is no node to insert
+          // it before. Use appendChild instead.
+          trNodeList[timeOfDay + i].appendChild(tdNode.cloneNode(true));
+        } else {
+          trNodeList[timeOfDay + i]
+            .insertBefore(
+              tdNode.cloneNode(true),
+              trNodeList[timeOfDay + i].children[dayOfWeek],
+            );
+        }
+      }
+
+      return true;
+    });
+  });
+}
+
+function parseSchedule(axiosResponse) {
+  const dom = new JSDOM(axiosResponse.data);
+  const { window } = dom;
+  const { document } = window;
+
+  const tableNode = document.querySelector('center > table');
+  const tbodyNode = tableNode.querySelector('tbody');
+  const trNodeList = tbodyNode.children;
+
+  Array.from(trNodeList).forEach((trNode, timeOfDay) => {
+    const tdNodeList = trNode.children;
+
+    if (timeOfDay === 0 || trNode.children.length === 0) {
+      tbodyNode.removeChild(trNode);
+      return;
+    }
+
+    Array.from(tdNodeList).forEach((tdNode, dayOfWeek) => {
+      if (dayOfWeek === 0) {
+        trNode.removeChild(tdNode);
+      }
+    });
+  });
+
+  let shouldContinue = true;
+  while (shouldContinue) {
+    shouldContinue = fixFirstLargeScheduleItem(trNodeList);
+  }
+
+  const scheduleItems = [];
+
+  Array.from(trNodeList).forEach((trNode, timeOfDay) => {
+    const tdNodeList = trNode.children;
+    Array.from(tdNodeList).forEach((tdNode, dayOfWeek) => {
+      if (tdNode.textContent.trim() === '') {
+        return;
+      }
+
+      const childTableNode = tdNode.querySelector('table');
+      const childTrNodeList = childTableNode.querySelectorAll('tr');
+
+      Array.from(childTrNodeList).forEach((childTrNode) => {
+        const subject = childTrNode.children[0].textContent.trim();
+        const attendees = childTrNode.children[1]
+          ? childTrNode.children[1].textContent.trim()
+          : undefined;
+        const location = childTrNode.children[2]
+          ? childTrNode.children[2].textContent.trim()
+          : undefined;
+
+        scheduleItems.push({
+          startTime: timeOfDay,
+          endTime: timeOfDay + 1,
+          dayOfWeek,
+          subject,
+          attendees,
+          location,
+        });
+      });
+    });
+  });
+
+  return scheduleItems;
+}
+
+module.exports = parseSchedule;
-- 
cgit v1.1