/**
 * @package admin
 * @copyright (c) Kufer Software GmbH, Loisachstrasse 4, D-84453 Mühldorf
 */

function trim(string) {
  return string.replace(/^\s+/, '').replace(/\s+$/, '');
}

if (!jQuery.fn.any) {
  jQuery.fn.any = function (filter) {
    for (var i = 0; i < this.length; i++) {
      if (filter.call(this[i])) return true;
    }
    return false;
  };
}

function toggleSubString(string, subString) {
  if (string == undefined) {
    string = '';
  }
  if (subString == undefined) {
    return string;
  }

  var exp = '\\b' + subString + '\\b';
  var regExp = new RegExp(exp, 'g');

  if (string.match(regExp)) {
    string = trim(string.replace(regExp, ''));
    //Aufbau des Strings: "abc def 123 456"
    //Beim Löschen eines Elements, z. B. 123, im String kann eine Lücke bleiben: "abc def  456"
    //Beim Auslesen macht das Probleme und es kommt zu einem JS-Fehler und die Seite
    //kann nicht mehr weiter benutzt werden, solange das Cookie fupload_opendirs nicht gelöscht wurde oder abgelaufen ist.
    //Deshalb werden hier zwei hintereinander vorkommende Leerzeichen mit einem ersetzt.
    string = string.replace('  ', ' ');
    return string;
  }
  else {
    return trim(string + ' ' + subString);
  }
}
function parseURL(url) {
  if (url == undefined) url = window.location.search;
  if (url == "") return;
  var params = url.slice(1).split("&");
  var param, name, value;
  for (var i = 0; i < params.length; i++) {
    param = params[i].split("=");
    name = decodeURIComponent(param[0]).replace("+", " ").replace("%20", " ");
    value = decodeURIComponent(param[1]).replace("+", " ").replace("%20", " ");
    this[name] = value;
  }
}

/**
 * Speichert das Formular des Inputbuttons per AJAX Request!
 * @param {Event} event
 * @this {HTMLElement}
 */
function ajaxPost(event) {
  event.preventDefault();
  /** @type {HTMLFormElement} */
  const form = this.closest('form');
  const link = form.action;
  const formData = new FormData();
  formData.append('ajax', 'content');

  // Der Hiddenstring wird nur für die Stundenplan Uhrzeit Tabelle in inder der Wochenplangrafik (sicht 312) zu Tool 21
  // (Kursübersicht Firmen) benötigt
  if (typeof KuferTools != 'undefined' && typeof KuferTools.generateHiddenString4Post === 'function')
    KuferTools.generateHiddenString4Post();

  /*
  if (typeof stdPlanZeitContainer.generateHiddenString4Post === 'function')
    generateHiddenString4Post(); */

  /**
   * @param {HTMLInputElement} element
   */
  function setFormDataWithInput(element) {
    formData.append(element.name, element.value);
  }

  // Versteckte Eingabefelder
  Array.from(form.querySelectorAll('input[type=hidden]')).forEach(setFormDataWithInput);
  // Eingabefelder
  Array.from(form.querySelectorAll('input[type=text]')).forEach(setFormDataWithInput);
  // Passwortfelder
  Array.from(form.querySelectorAll('input[type=password]')).forEach(setFormDataWithInput);
  // Absendebutton
  setFormDataWithInput(this);

  // Angewählte Checkboxen
  Array.from(form.querySelectorAll('input[type=radio]'))
    .filter(element => element.checked)
    .forEach(setFormDataWithInput);
  // Angewählte Radio-Groups
  Array.from(form.querySelectorAll('input[type=checkbox]'))
    .filter(element => element.checked)
    .forEach(setFormDataWithInput);

  // Textarea
  Array.from(form.querySelectorAll('textarea'))
    .filter(e => e.value !== "")
    .map(e => {
      e.style.display = 'block';
      return e;
    })
    .forEach(setFormDataWithInput);
  // Select-Box
  Array.from(form.querySelectorAll('select')).forEach(setFormDataWithInput);
  // FileUpload
  Array.from(form.querySelectorAll('input[type=file]')).forEach(setFormDataWithInput);

  const divContent = document.body.querySelector('div#content');
  divContent.classList.add('loading');

  const contentInlay = document.body.querySelector('div#content_inlay');
  fetch(link, {
    method: 'POST',
    headers: new Headers({
      'X-Requested-With': 'XMLHttpRequest'
    }),
    body: formData
  })
    .then(resp => resp.text())
    .then(data => {
      $(contentInlay).html(data);
      preparePage(contentInlay);
    })
    .catch(err => {
      contentInlay.innerHTML = '<div class="status_error">Ein technischer Fehler ist aufgetreten</div>';
      console.error(err);
    })
    .finally(() => {
      divContent.classList.remove('loading');
    });
} //end ajaxPost()

function securityQuestion(element, dialogid) {
  dialogid = (typeof (dialogid) == 'undefined') ? 'securitydialog' : dialogid;
  var confirmed = false;
  jQuery('#' + dialogid).dialog({
    modal: true,
    width: 400,
    buttons: {
      "Ok": function () {
        jQuery(this).dialog("close");
        // Dialog
        if (jQuery(element).is('input')) {
          jQuery(element).parents('form').trigger('submit');
        } else if (jQuery(element).is('a')) {
          loadContent(jQuery(element).prop('href'));
        }
      },
      "Abbrechen": function () {
        jQuery(this).dialog("close");
      }
    }
  });
}

function loadContent(link) {
  const divContent = document.body.querySelector('div#content');
  divContent.classList.add('loading');

  // Beim Laden einer Seite wird globale Variable KuferTools.generateHiddenstring4Post wieder zurückgesetzt, falls sie vorhanden
  // ist. Das verhindert, dass diese Funktion (Anm.: diese Variable beinhaltet eine Funktion) für andere Eingaben als die
  // Stundenplan Table in Tool21 (Sicht 312) ausgeführt wird; TODO: evtl. gibt es auch eine bessere Stelle,
  // um dies einzubauen
  if (typeof KuferTools !== 'undefined')
    KuferTools.generateHiddenString4Post = null;

  const url = new URL(link);
  url.searchParams.append('ajax', 'content');

  const contentInlay = document.body.querySelector('div#content_inlay');
  fetch(url, {
    method: 'GET',
    headers: new Headers({
      'X-Requested-With': 'XMLHttpRequest'
    })
  })
    .then(resp => resp.text())
    .then(data => {
      $(contentInlay).html(data);
      preparePage(contentInlay);
      setHelpTextDialog();
    })
    .catch(err => {
      console.error(err);
      contentInlay.innerHTML = '<div class="status_error">Ein technischer Fehler ist aufgetreten</div>';
    })
    .finally(() => {
      divContent.classList.remove('loading');
    });
}

/*****************************************************************************
 * Prüfen, ob die Session abgelaufen ist und ggf. abmelden
 *****************************************************************************
 */
function checkSession() {
  fetch('index.php?action=checklogin')
    .then(resp => resp.text())
    .then(data => {
      if (data === 'loggedIn:false') {
        location.reload();
      } else {
        // Funktion in 10 Sekunden wieder aufrufen
        // Angepasst, dass location.reload nur einmal ausgeführt wird, da es sonst extrem nervig ist,
        // alle paar Sekunden die Meldung wegzudrücken.
        window.setTimeout(checkSession, 15000);
      }
    });
}
checkSession();


/**
 * @param {Event} event
 * @param {HTMLAnchorElement} linkElement
 */
function linkToSightClicked(event, linkElement) {
  const url = new URL(linkElement.href, location.href);
  /** @type HTMLElement|undefined */
  const navToMark =
    document.body.querySelector('div#nav2 a[href$="' + url.search + '"]') ?? undefined;
  if (!navToMark) {
    return;
  }

  /** @type HTMLElement[] */
  const elements = [
    navToMark.closest('ul.level3') ?? undefined,
    navToMark.closest('ul.level4') ?? undefined,
    navToMark.closest('ul.level5') ?? undefined,
  ].filter(e => e !== undefined);
  for (let e of elements) {
    e.style.display = "block";
    const fold = e.parentElement?.querySelector('div.fold') ?? undefined;
    fold?.classList?.remove('ui-icon-circle-add');
    fold?.classList?.add('ui-icon-circle-minus');
  }

  navToMark.style.display = "block";

  markActiveNav(
    event,
    Array.from(document.body.querySelectorAll('div#nav2 a.active')),
    navToMark
  );
}

/**
 * @param {HTMLAnchorElement} navToMark
 */
function saveActiveNavHierarchy(navToMark) {
  const navHierarchy = [];

  /** @type {HTMLLIElement|undefined} */
  let e = navToMark.closest('li') ?? undefined;
  while (e !== undefined) {
    const child = e.querySelector('a');
    if (child) {
      navHierarchy.push(child.textContent.trim());
    }
    e = e.parentElement?.closest('li') ?? undefined;
  }

  // muss encodiert werden, sonst Strings mit Umlauten werden nicht korrekt gespeichert, in PHP wird decodiert
  const navHierarchyEncodedStr = base64.encode(navHierarchy.join());
  fetch('index.php?ajax=session&set=activeNavHierarchy:' + navHierarchyEncodedStr, {
    'method': 'POST'
  }).catch(err => {
    console.error(err);
  });
}

/**
 * @param {URL} url
 * @return {HTMLAnchorElement|undefined}
 */
function findShouldBeActiveNavByUrl(url) {
  return document.body.querySelector('div#nav2 a.hasnosubitems[href$="' + url.search + '"]');
}

/**
 * 'active' Klassen bei dem Element und übergeordneten Menüpunkten setzen
 * @param {HTMLAnchorElement} navToMark
 */
function makeNavElementActive(navToMark) {
  navToMark.classList.add('active');

  let parentMenu = navToMark.closest('ul') ?? undefined;
  while (parentMenu !== undefined) {
    Array.from(parentMenu.parentElement.children)
      .filter(e => e.matches('a'))
      .forEach(e => {
        e.classList.add('active');
      });

    parentMenu = parentMenu.parentElement.closest('ul') ?? undefined;
  }
}

/**
 * @param event
 * @param {HTMLAnchorElement[]} markedNav
 * @param {HTMLAnchorElement} navToMark
 */
function markActiveNav(event, markedNav, navToMark) {
  event.preventDefault();
  // "active" des vorherigen Aktiven Menüpunkts entfernen.
  for (const e of markedNav) {
    e.classList.remove('active');
  }
  // Angeklickten Menüpunkt aktiv setzen
  makeNavElementActive(navToMark);

  // speichert den Link des aktuell ausgewählten Elements
  const navToMarkLink = base64.encode(navToMark.href);
  fetch('index.php?ajax=session&set=navToMarkLink:' + navToMarkLink, {
    'method': 'GET'
  }).catch(err => {
    console.log(err);
  });

  saveActiveNavHierarchy(navToMark);

  const link = navToMark.href;
  if (window.history && typeof window.history.pushState === 'function' && typeof URL === 'function' && typeof URLSearchParams === 'function') {
    let lastLink = window.location.href;
    if (!history.state || !history.state.loadedFromMarkActiveNav) {
      // Um richtigen Menüpunkt ansteuern zu können
      /** @type HTMLAnchorElement|undefined */
      const lastMarkedNav = markedNav.findLast(() => true);
      if (lastMarkedNav && lastMarkedNav.classList.contains('hasnosubitems')) {
        lastLink = lastMarkedNav.href;
        window.history.replaceState({ loadedFromMarkActiveNav: true }, '', lastLink);
      }
      else if (!markedNav) {
        lastLink = $('li > a.hasnosubitems').first().prop('href');
        window.history.replaceState({ loadedFromMarkActiveNav: true }, '', lastLink);
      }
    }
    if (link !== lastLink) {
      window.history.pushState({ loadedFromMarkActiveNav: true }, '', link);
    }
  }

  loadContent(link);
}

/**
 * Details per Klick als Dialog öffnen
 */
function setHelpTextDialog() {
  for (const element of document.querySelectorAll('div.detail')) {
    element.addEventListener('click', event => {
      if (event.target.tagName && event.target.tagName === 'A') {
        return;
      }

      const $meldung = $('<div class="detail_dialog">' + $(event.currentTarget).html() + '</div>');

      $meldung.dialog({
        title: 'Details',
        modal: true,
        autoOpen: true,
        dialogClass: 'largeFont',
        minWidth: 800,
        closeText: "",
        close: function () {
          $(event.currentTarget).dialog("destroy")
        }
      });
    }, { passive: true });
  }
}

/**
 * @param text
 * @return {Promise<void>}
 */
function copyToClipboard(text) {
  if (typeof navigator.clipboard !== 'undefined' && typeof navigator.clipboard.writeText !== 'undefined') {
    return navigator.clipboard.writeText(text);
  }

  var temp = $('<textarea class="temp">');
  temp.text(text);
  document.body.appendChild(temp[0]);
  $('body').append(temp);
  temp.trigger('select');

  var success = document.execCommand('copy');
  document.body.removeChild(temp[0]);
  if (!success) {
    console.log('Fehler beim Kopieren zum Clipboard')
    return new Promise(function (resolve, reject) {
      reject(text);
    });
  } else {
    return new Promise(function (resolve, reject) {
      resolve(text);
    });
  }
}

$(function ($) {
  /*****************************************************************************
   * Nachladen der Seiteninhalte per Ajax
   *****************************************************************************
   */

  for (const nav of document.body.querySelectorAll('div#nav2 a:not(.hassubitems)')) {
    nav.addEventListener('click', event => {
      markActiveNav(
        event,
        Array.from(document.body.querySelectorAll('div#nav2 a.active')),
        nav
      );
    });
  }

  if (window.history && typeof window.history.pushState === 'function' && typeof URL === 'function' && typeof URLSearchParams === 'function') {
    window.addEventListener('popstate', function (event) {
      if (!history.state || !history.state.loadedFromMarkActiveNav) {
        return;
      }

      loadContent(window.location);

      var url = new URL(window.location);
      i = 1;
      var $current = $('#nav2');
      do {
        $current = $current.find('ul.level' + i + ' > li')
        var searchParam = url.searchParams.get('sub' + i);

        if ($current.length >= searchParam && searchParam > 0) {
          $current = $($current[searchParam - 1]);
        }
        else {
          break;
        }
        i++;
      } while ($current.has('ul.level' + i) && url.searchParams.has('sub' + i));

      if ($current.length === 1) {
        $('div#nav2 a.active').removeClass('active');
        $current.find('a.hasnosubitems').addClass('active');
        $current.parents('ul').prev('a').addClass('active');
      }
    });
  }

  /** @type {HTMLAnchorElement|undefined} */
  const firstActiveElement = document.body.querySelector('div#nav2 a:not(.hassubitems).active') ?? undefined;
  if (firstActiveElement) {
    const elements = [
      firstActiveElement.closest('ul.level3') ?? undefined,
      firstActiveElement.closest('ul.level4') ?? undefined,
      firstActiveElement.closest('ul.level5') ?? undefined,
    ].filter(e => e !== undefined)

    for (const e of elements) {
      e.parentElement.querySelector('a.hassubitems')?.classList?.add('.active');
    }
  }

  /*****************************************************************************
   * Die n-te Ebene des Untermenüs einklappen & ausklappen
   *****************************************************************************
   */

  let countSubItems = 5; //Anzahl an Ebenen; muss angepasst werden, falls weitere Unterpunkte in der Navigation hinzukämen

  // Generelles ausblenden
  for (var i = 2; i <= countSubItems; i++) {
    $('#nav2 ul.level' + i.toString()).toggle();
  }

  // Toggle
  for (const nav of document.body.querySelectorAll('#nav2 a.hassubitems')) {
    const link = new URL(nav.href, location.href);
    let name = '';
    for (let i = 1; i <= countSubItems; i++) {
      let part = link.searchParams.get('sub' + i.toString()) ?? undefined;
      if (typeof part !== 'undefined') {
        name += part;
      }
    }

    nav.name = name;
  }

  const url = new URL(location.href);
  const page = url.searchParams.get('action') ?? undefined;

  let activmenu = '';
  fetch('index.php?ajax=session&key=activmenu_' + page, {
    'method': 'GET'
  })
    .then(resp => resp.text())
    .then(resp => base64.decode(resp))
    .then(resp => JSON.parse(resp))
    .then(data => {
      activmenu = data['activmenu_' + page];

      if (activmenu !== undefined && activmenu !== '') {
        const openSubParts = activmenu.split(" ");

        // Welche Oberpunkte sollen aufgeklappt werden
        for (let i = 0; i < openSubParts.length; i++) {
          $('#nav2 a.hassubitems[name=\'' + openSubParts[i] + '\']')
            .next().toggle()
            .prev().prev().addClass('ui-icon-circle-minus').removeClass('ui-icon-circle-plus');
        }

        // only toggled (displayed) elements should have minus sign
        const subParts = $('.hassubitems');
        subParts.each(function () {
          if ($(this).prev().hasClass('ui-icon-circle-minus') && $(this).next().is(":hidden")) {
            $(this).prev().removeClass('ui-icon-circle-minus').addClass('ui-icon-circle-plus');
          }
        });
      }
    })
    .catch(err => {
      console.error(err);
    });

  // Klick auf den Link
  for (const nav of document.body.querySelectorAll('#nav2 a.hassubitems')) {
    /** @type {HTMLElement|undefined} */
    const fold = nav.parentElement.querySelector('div.fold') ?? undefined;
    nav.addEventListener('click', event => {
      event.preventDefault();

      activmenu = toggleSubString(activmenu, nav.name);
      fetch('index.php?ajax=session&set=activmenu_' + page + ':' + activmenu, {
        'method': 'POST'
      }).catch(err => {
        console.error(err);
      });

      $(nav.parentElement.querySelector('ul')).toggle({
        duration: 'fast',
        start: function (animation) {
          if (animation.tweens[0].end > 0) {
            fold?.classList?.remove('ui-icon-circle-plus');
            fold?.classList?.add('ui-icon-circle-minus');
          } else {
            fold?.classList?.remove('ui-icon-circle-minus');
            fold?.classList?.add('ui-icon-circle-plus');
          }
        }
      });
    });
    fold?.addEventListener('click', event => {
      event.preventDefault();

      nav.click();
    })
  }

  setHelpTextDialog();

  // Einige Buttons haben den Typ Submit aus Layoutgründen, obwohl diese nicht das Formular absenden sollen
  // Langfristige bessere Lösung: Das Button-Layout nur über Klassen, und nicht über Typ lösen.
  jQuery('.noSubmit').on('click', function (event) {
    event.preventDefault();
  });
});

/**
 * @param {URL|string} url
 * @param {boolean|undefined} boosted
 */
function loadAjaxLink(url, boosted) {
  if (boosted) {
    window.history.pushState({
      loadedFromMarkActiveNav: true
    }, '', url.toString());
  }

  const content = document.body.querySelector('div#content');
  content.classList.add('loading');

  const contentInlay = content.querySelector('#content_inlay');
  const ajaxUrl = new URL(url);
  ajaxUrl.searchParams.set('ajax', 'content');
  fetch(ajaxUrl)
    .then(resp => (async() => {
      /** @type {HTMLAnchorElement|undefined} */
      let shouldMark = undefined;
      if (resp.ok) {
        if (boosted) {
          const url = new URL(resp.url);
          url.searchParams.delete('ajax');
          window.history.replaceState({
            loadedFromMarkActiveNav: true
          }, '', url.toString());

          shouldMark = findShouldBeActiveNavByUrl(url);
        }
      }

      return [shouldMark, await resp.text()];
    })())
    .then(([shouldMark, data]) => {
      const $contentInlay = $(contentInlay);
      $contentInlay.html(data);
      preparePage(contentInlay);
      content.classList.remove('loading');

      if (shouldMark) {
        for (const e of document.querySelectorAll('div#nav2 a.active')) {
          e.classList.remove('active');
        }

        makeNavElementActive(shouldMark);
      }
    })
    .catch(err => {
      console.error(err);

      contentInlay.innerHTML =
        '<div class="status_error">Ein Fehler ist aufgetreten.</div>';
    })
    .finally(() => {
      content.classList.remove('loading');
    });
}

function handleAjaxLinks() {
  if (!window.history) {
    return;
  }

  for (const ajaxlink of document.body.querySelectorAll('a.ajaxlink')) {
    const url = new URL(ajaxlink.href);
    const boosted = ajaxlink.classList.contains('ajaxlink-boosted');

    function overviewIfEmpty(str) {
      if (!str) {
        return 'overview';
      }

      return str;
    }

    let newUrlAction = overviewIfEmpty(url.searchParams.get('action'));
    let currentUrlAction = overviewIfEmpty(new URL(window.location.href).searchParams.get('action'));

    if (newUrlAction !== currentUrlAction) {
      continue; // Bei Link auf eine andere Seite ignorieren
    }

    ajaxlink.addEventListener('click', event => {
      event.preventDefault();

      loadAjaxLink(url, boosted);
    });
  }
}