"use strict";
(() => {
  // src/ide/web/worksheet-model.ts
  function getNow() {
    const dt = /* @__PURE__ */ new Date();
    const sp = document.createElement("span");
    sp.classList.add("timestamp");
    return `${dt.toLocaleTimeString()} ${dt.toLocaleDateString()}`;
  }
  var QuestionModel = class {
    constructor(id) {
      this.id = id;
    }
    value = "";
    setValue(v) {
      this.value = v;
    }
    isAnswered() {
      return !!this.value;
    }
    setAnswers(answers) {
      this.value = answers.value;
    }
  };
  var StepModel = class {
    constructor(id, notes2, questions2, hints2) {
      this.id = id;
      this.notes = notes2;
      this.questions = questions2;
      this.hints = hints2;
    }
    done = false;
    timeDone = "";
    diff = [];
    conditionalSetDone() {
      if (this.questions.every((q) => q.isAnswered())) {
        this.done = true;
        this.timeDone = getNow();
      }
    }
    setDiff(diff) {
      this.diff = diff;
    }
    getQuestionById(id) {
      return this.questions.find((q) => q.id === id);
    }
    getHintById(id) {
      return this.hints.find((h) => h.id === id);
    }
    setAnswers(answers) {
      this.done = answers.done;
      this.timeDone = answers.timeDone;
      this.diff = answers.diff;
      this.notes.setAnswers(answers.notes);
      for (const a of answers.questions) {
        this.getQuestionById(a.id)?.setAnswers(a);
      }
      for (const a of answers.hints) {
        this.getHintById(a.id)?.setAnswers(a);
      }
    }
    getTakenHintsTotal() {
      return this.hints.filter((h) => h.taken).length;
    }
  };
  var HintModel = class {
    constructor(id) {
      this.id = id;
    }
    diff = [];
    taken = false;
    timeTaken = "";
    stepComplete = false;
    setDiff(diff) {
      this.diff = diff;
    }
    setTaken() {
      this.taken = true;
      this.timeTaken = getNow();
    }
    setAnswers(answers) {
      this.diff = answers.diff;
      this.taken = answers.taken;
      this.timeTaken = answers.timeTaken;
      this.stepComplete = answers.stepComplete;
    }
  };
  var WorksheetModel = class {
    constructor(title, version, username, steps) {
      this.title = title;
      this.version = version;
      this.username = username;
      this.steps = steps;
    }
    setAnswers(answers) {
      this.title = answers.title;
      this.version = answers.version;
      this.username.setAnswers(answers.username);
      this.username.setAnswers(answers.username);
      for (const a of answers.steps) {
        this.getStepById(a.id)?.setAnswers(a);
      }
    }
    getQuestionOrNotesById(id) {
      if (id.startsWith("notes")) {
        const stepId = id.replace("notes", "step");
        return this.getStepById(stepId)?.notes;
      }
      for (const step of this.steps) {
        const q = step.getQuestionById(id);
        if (q) {
          return q;
        }
      }
      return void 0;
    }
    getHintById(id) {
      for (const step of this.steps) {
        const h = step.getHintById(id);
        if (h) {
          return h;
        }
      }
      return void 0;
    }
    getStepById(id) {
      return this.steps.find((s) => s.id === id);
    }
    getNextStep() {
      return this.steps.find((s) => !s.done);
    }
    getHintsTotalAndTakenByStep(id) {
      const step = this.getStepById(id);
      const previousSteps = this.steps.slice(0, this.steps.indexOf(step) + 1);
      let total = 0;
      let taken = 0;
      for (const s of previousSteps) {
        total = total + s.hints.length;
        taken = taken + s.getTakenHintsTotal();
      }
      return [total, taken];
    }
  };
  function createQuestion(question) {
    return new QuestionModel(question.id);
  }
  function createStep(step) {
    return new StepModel(
      step.id,
      createQuestion(step.querySelector("textarea.notes")),
      Array.from(step.querySelectorAll("input.question, textarea.question, select.question")).map(
        (q) => createQuestion(q)
      ),
      Array.from(step.querySelectorAll("div.hint")).map((h) => createHint(h))
    );
  }
  function createHint(hint) {
    return new HintModel(hint.id);
  }
  function createModelFromDocument(document2) {
    return new WorksheetModel(
      document2.querySelector("div.docTitle").textContent,
      document2.querySelector("div.version").textContent,
      createQuestion(document2.querySelector("#username")),
      Array.from(document2.querySelectorAll("div.step")).map((s) => createStep(s))
    );
  }

  // src/ide/web/worksheet-model-scripts.ts
  var questionsSelector = "input.question, textarea.question, select.question";
  var questions = document.querySelectorAll(questionsSelector);
  var notes = document.querySelectorAll("textarea.notes");
  var hints = document.querySelectorAll("div.hint");
  var doneCheckboxes = document.querySelectorAll("div.step > input.step-complete");
  var snapshots = document.querySelectorAll("div.snapshot");
  var autoSaveButton = document.getElementById("auto-save");
  var loadAnswersButton = document.getElementById("load-answers");
  var helps = document.querySelectorAll("a.help");
  var loads = document.querySelectorAll("button.load");
  var userName = document.getElementById("username");
  var postSaveUserName = document.getElementById("postsave-username");
  var autosave = document.getElementById("auto-save");
  var fh;
  var wsModel = createModelFromDocument(document);
  async function write(jsonModel, fh2) {
    try {
      const writeable = await fh2.createWritable();
      await writeable.write(jsonModel);
      await writeable.close();
      document.getElementById("worksheet")?.classList.add("saved");
    } catch (_e) {
      document.getElementById("worksheet")?.classList.remove("saved");
      throw _e;
    }
  }
  async function chromeSave(jsonModel, newName) {
    try {
      const fh2 = await showSaveFilePicker({
        suggestedName: newName,
        startIn: "documents",
        types: [{ accept: { "application/json": ".json" } }],
        id: ""
      });
      await write(jsonModel, fh2);
      userName.disabled = true;
      return fh2;
    } catch {
      document.getElementById("worksheet")?.classList.remove("saved");
      return void 0;
    }
  }
  async function chromeRead() {
    try {
      const [fileHandle] = await window.showOpenFilePicker({
        startIn: "documents",
        types: [{ accept: { "application/json": ".json" } }],
        id: ""
      });
      const codeFile = await fileHandle.getFile();
      fh = fileHandle;
      return await codeFile.text();
    } catch (_e) {
      return;
    }
  }
  function scrollToActiveElement() {
    const activeAndCompleteSteps = document.querySelectorAll("div.complete, div.active");
    if (activeAndCompleteSteps.length === 0) {
      const firstStep = document.querySelector("div.step");
      firstStep?.classList.add("active");
      firstStep?.scrollIntoView(false);
    } else {
      const arr = Array.from(activeAndCompleteSteps);
      const lastElement = arr[arr.length - 1];
      lastElement.scrollIntoView(false);
    }
  }
  autoSaveButton.addEventListener("click", async () => {
    const code = JSON.stringify(wsModel);
    const wsName = document.getElementsByClassName("docTitle")[0].innerHTML;
    const suggestedName = `${wsModel.username.value} - ${wsName} - answers`;
    fh = await chromeSave(code, suggestedName);
    scrollToActiveElement();
  });
  loadAnswersButton.addEventListener("click", async () => {
    const txt = await chromeRead();
    if (txt) {
      let answers;
      try {
        answers = JSON.parse(txt);
      } catch {
        fh = void 0;
        alert("Attempting to load an invalid JSON file");
        return;
      }
      const title = document.querySelector("div.docTitle")?.textContent;
      const wsTitle = answers.title;
      if (title !== wsTitle) {
        fh = void 0;
        alert(
          `Attempting to load answers file for a different worksheet Expected: ${title} Actual: ${wsTitle}`
        );
        return;
      }
      const version = document.querySelector("div.version")?.textContent ?? "";
      const wsVersion = answers.version ?? "";
      if (version !== wsVersion) {
        fh = void 0;
        alert(
          `Attempting to load answers file for a different version of the worksheet Expected: ${version} Actual: ${wsVersion}`
        );
        return;
      }
      document.getElementById("worksheet")?.classList.add("saved");
      wsModel.setAnswers(answers);
      resetHtml();
      userName.disabled = true;
      userName.value = wsModel.username.value;
      postSaveUserName.value = wsModel.username.value;
      for (const step of wsModel.steps) {
        const st = document.getElementById(step.id);
        const notes2 = document.getElementById(step.notes.id);
        notes2.value = step.notes.value;
        if (step.done) {
          const doneId = step.id.replace("step", "done");
          const cb = document.getElementById(doneId);
          markStepComplete(cb, st);
          setDiffInHtml(doneId, step.diff);
        }
        for (const hint of step.hints) {
          if (hint.taken) {
            const ht = document.getElementById(hint.id);
            takeHint(ht, hint);
            setDiffInHtml(hint.id, hint.diff);
          }
        }
        for (const question of step.questions) {
          const q = document.getElementById(question.id);
          q.value = question.value;
          setAnswered(q, question);
        }
      }
      await save();
    }
    scrollToActiveElement();
  });
  function clearTempMsgs() {
    const allMsgs = document.querySelectorAll(`.temp-msg`);
    for (const m of allMsgs) {
      m.remove();
    }
  }
  async function save() {
    if (fh) {
      const code = JSON.stringify(wsModel);
      try {
        await write(code, fh);
      } catch (_e) {
        document.getElementById("worksheet")?.classList.remove("saved");
        throw _e;
      }
    }
  }
  for (const e of questions) {
    addEventListenerToInput(e);
  }
  for (const e of notes) {
    addEventListenerToInput(e);
  }
  function updateHintsTaken() {
    for (const step of wsModel.steps) {
      const [hintsSoFar, hintsTaken] = wsModel.getHintsTotalAndTakenByStep(step.id);
      const st = document.getElementById(step.id);
      const taken = st.querySelector("span.hints-taken");
      const total = st.querySelector("span.hints-total");
      taken.innerText = `${hintsTaken}`;
      total.innerText = `${hintsSoFar}`;
    }
  }
  function takeHint(hint, hintModel) {
    const encryptedText = hint.dataset.hint || "";
    if (encryptedText !== "") {
      const content = document.getElementById(`${hint.id}content`);
      if (content) {
        content.innerHTML = atob(encryptedText);
        const hintHelps = content.querySelectorAll("a.help");
        setupHelpLinks(hintHelps);
      }
    }
    hint.classList.add("taken");
    hint.append(getTimestamp(hintModel.timeTaken));
    updateHintsTaken();
  }
  for (const hint of hints) {
    hint.addEventListener("click", async (_e) => {
      const hintModel = wsModel.getHintById(hint.id);
      if (!hintModel.stepComplete && !hintModel.taken) {
        hintModel?.setTaken();
        takeHint(hint, hintModel);
        snapShotCode(hint.id);
      }
    });
  }
  for (const ss of snapshots) {
    ss.classList.add("collapsed");
    ss.addEventListener("click", () => ss.classList.toggle("collapsed"));
  }
  function setAnswered(question, questionModel) {
    if (questionModel.isAnswered()) {
      question.classList.add("answered");
    } else {
      question.classList.remove("answered");
    }
  }
  function addEventListenerToInput(e) {
    e.addEventListener("input", async (e2) => {
      const ie = e2;
      const tgt = ie.target;
      if (tgt instanceof HTMLTextAreaElement) {
        const q = wsModel.getQuestionOrNotesById(tgt.id);
        q.setValue(tgt.value);
        setAnswered(tgt, q);
      }
      clearTempMsgs();
      await save();
    });
  }
  function getTimestamp(time) {
    const sp = document.createElement("span");
    sp.classList.add("timestamp");
    sp.innerText = time;
    return sp;
  }
  function markStepComplete(cb, step) {
    cb.disabled = true;
    cb.setAttribute("checked", "true");
    step.classList.remove("active");
    step.classList.add("complete");
    const stepModel = wsModel.getStepById(step.id);
    for (const q of stepModel.questions) {
      document.getElementById(q.id).disabled = true;
    }
    for (const h of stepModel.hints) {
      h.stepComplete = true;
    }
    const nextId = wsModel.getNextStep()?.id;
    const nextStep = document.getElementById(nextId);
    if (nextStep) {
      nextStep.classList.add("active");
    }
    cb.after(getTimestamp(wsModel.getStepById(step.id).timeDone));
  }
  function addTempMsg(tgt, msg) {
    const div = document.createElement("div");
    div.classList.add("temp-msg");
    div.innerText = msg;
    tgt.after(div);
  }
  for (const cb of doneCheckboxes) {
    cb.addEventListener("click", async (e) => {
      clearTempMsgs();
      const step = cb.parentElement;
      if (step) {
        const stepModel = wsModel.getStepById(step.id);
        stepModel?.conditionalSetDone();
        if (stepModel?.done) {
          markStepComplete(cb, step);
          updateHintsTaken();
          snapShotCode(cb.id);
          await save();
        } else {
          addTempMsg(cb, "All required inputs must be completed to continue");
          e.preventDefault();
        }
      }
    });
  }
  for (const step of document.querySelectorAll("div.step")) {
    const hintsTaken = step.querySelectorAll("span.hints-taken");
    const total = step.querySelectorAll("span.hints-total");
    for (const ht of hintsTaken) {
      ht.innerText = `${0}`;
    }
    for (const ht of total) {
      ht.innerText = `${0}`;
    }
  }
  function transformHeader(s) {
    if (s.startsWith("#")) {
      const tokens = s.split(" ");
      if (tokens.length === 7 && tokens[0] === "#" && tokens[2] === "Elan") {
        return `${tokens[0]} ${tokens[2]} ${tokens[3]}\r
`;
      }
    }
    return s;
  }
  function fixHeader(s) {
    const firstNL = s.indexOf("\n");
    if (firstNL !== -1) {
      let firstLine = s.slice(0, firstNL);
      firstLine = transformHeader(firstLine);
      return `${firstLine}${s.slice(firstNL + 1)}`;
    }
    return s;
  }
  window.addEventListener("message", async (m) => {
    if (m.data === "hasFocus") {
      scrollToActiveElement();
    }
    if (m.data.startsWith("code:")) {
      const idPrefixed = m.data.slice(5);
      const indexOfColon = idPrefixed.indexOf(":");
      const id = idPrefixed.slice(0, indexOfColon);
      const newCode = idPrefixed.slice(indexOfColon + 1);
      const oldCode = localStorage.getItem("code_snapshot") ?? "";
      localStorage.setItem("code_snapshot", newCode);
      if (id.startsWith("done") || id.startsWith("hint")) {
        let diff = Diff.diffLines(fixHeader(oldCode), fixHeader(newCode), {
          newLineIsToken: true
        });
        diff = diff.map((d) => {
          if (d.added || d.removed) {
            return d;
          }
          if (d.count > 2) {
            const all = d.value.split("\n").map((s) => s.trimEnd()).filter((s) => s);
            if (all.length > 2) {
              const result = [all[0], "...", all[all.length - 1]];
              return {
                added: false,
                removed: false,
                value: result.join("\n"),
                count: result.length
              };
            }
          }
          return d;
        });
        if (id.startsWith("hint")) {
          const hintModel = wsModel.getHintById(id);
          hintModel?.setDiff(diff);
        } else {
          const stepModel = wsModel.getStepById(id.replace("done", "step"));
          stepModel?.setDiff(diff);
        }
        setDiffInHtml(id, diff);
      }
      await save();
    }
  });
  function resetHtml() {
    const diffs = document.querySelectorAll("div.snapshot");
    for (const diff of diffs) {
      diff.remove();
    }
    const timestamps = document.querySelectorAll("span.timestamp");
    for (const timestamp of timestamps) {
      timestamp.remove();
    }
    clearTempMsgs();
  }
  function setDiffInHtml(id, diff) {
    const text = Diff.convertChangesToXML(diff);
    const diffDiv = document.createElement("div");
    diffDiv.classList.add("diff");
    diffDiv.innerHTML = text;
    const snapshotDiv = document.createElement("div");
    snapshotDiv.classList.add("snapshot");
    snapshotDiv.classList.add("collapsed");
    snapshotDiv.appendChild(diffDiv);
    document.getElementById(id)?.before(snapshotDiv);
    snapshotDiv.addEventListener("click", () => snapshotDiv.classList.toggle("collapsed"));
  }
  function setupLoadButtons(loadButtons) {
    for (const b of loadButtons) {
      b.addEventListener("click", (_e) => {
        const code = document.getElementById(`code-${b.id}`)?.textContent ?? "";
        window.parent.postMessage(`code:${code}`, "*");
        window.parent.postMessage(`filename:${b.dataset.file}`, "*");
        snapShotCode("reset");
      });
    }
  }
  function setupHelpLinks(helpLinks) {
    for (const b of helpLinks) {
      b.addEventListener("click", (e) => {
        const link = b.href;
        window.parent.postMessage(`help:${link}`, "*");
        e.preventDefault();
        e.stopPropagation();
      });
    }
  }
  setupLoadButtons(loads);
  setupHelpLinks(helps);
  updateHintsTaken();
  var invalidCharacters = ["<", ">", ":", '"', "/", "\\", "|", "?", "*"];
  userName.addEventListener("keyup", (e) => {
    clearTempMsgs();
    const value = e.target.value;
    if (invalidCharacters.some((c) => value.includes(c))) {
      wsModel.username.setValue("");
      addTempMsg(userName, `Username may not contain any of ${invalidCharacters.join()}`);
    } else {
      wsModel.username.setValue(e.target.value);
    }
    autosave.disabled = !wsModel.username.isAnswered();
    postSaveUserName.value = wsModel.username.value;
  });
  function snapShotCode(id) {
    window.parent.postMessage(`snapshot:${id}`, "*");
  }
  snapShotCode("initial");
})();
