var prevTag;
function removeOverlay() {
  $("#loading_overlay").removeClass("overlay");
}
function reload() {
  location.reload();
}
function storageComp() {
  if (typeof (Storage) !== "undefined")
    return true;
  return false;
}
function getStorage(item) {
  if (storageComp()) {
    return localStorage.getItem(item);
  }
  return null;
}
function setStorage(item, value) {
  if (storageComp()) {
    localStorage.setItem(item, value);
  }
}
function removeStorage(item) {
  if (storageComp()) {
    localStorage.removeItem(item);
  }
}
function debugMessage(msg) {
  if (window.debugMessagesActive) {
    console.log(msg);
  }
}
function validateDuration(d) {
  if (typeof d === "undefined" || d < 0)
    return ENDLESS;
  else
    return d *= 1000;
}
function getHashtag() {
  if (getStorage('lasthashtag') != null)
    return getStorage('lasthashtag');
  else {
    var tag = document.URL;
    tag = tag.substr(tag.indexOf("#") + 1);
    if (tag == "" || typeof tag === "undefined" || tag.startsWith("http"))
      tag = "dashboard"
    return tag;
  }
}
function loadContent(event, forceRefresh) {
  var tag;
  var lastSelectedInstance = getStorage('lastSelectedInstance');
  if (lastSelectedInstance && (lastSelectedInstance != window.currentHyperionInstance)) {
    if (window.serverInfo.instance[lastSelectedInstance] && window.serverInfo.instance[lastSelectedInstance].running) {
      instanceSwitch(lastSelectedInstance);
    } else {
      removeStorage('lastSelectedInstance');
    }
  }
  if (typeof event != "undefined") {
    tag = event.currentTarget.hash;
    tag = tag.substr(tag.indexOf("#") + 1);
    setStorage('lasthashtag', tag);
  }
  else
    tag = getHashtag();
  if (forceRefresh || prevTag != tag) {
    prevTag = tag;
    $("#page-content").off();
    $("#page-content").load("/content/" + tag + ".html", function (response, status, xhr) {
      if (status == "error") {
        tag = 'dashboard';
        console.log("Could not find page:", prevTag, ", Redirecting to:", tag);
        setStorage('lasthashtag', tag);
        $("#page-content").load("/content/" + tag + ".html", function (response, status, xhr) {
          if (status == "error") {
            $("#page-content").html('
' + encode_utf8(tag) + ' ');
            removeOverlay();
          }
        });
      }
      updateUiOnInstance(window.currentHyperionInstance);
    });
  }
}
function getInstanceNameByIndex(index) {
  var instData = window.serverInfo.instance
  for (var key in instData) {
    if (instData[key].instance == index)
      return instData[key].friendly_name;
  }
  return "unknown"
}
function updateHyperionInstanceListing() {
  if (window.serverInfo.instance) {
    var data = window.serverInfo.instance.filter(entry => entry.running);
    $('#hyp_inst_listing').html("");
    for (var key in data) {
      var currInstMarker = (data[key].instance == window.currentHyperionInstance) ? "component-on" : "";
      var html = ' \
        \
          \
          '+ data[key].friendly_name + '  \
        
 \
        \
      '
      if (data.length - 1 > key)
        html += '' + availLangText[i] + ' ');
  }
  var langLocale = storedLang;
  //Test, if language is supported by hyperion
  var langIdx = availLang.indexOf(langLocale);
  if (langIdx > -1) {
    langText = availLangText[langIdx];
  } else {
    // If language is not supported by hyperion, try fallback language
    langLocale = $.i18n().options.fallbackLocale.substring(0, 2);
    langIdx = availLang.indexOf(langLocale);
    if (langIdx > -1) {
      langText = availLangText[langIdx];
    } else {
      langLocale = 'en';
      langIdx = availLang.indexOf(langLocale);
      if (langIdx > -1) {
        langText = availLangText[langIdx];
      }
    }
  }
  $('#language-select').prop('title', langText);
  $("#language-select").val(langIdx);
  $("#language-select").selectpicker("refresh");
}
function updateUiOnInstance(inst) {
  window.currentHyperionInstance = inst;
  window.currentHyperionInstanceName = getInstanceNameByIndex(inst);
  $("#active_instance_friendly_name").text(getInstanceNameByIndex(inst));
  if (window.serverInfo.instance.filter(entry => entry.running).length > 1) {
    $('#btn_hypinstanceswitch').toggle(true);
    $('#active_instance_dropdown').prop('disabled', false);
    $('#active_instance_dropdown').css('cursor', 'pointer');
    $("#active_instance_dropdown").css("pointer-events", "auto");
  } else {
    $('#btn_hypinstanceswitch').toggle(false);
    $('#active_instance_dropdown').prop('disabled', true);
    $("#active_instance_dropdown").css('cursor', 'default');
    $("#active_instance_dropdown").css("pointer-events", "none");
  }
}
function instanceSwitch(inst) {
  requestInstanceSwitch(inst)
  window.currentHyperionInstance = inst;
  window.currentHyperionInstanceName = getInstanceNameByIndex(inst);
  setStorage('lastSelectedInstance', inst)
}
function loadContentTo(containerId, fileName) {
  $(containerId).load("/content/" + fileName + ".html");
}
function toggleClass(obj, class1, class2) {
  if ($(obj).hasClass(class1)) {
    $(obj).removeClass(class1);
    $(obj).addClass(class2);
  }
  else {
    $(obj).removeClass(class2);
    $(obj).addClass(class1);
  }
}
function setClassByBool(obj, enable, class1, class2) {
  if (enable) {
    $(obj).removeClass(class1);
    $(obj).addClass(class2);
  }
  else {
    $(obj).removeClass(class2);
    $(obj).addClass(class1);
  }
}
function showInfoDialog(type, header, message) {
  if (type == "success") {
    $('#id_body').html('');
    if (header == "")
      $('#id_body').append('' + $.i18n('infoDialog_general_success_title') + ' ');
    $('#id_footer').html('' + $.i18n('general_btn_ok') + ' ');
  }
  else if (type == "warning") {
    $('#id_body').html('');
    if (header == "")
      $('#id_body').append('' + $.i18n('infoDialog_general_warning_title') + ' ');
    $('#id_footer').html('' + $.i18n('general_btn_ok') + ' ');
  }
  else if (type == "error") {
    $('#id_body').html('');
    if (header == "")
      $('#id_body').append('' + $.i18n('infoDialog_general_error_title') + ' ');
    $('#id_footer').html('' + $.i18n('general_btn_ok') + ' ');
  }
  else if (type == "select") {
    $('#id_body').html('' + $.i18n('InfoDialog_nowrite_foottext') + ' ');
  }
  else if (type == "import") {
    $('#id_body').html('');
    $('#id_footer').html('');
    $('#id_footer').html('' + header + ' ');
    $('#id_body_rename').append('' + header + '      ' + $.i18n('infoDialog_password_minimum_length') + ' 
');
    $('#id_footer_rename').html('' + $.i18n('infoDialog_checklist_title') + ' ');
    $('#id_body').append(header);
    $('#id_footer').html('' + $.i18n('general_btn_ok') + ' ');
  }
  else if (type == "newToken") {
    $('#id_body').html('' + $.i18n('general_btn_ok') + ' ');
  }
  else if (type == "grantToken") {
    $('#id_body').html('' + $.i18n('general_btn_grantAccess') + ' ');
    $('#id_footer').append('' + $.i18n('general_btn_denyAccess') + ' ');
  }
  if (type != "renInst") {
    $('#id_body').append('' + header + ' ');
    $('#id_body').append(message);
  }
  if (type == "select" || type == "iswitch")
    $('#id_body').append('
' + text + ' 
Information
';
    tclass = "info-hint";
  }
  else if (type == "wizard") {
    fe = '
Information
';
    tclass = "wizard-hint";
  }
  else if (type == "warning") {
    fe = '
Information
';
    tclass = "warning-hint";
  }
  if (buttonid)
    buttonid = '' + text + ' 
';
  else
    buttonid = "";
  if (type == "intro")
    $('#' + container).prepend('
' + $.i18n("conf_helptable_expl") + ' ' + text + '');
  else if (type == "wizard")
    $('#' + container).prepend('
' + $.i18n("wiz_wizavail") + ' ' + $.i18n('wiz_guideyou', text) + buttonid + '');
  else {
    createTable('', 'htb', container, true, tclass);
    $('#' + container + ' .htb').append(createTableRow([fe, text], false, true));
  }
}
function createEffHint(title, text) {
  return '
' + title + ' ' + text + '';
}
function valValue(id, value, min, max) {
  if (typeof max === 'undefined' || max == "")
    max = 999999;
  if (Number(value) > Number(max)) {
    $('#' + id).val(max);
    showInfoDialog("warning", "", $.i18n('edt_msg_error_maximum_incl', max));
    return max;
  }
  else if (Number(value) < Number(min)) {
    $('#' + id).val(min);
    showInfoDialog("warning", "", $.i18n('edt_msg_error_minimum_incl', min));
    return min;
  }
  return value;
}
function readImg(input, cb) {
  if (input.files && input.files[0]) {
    var reader = new FileReader();
    // inject fileName property
    reader.fileName = input.files[0].name
    reader.onload = function (e) {
      cb(e.target.result, e.target.fileName);
    }
    reader.readAsDataURL(input.files[0]);
  }
}
function isJsonString(str) {
  try {
    JSON.parse(str);
  }
  catch (e) {
    return e;
  }
  return "";
}
const getObjectProperty = (obj, path) => path.split(".").reduce((o, key) => o && typeof o[key] !== 'undefined' ? o[key] : undefined, obj);
const setObjectProperty = (object, path, value) => {
  const parts = path.split('.');
  const limit = parts.length - 1;
  for (let i = 0; i < limit; ++i) {
    const key = parts[i];
    if (key === "__proto__" || key === "constructor") continue;
    object = object[key] ?? (object[key] = {});
  }
  const key = parts[limit];
  object[key] = value;
};
function getLongPropertiesPath(path) {
  if (path) {
    var path = path.replace('root.', '');
    const parts = path.split('.');
    parts.forEach(function (part, index) {
      this[index] += ".properties";
    }, parts);
    path = parts.join('.') + '.';
  }
  return path;
}
function createJsonEditor(container, schema, setconfig, usePanel, arrayre) {
  $('#' + container).off();
  $('#' + container).html("");
  if (typeof arrayre === 'undefined')
    arrayre = true;
  var editor = new JSONEditor(document.getElementById(container),
    {
      theme: 'bootstrap3',
      iconlib: "fontawesome4",
      disable_collapse: 'true',
      form_name_root: 'sa',
      disable_edit_json: true,
      disable_properties: true,
      disable_array_reorder: arrayre,
      no_additional_properties: true,
      disable_array_delete_all_rows: true,
      disable_array_delete_last_row: true,
      access: storedAccess,
      schema: {
        title: '',
        properties: schema
      }
    });
  if (usePanel) {
    $('#' + container + ' .well').first().removeClass('well well-sm');
    $('#' + container + ' h4').first().remove();
    $('#' + container + ' .well').first().removeClass('well well-sm');
  }
  if (setconfig) {
    for (var key in editor.root.editors) {
      editor.getEditor("root." + key).setValue(Object.assign({}, editor.getEditor("root." + key).value, window.serverConfig[key]));
    }
  }
  return editor;
}
function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVals, newTitelVals, newDefaultVal, addSelect, addCustom, addCustomAsFirst, customText) {
  var editor = rootEditor.getEditor(path);
  var orginalProperties = editor.schema.properties[key];
  var orginalWatchFunctions = rootEditor.watchlist[path + "." + key];
  rootEditor.unwatch(path + "." + key);
  var newSchema = [];
  newSchema[key] =
  {
    "type": "string",
    "enum": [],
    "required": true,
    "options": { "enum_titles": [], "infoText": "" },
    "propertyOrder": 1
  };
  //Add additional elements to overwrite defaults
  for (var item in addElements) {
    newSchema[key][item] = addElements[item];
  }
  if (orginalProperties) {
    if (orginalProperties["title"]) {
      newSchema[key]["title"] = orginalProperties["title"];
    }
    if (orginalProperties["options"] && orginalProperties["options"]["infoText"]) {
      newSchema[key]["options"]["infoText"] = orginalProperties["options"]["infoText"];
    }
    if (orginalProperties["propertyOrder"]) {
      newSchema[key]["propertyOrder"] = orginalProperties["propertyOrder"];
    }
  }
  if (addCustom) {
    if (newTitelVals.length === 0) {
      newTitelVals = [...newEnumVals];
    }
    if (!!!customText) {
      customText = "edt_conf_enum_custom";
    }
    if (addCustomAsFirst) {
      newEnumVals.unshift("CUSTOM");
      newTitelVals.unshift(customText);
    } else {
      newEnumVals.push("CUSTOM");
      newTitelVals.push(customText);
    }
    if (newSchema[key].options.infoText) {
      var customInfoText = newSchema[key].options.infoText + "_custom";
      newSchema[key].options.infoText = customInfoText;
    }
  }
  if (addSelect) {
    newEnumVals.unshift("SELECT");
    newTitelVals.unshift("edt_conf_enum_please_select");
    newDefaultVal = "SELECT";
  }
  if (newEnumVals) {
    newSchema[key]["enum"] = newEnumVals;
  }
  if (newTitelVals) {
    newSchema[key]["options"]["enum_titles"] = newTitelVals;
  }
  if (newDefaultVal) {
    newSchema[key]["default"] = newDefaultVal;
  }
  editor.original_schema.properties[key] = orginalProperties;
  editor.schema.properties[key] = newSchema[key];
  //Update schema properties for validator
  setObjectProperty(rootEditor.validator.schema.properties, getLongPropertiesPath(path) + key, newSchema[key]);
  editor.removeObjectProperty(key);
  delete editor.cached_editors[key];
  editor.addObjectProperty(key);
  if (orginalWatchFunctions) {
    for (var i = 0; i < orginalWatchFunctions.length; i++) {
      rootEditor.watch(path + "." + key, orginalWatchFunctions[i]);
    }
  }
  rootEditor.notifyWatchers(path + "." + key);
}
function updateJsonEditorMultiSelection(rootEditor, path, key, addElements, newEnumVals, newTitelVals, newDefaultVal) {
  var editor = rootEditor.getEditor(path);
  var orginalProperties = editor.schema.properties[key];
  var orginalWatchFunctions = rootEditor.watchlist[path + "." + key];
  rootEditor.unwatch(path + "." + key);
  var newSchema = [];
  newSchema[key] =
  {
    "type": "array",
    "format": "select",
    "items": {
      "type": "string",
      "enum": [],
      "options": { "enum_titles": [] },
    },
    "options": { "infoText": "" },
    "default": [],
    "propertyOrder": 1
  };
  //Add additional elements to overwrite defaults
  for (var item in addElements) {
    newSchema[key][item] = addElements[item];
  }
  if (orginalProperties) {
    if (orginalProperties["title"]) {
      newSchema[key]["title"] = orginalProperties["title"];
    }
    if (orginalProperties["options"] && orginalProperties["options"]["infoText"]) {
      newSchema[key]["options"]["infoText"] = orginalProperties["options"]["infoText"];
    }
    if (orginalProperties["propertyOrder"]) {
      newSchema[key]["propertyOrder"] = orginalProperties["propertyOrder"];
    }
  }
  if (newEnumVals) {
    newSchema[key]["items"]["enum"] = newEnumVals;
  }
  if (newTitelVals) {
    newSchema[key]["items"]["options"]["enum_titles"] = newTitelVals;
  }
  if (newDefaultVal) {
    newSchema[key]["default"] = newDefaultVal;
  }
  editor.original_schema.properties[key] = orginalProperties;
  editor.schema.properties[key] = newSchema[key];
  //Update schema properties for validator
  setObjectProperty(rootEditor.validator.schema.properties, getLongPropertiesPath(path) + key, newSchema[key]);
  editor.removeObjectProperty(key);
  delete editor.cached_editors[key];
  editor.addObjectProperty(key);
  if (orginalWatchFunctions) {
    for (var i = 0; i < orginalWatchFunctions.length; i++) {
      rootEditor.watch(path + "." + key, orginalWatchFunctions[i]);
    }
  }
  rootEditor.notifyWatchers(path + "." + key);
}
function updateJsonEditorRange(rootEditor, path, key, minimum, maximum, defaultValue, step, clear) {
  var editor = rootEditor.getEditor(path);
  //Preserve current value when updating range
  var currentValue = rootEditor.getEditor(path + "." + key).getValue();
  var orginalProperties = editor.schema.properties[key];
  var newSchema = [];
  newSchema[key] = orginalProperties;
  if (clear) {
    delete newSchema[key]["minimum"];
    delete newSchema[key]["maximum"];
    delete newSchema[key]["default"];
    delete newSchema[key]["step"];
  }
  if (typeof minimum !== "undefined") {
    newSchema[key]["minimum"] = minimum;
  }
  if (typeof maximum !== "undefined") {
    newSchema[key]["maximum"] = maximum;
  }
  if (typeof defaultValue !== "undefined") {
    newSchema[key]["default"] = defaultValue;
    currentValue = defaultValue;
  }
  if (typeof step !== "undefined") {
    newSchema[key]["step"] = step;
  }
  editor.original_schema.properties[key] = orginalProperties;
  editor.schema.properties[key] = newSchema[key];
  //Update schema properties for validator
  setObjectProperty(rootEditor.validator.schema.properties, getLongPropertiesPath(path) + key, newSchema[key]);
  editor.removeObjectProperty(key);
  delete editor.cached_editors[key];
  editor.addObjectProperty(key);
  // Restore current (new default) value for new range
  rootEditor.getEditor(path + "." + key).setValue(currentValue);
}
function addJsonEditorHostValidation() {
  JSONEditor.defaults.custom_validators.push(function (schema, value, path) {
    var errors = [];
    if (!jQuery.isEmptyObject(value)) {
      switch (schema.format) {
        case "hostname_or_ip":
          if (!isValidHostnameOrIP(value)) {
            errors.push({
              path: path,
              property: 'format',
              message: $.i18n('edt_msgcust_error_hostname_ip')
            });
          }
          break;
        case "hostname_or_ip4":
          if (!isValidHostnameOrIP4(value)) {
            errors.push({
              path: path,
              property: 'format',
              message: $.i18n('edt_msgcust_error_hostname_ip4')
            });
          }
          break;
        //Remove, when new json-editor 2.x is used
        case "ipv4":
          if (!isValidIPv4(value)) {
            errors.push({
              path: path,
              property: 'format',
              message: $.i18n('edt_msg_error_ipv4')
            });
          }
          break;
        case "ipv6":
          if (!isValidIPv6(value)) {
            errors.push({
              path: path,
              property: 'format',
              message: $.i18n('edt_msg_error_ipv6')
            });
          }
          break;
        case "hostname":
          if (!isValidHostname(value)) {
            errors.push({
              path: path,
              property: 'format',
              message: $.i18n('edt_msg_error_hostname')
            });
          }
          break;
        default:
      }
    }
    return errors;
  });
}
function buildWL(link, linkt, cl) {
  var baseLink = "https://docs.hyperion-project.org/";
  var lang;
  if (typeof linkt == "undefined")
    linkt = "Placeholder";
  if (storedLang == "de" || navigator.locale == "de")
    lang = "de";
  else
    lang = "en";
  if (cl === true) {
    linkt = $.i18n(linkt);
    return '' + linkt + ' ' + $.i18n('general_wiki_moreto', linkt) + ': 
' + linkt + ' ' + linkt + ' ';
}
function rgbToHex(rgb) {
  if (rgb.length == 3) {
    return "#" +
      ("0" + parseInt(rgb[0], 10).toString(16)).slice(-2) +
      ("0" + parseInt(rgb[1], 10).toString(16)).slice(-2) +
      ("0" + parseInt(rgb[2], 10).toString(16)).slice(-2);
  }
  else
    debugMessage('rgbToHex: Given rgb is no array or has wrong length');
}
function hexToRgb(hex) {
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16)
  } : {
    r: 0,
    g: 0,
    b: 0
  };
}
/*
  Show a notification
  @param type     Valid types are "info","success","warning","danger"
  @param message  The message to show
  @param title     A title (optional)
  @param addhtml   Add custom html to the notification end
 */
function showNotification(type, message, title = "", addhtml = "") {
  if (title == "") {
    switch (type) {
      case "info":
        title = $.i18n('infoDialog_general_info_title');
        break;
      case "success":
        title = $.i18n('infoDialog_general_success_title');
        break;
      case "warning":
        title = $.i18n('infoDialog_general_warning_title');
        break;
      case "danger":
        title = $.i18n('infoDialog_general_error_title');
        break;
    }
  }
  $.notify({
    // options
    title: title,
    message: message
  }, {
    // settings
    type: type,
    animate: {
      enter: 'animate__animated animate__fadeInDown',
      exit: 'animate__animated animate__fadeOutUp'
    },
    placement: {
      align: 'center'
    },
    mouse_over: 'pause',
    template: '' +
      '
× ' +
      '
 ' +
      '
{1}  ' +
      '
{2} ' +
      addhtml +
      '
' +
      '
' +
      '
// @param array list :innerHTML content for / 
// @param bool head  :if null or false it's body
// @param bool align :if null or false no alignment
//
// @return :    with  or   as child(s)
function createTableRow(list, head, align) {
  var row = document.createElement('tr');
  for (var i = 0; i < list.length; i++) {
    if (head === true)
      var el = document.createElement('th');
    else
      var el = document.createElement('td');
    if (align)
      el.style.verticalAlign = "middle";
    var purifyConfig = {
            ADD_TAGS: ['button'],
            ADD_ATTR: ['onclick']
    };
    el.innerHTML = DOMPurify.sanitize(list[i], purifyConfig);
    row.appendChild(el);
  }
  return row;
}
function createRow(id) {
  var el = document.createElement('div');
  el.className = "row";
  el.setAttribute('id', id);
  return el;
}
function createOptPanel(phicon, phead, bodyid, footerid, css, panelId) {
  phead = '