{% extends 'pageWrapper.html' %}
{% import "macros.html" as macros %}
{% block head %}
    <title>Multiworld {{ room.id|suuid }}</title>
    {% if should_refresh %}<meta http-equiv="refresh" content="2">{% endif %}
    <meta name="og:site_name" content="Archipelago">
    <meta property="og:title" content="Multiworld {{ room.id|suuid }}">
    <meta property="og:type" content="website" />
    {% if room.seed.slots|length < 2 %}
    <meta property="og:description" content="{{ room.seed.slots|length }} Player World
    {% if room.last_port != -1 %}running on {{ config['HOST_ADDRESS'] }} with port {{ room.last_port }}{% endif %}">
    {% else %}
    <meta property="og:description" content="{{ room.seed.slots|length }} Players Multiworld
    {% if room.last_port != -1 %}running on {{ config['HOST_ADDRESS'] }} with port {{ room.last_port }}{% endif %}">
    {% endif %}
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/hostRoom.css") }}"/>
{% endblock %}

{% block body %}
    {% include 'header/grassHeader.html' %}
    <div id="host-room">
        <span id="host-room-info">
            {% if room.owner == session["_id"] %}
                Room created from <a href="{{ url_for("view_seed", seed=room.seed.id) }}">Seed #{{ room.seed.id|suuid }}</a>
                <br />
            {% endif %}
            {% if room.tracker %}
                This room has a <a href="{{ url_for("get_multiworld_tracker", tracker=room.tracker) }}">Multiworld Tracker</a>
                and a <a href="{{ url_for("get_multiworld_sphere_tracker", tracker=room.tracker) }}">Sphere Tracker</a> enabled.
                <br />
            {% endif %}
            The server for this room will be paused after {{ room.timeout//60//60 }} hours of inactivity.
            Should you wish to continue later,
            anyone can simply refresh this page and the server will resume.<br>
            {% if room.last_port == -1 %}
                There was an error hosting this Room. Another attempt will be made on refreshing this page.
                The most likely failure reason is that the multiworld is too old to be loaded now.
            {% elif room.last_port %}
                You can connect to this room by using <span class="interactive"
                data-tooltip="This means address/ip is {{ config['HOST_ADDRESS'] }} and port is {{ room.last_port }}.">
                '/connect {{ config['HOST_ADDRESS'] }}:{{ room.last_port }}'
                </span>
                in the <a href="{{ url_for("tutorial_landing")}}">client</a>.<br>
            {% endif %}
        </span>
        {{ macros.list_patches_room(room) }}
        {% if room.owner == session["_id"] %}
            <div style="display: flex; align-items: center;">
                <form method="post" id="command-form" style="flex-grow: 1; margin-right: 1em;">
                    <div class="form-group">
                        <label for="cmd"></label>
                        <input class="form-control" type="text" id="cmd" name="cmd"
                               placeholder="Server Command. /help to list them, list gets appended to log.">
                        <span class="loader"></span>
                    </div>
                </form>
                <a href="{{ url_for("display_log", room=room.id) }}">
                    Open Log File...
                </a>
            </div>
        {%  set log, log_len = get_log() -%}
        <div id="logger" style="white-space: pre">{{ log }}</div>
        <script>
          let url = '{{ url_for('display_log', room = room.id) }}';
          let bytesReceived = {{ log_len }};
          let updateLogTimeout;
          let updateLogImmediately = false;
          let awaitingCommandResponse = false;
          let logger = document.getElementById("logger");

          function scrollToBottom(el) {
            let bot = el.scrollHeight - el.clientHeight;
            el.scrollTop += Math.ceil((bot - el.scrollTop)/10);
            if (bot - el.scrollTop >= 1) {
              window.clearTimeout(el.scrollTimer);
              el.scrollTimer = window.setTimeout(() => {
                scrollToBottom(el)
              }, 16);
            }
          }

          async function updateLog() {
            try {
              if (!document.hidden) {
                updateLogImmediately = false;
                let res = await fetch(url, {
                  headers: {
                    'Range': `bytes=${bytesReceived}-`,
                  }
                });
                if (res.ok) {
                  let text = await res.text();
                  if (text.length > 0) {
                    awaitingCommandResponse = false;
                    if (bytesReceived === 0 || res.status !== 206) {
                      logger.innerHTML = '';
                    }
                    if (res.status !== 206) {
                      bytesReceived = 0;
                    } else {
                      bytesReceived += new Blob([text]).size;
                    }
                    if (logger.innerHTML.endsWith('…')) {
                      logger.innerHTML = logger.innerHTML.substring(0, logger.innerHTML.length - 1);
                    }
                    logger.appendChild(document.createTextNode(text));
                    scrollToBottom(logger);
                    let loader = document.getElementById("command-form").getElementsByClassName("loader")[0];
                    loader.classList.remove("loading");
                  }
                }
              } else {
                updateLogImmediately = true;
              }
            }
            finally {
              window.clearTimeout(updateLogTimeout);
              updateLogTimeout = window.setTimeout(updateLog, awaitingCommandResponse ? 500 : 10000);
            }
          }

          async function postForm(ev) {
            /** @type {HTMLInputElement} */
            let cmd = document.getElementById("cmd");
            if (cmd.value === "") {
              ev.preventDefault();
              return;
            }
            /** @type {HTMLFormElement} */
            let form = document.getElementById("command-form");
            let req = fetch(form.action || window.location.href, {
              method: form.method,
              body: new FormData(form),
              redirect: "manual",
            });
            ev.preventDefault(); // has to happen before first await
            form.reset();
            let loader = form.getElementsByClassName("loader")[0];
            loader.classList.add("loading");
            try {
              let res = await req;
              if (res.ok || res.type === 'opaqueredirect') {
                awaitingCommandResponse = true;
                window.clearTimeout(updateLogTimeout);
                updateLogTimeout = window.setTimeout(updateLog, 100);
              } else {
                loader.classList.remove("loading");
                window.alert(res.statusText);
              }
            } catch (e) {
                console.error(e);
                loader.classList.remove("loading");
                window.alert(e.message);
            }
          }

          document.getElementById("command-form").addEventListener("submit", postForm);
          updateLogTimeout = window.setTimeout(updateLog, 1000);
          logger.scrollTop = logger.scrollHeight;
          document.addEventListener("visibilitychange", () => {
            if (!document.hidden && updateLogImmediately) {
              updateLog();
            }
          })
        </script>
        {% endif %}
        <script>
          function updateInfo() {
            let url = new URL(window.location.href);
            url.search = "?update";
            fetch(url)
              .then(res => {
                if (!res.ok) {
                  throw new Error(`HTTP error ${res.status}`);
                }
                return res.text()
              })
              .then(text => new DOMParser().parseFromString(text, 'text/html'))
              .then(newDocument => {
                ["host-room-info", "slots-table"].forEach(function(id) {
                  const newEl = newDocument.getElementById(id);
                  const oldEl = document.getElementById(id);
                  if (oldEl && newEl) {
                    oldEl.innerHTML = newEl.innerHTML;
                  } else if (newEl) {
                    console.warn(`Did not find element to replace for ${id}`)
                  }
                });
            });
          }

          if (document.querySelector("meta[http-equiv='refresh']")) {
            console.log("Refresh!");
            window.addEventListener('load', function () {
              for (let i=0; i<3; i++) {
                window.setTimeout(updateInfo, Math.pow(2, i) * 2000); // 2, 4, 8s
              }
              window.stop(); // cancel meta refresh
            })
          }
        </script>
    </div>
{% endblock %}
