/* 
 * SPEZIELL FUER RESPONSIVE DESIGN:
 * Enthält die allgemeinen Events und Funktionen
 * 
 * Pfad: ../kufertools/sys/layout/js
 * 
 * Achtung: Hier werden nur die Methoden implementiert, die sich von denen in der Original Datei 
 * webtools/js/project.js unterscheiden; dadurch werden die alten Methoden überschrieben. 
 */


function registerNamespace(ns) {
  var parts = ns.split(".");
  var root = window;

  for (var i = 0; i < parts.length; i++) {
    if (typeof root[parts[i]] === "undefined")
      root[parts[i]] = {};

    root = root[parts[i]];
  }
}

/** Konstanten, die an mehreren Stellen gebraucht werden */
var CalendarDayNames = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
var CalendarDayNamesShort = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'];

if (typeof KuferTools == 'undefined') KuferTools = {};
// registerNamespace(KuferTools);

initLocalization();

registerNamespace('KuferTools.Button.Bezeichnung');
KuferTools.Button.Bezeichnung.Schliessen = 'Schließen';
KuferTools.Button.Bezeichnung.FilterLeeren = 'Filter leeren';
KuferTools.Button.Bezeichnung.FilterSetzen = 'Filter setzen';
KuferTools.Button.Bezeichnung.Ok = 'Ok';
KuferTools.Button.Bezeichnung.Abbrechen = 'Abbrechen';

$(function () {

  // Falls sich Eingabefelder auf der Seite befinden, soll das erste Fokusiert werden.
  // Das macht z. B. den Loginbildschirm angenehmen, da man sofort den Benutzernamen eingeben kann.
  $('input:text:visible, input:password:visible, select:visible, textarea:visible:not(:disabled)').not('.anw_ktueb_datum, #datumwahl4geb, #grafik_starttime, #grafik_endtime, #datumwahl4, #grafik_datvon, #grafik_datbis').first().trigger('focus');

  $(document.body).on('submit', '#privilege-selection-form, #add-privileges-form', function (e) {
    e.preventDefault();
    const divContent = document.body.querySelector('div#content');

    const form = this;
    /** @type {HTMLInputElement[]} */
    const privileges = Array.from(form.querySelectorAll('input.privilege-access[type=radio]:checked'));
    divContent.classList.add('loading');
    fetch(form.action, {
      method: 'POST',
      headers: new Headers({
        'Content-Type': 'application/json',
      }),
      body: JSON.stringify(privileges.map(privilegeElement => {
        return {
          privilege_id: parseInt(privilegeElement.name.match(/[0-9]+/)[0]),
          status: parseInt(privilegeElement.value)
        };
      }))
    })
      .then(resp => resp.text())
      .then(resp => {
        document.getElementById('content_inlay').innerHTML = resp;
        divContent.classList.remove('loading');
      })
      .catch(err => {
        console.error(err);
        document.getElementById('content_inlay').innerHTML = '<div class="error">Ein Fehler ist aufgetreten</div>';
        divContent.classList.remove('loading');
      })
  });

  $(document).on('click', '.ajax-link', function (e) {
    e.preventDefault();
    const divContent = document.body.querySelector('div#content');
    divContent.classList.add('loading');
    fetch(e.target.closest('.ajax-link').href, {
      method: 'GET',
    })
      .then(resp => resp.text())
      .then(resp => {
        const contentInlay = document.getElementById('content_inlay');
        $(contentInlay).html(resp);
        if (typeof preparePage === "function") {
          preparePage(contentInlay);
        }
        divContent.classList.remove('loading');
      })
      .catch(err => {
        console.error(err);
        document.getElementById('content_inlay').innerHTML = '<div class="error">Ein Fehler ist aufgetreten</div>';
        divContent.classList.remove('loading');
      })
  });

  $(document).on('click', '.privilege-searchbutton', function (e) {
    searchPrivileges();
  });

  $(document).on('keypress', '.privilege-searchinput', function (e) {
    if (e.originalEvent.charCode == 13) {
      searchPrivileges();
    }
  });

  $(document).on('click', '.privilege-searchcancel', function (e) {
    removePrivilegeSearchHighlightAndWarning();
  });

  $(document).on('click', '.treetable-titlebar', function (e) {
    const button = $(e.currentTarget).find('.treetable-collapse')[0];
    const $toggleDiv = $(e.currentTarget.parentElement);

    if ($toggleDiv.children(':visible').not('.treetable-titlebar').length === 0) {
      $toggleDiv.children().not('.treetable-titlebar').show();
      button.innerHTML = '<span class="fold ui-icon ui-icon-circle-minus" id="rechte">';
    } else {
      $toggleDiv.children().not('.treetable-titlebar').hide();
      button.innerHTML = '<span class="fold ui-icon ui-icon-circle-plus" id="rechte">';
    }
  });

  $(document).on('click', '.show-add-privileges', function (e) {
    e.preventDefault();
    const divContent = document.body.querySelector('div#content');
    divContent.classList.add('loading');
    fetch(e.target.parentElement.href, {
      method: 'POST'
    })
      .then(resp => resp.text())
      .then(data => {
        const contentInlay = divContent.querySelector('#content_inlay');
        $(contentInlay).html(data);
        if (typeof preparePage === 'function') {
          preparePage(contentInlay);
        }
        divContent.classList.remove('loading');
      });
  });

  $(document).on('click', '.privilege-reset-auswahl', function (e) {
    const privId = e.target.dataset.privilegeId;
    /**
     * @type {NodeListOf<HTMLInputElement>}
     */
    const privAccessElements = document.body.querySelectorAll(`[name$="priv-${privId}-access"]`);
    for (const privAccessElement of privAccessElements) {
      privAccessElement.checked = false;
    }
  });

  $(document).on('click', '.privilege-table-key', function (e) {
    var $keyCell = e.target;
    var $table = $(e.target.closest('tbody'));
    if ($keyCell.classList.contains('sorted-asc')) {
      sortPrivilegeKeys($table, false);
    } else {
      sortPrivilegeKeys($table, true);
    }
  });

});  // End Ready

function searchPrivileges() {
  const toSearch = document.body.querySelector('.privilege-searchinput').value.trim();
  removePrivilegeSearchHighlightAndWarning();
  if (toSearch.length === 0) {
    $('.privilege-utilbar').append("<div class=\"status_warning\">Bitte geben Sie einen Suchbegriff ein.</div>");
    return;
  }
  /*
   * JQuery Contains ist leider standardmaeßig case-sensitive, dieser
   * workaround ermoeglicht case-insensitive Suche 
   */
  $.extend($.expr.pseudos, {
    'containsi': function (elem, i, match, array) {
      return (elem.textContent || elem.innerText || '').toLowerCase()
        .indexOf((match[3] || "").toLowerCase()) >= 0;
    }
  });

  var formSelector = ($('#add-privileges-form').length > 0) ? '#add-privileges-form' : '#privilege-selection-form';

  var sel = formSelector + ' td:containsi(' + toSearch + ')';
  var result = $(sel);
  if (result.length === 0) {
    $('.privilege-utilbar').append("<div class=\"status_warning\">Keine Ergebnisse gefunden.</div>");
  }
  KuferTools.PreviousPrivilegeSearchResults = result;

  result.each(function (i, e) {
    e.parentNode.style.background = '#fff300';
    let parents = $(e.parentNode).parentsUntil('#privilege-selection-form', '.treetable-group');
    parents.each(function (i, e) {
      if ($(e).children(':visible').length == 1) {
        $(e).find('.treetable-titlebar').trigger('click');
      }
    });
  })
}

function removePrivilegeSearchHighlightAndWarning() {
  $('.privilege-utilbar .status_warning').remove();
  if (KuferTools.PreviousPrivilegeSearchResults != null) {
    KuferTools.PreviousPrivilegeSearchResults.each(function (i, e) {
      if ($(e.parentNode).index() % 2 === 0) {
        e.parentNode.style.backgroundColor = '#ffffff';
      } else {
        e.parentNode.style.backgroundColor = '#f2f2f2';
      }
    });
    KuferTools.PreviousPrivilegeSearchResults = null;
    document.body.querySelector('.privilege-searchinput').value = '';
  }
}

function sortPrivilegeKeys($tableBody, $asc) {
  var sortedRows = $tableBody.find('.privilege-group').sort(function (row1, row2) {
    const key1 = row1.querySelector('.privilege-key').innerText;
    const key2 = row2.querySelector('.privilege-key').innerText;
    /* 
     * +100000 da Schlüssel mit einem Punkt oben, und mit mehren Punkten, unten
     * angezeigt werden sollen.
     */
    const factor1 = (key1.match(/\./g).length === 1) ? 10000000 : 0;
    const factor2 = (key2.match(/\./g).length === 1) ? 10000000 : 0;

    const ascFactor = $asc ? 1 : -1; // Ergebnis invertieren um absteigend zu sortieren
    const key1Num = parseInt(key1.replace(/\./g, ''));
    const key2Num = parseInt(key2.replace(/\./g, ''));
    return ascFactor * ((key1Num + factor1) - (key2Num + factor2));
  });
  $tableBody.find('.privilege-group').remove();
  $tableBody.append(sortedRows);

  var $keyTitleCell = $tableBody.find('.privilege-table-key');
  if ($asc) {
    $keyTitleCell.addClass('sorted-asc');
    $keyTitleCell.removeClass('sorted-desc');
  } else {
    $keyTitleCell.removeClass('sorted-asc');
    $keyTitleCell.addClass('sorted-desc');
  }
}

/**
 * Allgemeine Funktion zum Ausgeben von Meldungen
 * 
 * Diese Funktion ersetzt die alte showMessage Funktion und soll für das Responsive Design verwendet werden.
 * Hauptunterschied: Es wir nur noch ein Messageobjekt als Parameter übergeben, der die benötigten 
 * Objektvariablen enthält wie z.B. meldung, title etc.  
 * wurde gegenüber der Original Funktion um den Events  dragStop erweitert, um ein Dialogfenster nach dem 
 * Verschieben auch weiterhin flexibel in Breite und Höhe mit Wert 'auto' zu halten. 
 * Sonst wird beim Verschieben eine feste Höhe bzw. Breite zugewiesen (und das ist nicht mehr Responsive)
 * 
 * @param pMessageObj Meldungs Objekt bestehend aus:
 *   { string meldung Meldungsinhalt, 
 *     string title Dialogtitel, 
 *     object buttons Buttons, 
 *     string width Breite des Fensters (optional, 
 *     string height Höhe des Fensters (optional), 
 *     string position Position des Fensters 
 *     function pressEntrFunc Funktion, die aufgerufen wird, wenn die Enter-Taste gedrückt wird (optional)
 *   }
 * @param pOpenFunc Funktions Objekt bzw. Funktion, die beim Öffnen des Dialogs noch zusätzlich ausgeführt werden kann (bei Bedarf)
 * @param pCloseFunc Function wenn Dialog geschlossen wird
 *            
 **/
// function showMessage(meldung, pTitle, pButtons, pWidth, pPosition, pPressEnterFunc, pHeight) {

KuferTools.showMessage = function (pMessageObj, pOpenFunc, pCloseFunc) {
  // Erstmal die definierten Objektvariablen in passenden Variablen abspeichern
  var meldung = '';
  if (typeof pMessageObj.meldung !== 'undefined') {
    meldung = pMessageObj.meldung;
  }
  var title = '';
  if (typeof pMessageObj.title !== 'undefined') {
    title = pMessageObj.title;
  }

  var buttons = {};
  buttons[KuferTools.Button.Bezeichnung.Ok] = function () { $(this).dialog("close"); };
  if (typeof pMessageObj.buttons !== 'undefined') {
    buttons = pMessageObj.buttons;
  }

  var width = 550;
  if (typeof pMessageObj.width !== 'undefined') {
    width = pMessageObj.width;
  }

  var height = 'auto';
  if (typeof pMessageObj.height !== 'undefined') {
    height = pMessageObj.height;
  }

  var position = { my: "center", at: "center", of: window }
  if (typeof pMessageObj.position !== 'undefined') {
    position = pMessageObj.position;
  }

  //Zusätzliche Eingabe einer DialogId ermöglichen
  var dialogId = '';
  if (typeof pMessageObj.dialogId !== 'undefined') {
    dialogId = pMessageObj.dialogId;
  }

  var $meldung;
  if (typeof meldung == 'object') {
    if (isempty(meldung.html())) {
      console.log('Fehler beim Erstellen des Dialogs: Kein Inhalt für den Dialog vorhanden. ');
      $meldung = $('<div>Allgemeiner Fehler: Bitte kontaktieren Sie die Schulungseinrichtung.</div>');
    }
    else
      $meldung = meldung;
  }
  else {
    $meldung = $('<div>' + meldung + '</div>');
  }

  //$meldung.dialog('widget').prop('id', 'dialogId');
  $meldung.dialog({
    modal: true,
    autoOpen: false,
    position: position,
    width: width,
    height: height,
    title: title,
    bgiframe: true,
    resizable: false,
    dialogClass: 'dialogwindow',
    closeOnEscape: false,//ansonsten bei manchen DetailDialogen ein Problem (z.B. Unterrichtsmittellist, wenn neuer Eintrag da, und dann ESC/schließen
    buttons: buttons,
    close: function (a, b) {
      $meldung.detach(); //Bei Verwendung von .remove() wurden anschließend immer Javascript Fehler erzeugt,
      //wenn man auf inputs geklickt hat. Wieso das so ist, war nicht nachzuvollziehen.
      KuferTools.DialogWindows.pop();

      if (typeof pCloseFunc !== "undefined") {
        pCloseFunc();
      }
    },
    open: function (event, ui) {
      registerNamespace('KuferTools');
      if (typeof (KuferTools.DialogWindows) == 'undefined') {
        KuferTools.DialogWindows = [];
      }
      KuferTools.DialogWindows.push($(this));

      //setzt wg. Datepicker vorab den Focus auf das erste Textarea- oder Input-Feld; sonst blendet gleich der Datepicker Kalender auf, 
      // wenn das erste Eingabefeld ein Datumsfeld ist und man irgendein anderes Eingabefeld anklickt
      KuferTools.DialogWindows[KuferTools.DialogWindows.length - 1].find('input, textarea').first().trigger('focus');

      var $hasDatePicker = KuferTools.DialogWindows[KuferTools.DialogWindows.length - 1].find('.hasDatepicker');
      //Falls beim Dialog zuvor ein Date-/Timepicker existierte, kann es sein, dass es die Klasse hasDatepicker bereits gibt,
      //und es wird kein Datepicker hinzugefügt. Deshalb die Klasse hasDatepicker entfernen, sofern vorhanden.
      $hasDatePicker.removeClass('hasDatepicker');

      KuferTools.InitAllgemeineHandler($hasDatePicker);

      if (typeof pMessageObj.inputvals !== 'undefined') {
        var inputFields = $(this).find(':input');
        inputFields.each(function () {
          if ((pMessageObj.inputvals[this.id])) {
            $(this).val(pMessageObj.inputvals[this.id]); // match ids and set vals
          }
        });
      }
      // Falls der 2te Parameter definiert ist, zusätzlich diese Funktion ausführen; wird z.B. Beim Öffnen
      // des Dialogs für das Hinzufügen von Unterrichtsmitteln gebraucht (in doz_anwesenheitseingabe.js)
      if (typeof pOpenFunc !== 'undefined')
        pOpenFunc();

      $(".ui-dialog-titlebar-close", ui.dialog).hide();
    },  //end function
    dragStop: function (event, ui) {

      // Um die Responsible Eigenschaften zu gewährleisten, muss nach dem Verschieben des Dialog Fensters 
      //  die Breite und Höhe wieder auf "auto" gesetzt werden; beim drag wird sie automatisch 
      //  auf einen festen Wert gesetzt
      // ui ist ein Objekt das die aktuelle Position des Dialogs wiedergibt in ui.offset 
      // event.target ist das Dialog div#ajaxResponse; das Elternelement davon ist das aktuelle
      // UI-Dialog Fenster, <div class="ui-dialog ui-widget dialogwindow..."> 

      $(event.target).parent().css('height', height).css('width', width);
    } //end function           



  }); //end dialog

  // Falls vorhanden zusätzlich die DialogId im Ui-Dialog mitausgeben; hierzu gibt es keine Dialog Option; das 
  // geht nur mit der Widget() Funktion des Dialogs
  if (dialogId !== '')
    $meldung.dialog('widget').prop('id', dialogId);
  $meldung.dialog('open');

  var pressEnterFunc;
  if (typeof pMessageObj.pressEnterFunc !== 'undefined') {
    if (typeof pMessageObj.pressEnterFunc === 'function') {
      pressEnterFunc = pMessageObj.pressEnterFunc;
    }
  }

  // Damit Datepicker usw. in den Dialogen wieder funktionieren.
  KuferTools.InitAllgemeineHandler($meldung);

  //Bei Drücken der Enter-Taste Formular abschicken
  $meldung.parents('.ui-dialog').on('keydown', $(this), function (event) {
    const key = event.key;

    if (key === 'Enter') {
      if (typeof (pressEnterFunc) !== "undefined" && event.target.nodeName !== 'TEXTAREA') {
        event.preventDefault();
        pressEnterFunc.call($meldung);
      }
    } else if (key === 'Escape') {
      if (typeof pCloseFunc !== 'undefined') {
        pCloseFunc();
      }

      $meldung.dialog('close');
    }
  });
}; //end showMessage(..)





KuferTools.InitDatePickerOld = function ($pTarget) {
  $pTarget.datepicker({
    changeYear: true,
    constrainInput: true,
    dateFormat: "dd.mm.yy",
    yearRange: 'c-80:c+10'
  });
};



/**
 * Initialisiert einen Datepicker zu einem Datum , Monat, Jahr oder einer Woche für die übergebenen Input-Elemente
 * 
 * Gibt in Abhängigkeit vom Mode den passenden Datepicker aus
 * 
 * @param jQuery $target
 * @param string pMode 'kaljahr', 'kalwoche' oder 'kalmonat'
 */

KuferTools.InitDatePicker = function ($pTarget, pMode) {

  //Per default wird ein DatumsFormat dd.mm.yy ausgegeben

  if (typeof pMode === 'undefined') {
    $pTarget.datepicker({
      changeMonth: true,
      changeYear: true,
      constrainInput: true,
      dateFormat: "dd.mm.yy",
      yearRange: 'c-80:c+10'
    });
    return;
  }
  switch (pMode) {
    case 'kaljahr':
      KuferTools.InitJahrPicker($pTarget);
      break;
    /**
  case 'kalmonat':
    KuferTools.InitMonatPicker($pTarget);
    break; */
    case 'kalwoche':
      KuferTools.InitWochenPicker($pTarget);
  } //end switch


};

/**
 * Initialisiert einen Standard-Datepicker für die übergebenen Input-Elemente
 * 
 * Es wird ein Datumsformat mit 4-Stellige Jahreszahl ausgegeben, die Jahre können via Select geändert werden
 * 
 * @param jQuery $target
 */
KuferTools.InitDateTimePicker = function ($pTarget) {
  $pTarget.datetimepicker({
    changeYear: true,
    constrainInput: true,
    dateFormat: "dd.mm.yy",
    yearRange: 'c-80:c+10',
    timeFormat: "HH:mm"
  });
};


/**
 * Initialisiert einen Jahrpicker für die übergebenen Input-Elemente
 * 
 * verwendet einen Datepicker der nur eine 4-Stellige Jahreszahl (ohne Tag und monat ausgibt);
 * die Jahre können mit einem Select geändert werden.
 * 
 * @param jQuery $target
 */
KuferTools.InitJahrPicker = function ($pTarget) {
  $pTarget.datepicker({
    //  defaultDate: '2015',
    //Gibt ein Objekt mit Optionen zurück, mit denen die aktuelle Datepicker Instanz upgedatet wird
    //ändert nur die aktuelle (aber keine anderen) DatePicker Instanzen
    beforeShow: function () {
      var inputVal = $(this).val();
      return {
        defaultDate: (inputVal !== '') ? new Date(inputVal) : null,
        dateFormat: 'yy',
        constrainInput: true,
        showMonthAfterYear: false,
        changeMonth: false,
        changeYear: true,
        showButtonPanel: true,  //nächste 2 Buttons gehören zu  diesem Panel
        currentText: 'aktuelles Jahr',
        closeText: 'schließen',
        stepMonths: 12,
        monthNames: ["", "", "", "", "", "", "", "", "", "", "", "", "", ""],


        onChangeMonthYear: function (year) {

          $(this).val(year);
        }
      };
    }, //end function

    onClose: function (dateText, inst) {
      // wenn nichts im Inputfeld für das Jahr eingetragen ist, wird das aktuelle Datum für die Anzeige des Jahres 
      // im Kalender verwendet
      var aktDate = new Date();
      if (dateText != '')
        aktDate = new Date(dateText);
      //aktuell ausgewählte Kalenderwoche
      var wk = $('#wochenplan').find('#kwnr').val()
      // var wk = $.datepicker.iso8601Week(aktDate);
      var jahr = aktDate.getFullYear();
      //Eingabefeld für das Jahr input#kwjahr
      if (isNaN(jahr)) {
        $(this).val("");
      } else {
        $(this).val(jahr);
      }

      // Besetzt den Von-Bis Datumsbereich im Wochenplan Formular mit dem neu aus Kalenderwoche und -jahr
      // berechneten Daten
      KuferTools.getDateVonBisFromKalenderInput(wk, jahr);


    } //end function


  }); //end datepicker

  //Blendet den Kalender (im Gegensatz zum Datepicker) aus
  $pTarget.on('focus', function () {
    $(".ui-datepicker-calendar").hide();
  });

}; //end InitJahrPicker


/**
 * Initialisiert einen Wochenpicker für die übergebenen Input-Elemente
 * 
 * verwendet einen Datepicker, der einen Kalender anzeigt und zum angeklickten Datum eine Wochennummer 
 *  (zwischen 1 und 53) selektiert 
 * 
 * @param jQuery $target
 */
KuferTools.InitWochenPicker = function ($pTarget) {

  var startDate;
  var endDate;

  /**
    var selectCurrentWeek = function () {
      window.setTimeout(function () {
        $pTarget.datepicker('widget').find('.ui-datepicker-current-day a').addClass('ui-state-active')
      }, 1);
    }
    **/

  $pTarget.datepicker({
    dateFormat: "yy-mm-dd",
    showOtherMonths: true,
    selectOtherMonths: true,
    changeMonth: true,
    changeYear: true,
    showWeek: true,

    //setzt vor dem Klick auf das Eingabefeld die Tage der aktuell gewählten Kalenderwoche auf aktiv
    // und initialisiert die MouseHandler zum highlighten
    beforeShow: function () {

      //  $("#ui-datepicker-div td.ui-datepicker-today").removeClass('ui-datepicker-current-day'); 
      // für Wochen Highlighting
      $(document).on("mousemove", ".ui-datepicker-calendar tr", function () {
        $(this).find(".ui-datepicker-week-col").addClass("ui-state-hover");
      });
      $(document).on("mouseleave", ".ui-datepicker-calendar tr", function () {
        $(this).find("td a").removeClass("ui-state-hover");
        $(this).find(".ui-datepicker-week-col").removeClass("ui-state-hover");
      });
    },
    //wird beim Klick auf einen Kalendertag im Datepicker Kalender (ui-datepicker-calendar) ausgeführt;
    // setzt die zum ausgewählten Tag gehörigen Wochentage auf aktiv (via selectCurrentWeek())
    onSelect: function (dateText, inst) {
      var date = $(this).datepicker('getDate');
      //Auswahl: von Mo -So einer Woche
      startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay() + 1);
      endDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay() + 7);
      //    console.log('Onselect StartTag: ' + (date.getDate() - date.getDay() + 1) + '  Endtag: ' + (date.getDate() - date.getDay() + 7));

    },
    beforeShowDay: function (date) {

      var cssClass = '';
      // console.log('beforeShowDay Start: ' + startDate + '  Ende: ' + endDate + ' Date:  ' + date);
      if (date >= startDate && date <= endDate)
        cssClass = 'ui-datepicker-current-day';
      return [true, cssClass];
    },
    //waehlt die Wochennr und das Jahr  beim Schließen des Kalenders
    onClose: function (dateText, inst) {

      // wenn nichts im Inputfeld für das Jahr eingetragen ist, wird das aktuelle Datum für die Anzeige der Woche 
      // im Kalender verwendet
      var aktDate = new Date();
      if (dateText != '')
        aktDate = new Date(dateText);
      var wk = $.datepicker.iso8601Week(aktDate);
      var jahr = aktDate.getFullYear();
      if (parseInt(wk) < 10) {
        wk = "0" + wk;
      }
      if (!isNaN(wk)) {
        // wk = $(this).val()
        $(this).val(wk);
      }
      else {
        //bisherigen Wert setzen für die Woche
        wk = $(this).val();
      }

      if (!isNaN(jahr)) {
        //das korrekte Jahr setzen
        $('#wochenplan').find('#kwjahr').val(jahr);
      }
      else {
        //bisherigen Wert für das Jahr setzen
        jahr = $('#wochenplan').find('#kwjahr').val();
      }
      // Besetzt den Von-Bis Datumsbereich im Wochenplan Formular mit dem neu aus Kalenderwoche und -jahr
      // berechneten Daten
      KuferTools.getDateVonBisFromKalenderInput(wk, jahr);

      // deaktiviert live listeners so dass sie keine wirkung auf anderen Instanzen haben
      $(document).off("mousemove", ".ui-datepicker-calendar tr");
      $(document).off("mouseleave", ".ui-datepicker-calendar tr");
    } //end function

  }); //end datepicker


}; //end KuferTools.InitWochenPicker


/*
 * Wird im Close Handler des Wochenpickers und Jahrpickers aufgerufen
 */
KuferTools.getDateVonBisFromKalenderInput = function (pKWeek, pKYear) {

  var datary = KuferTools._getWocheVonBis(pKWeek, pKYear);
  var datVon = datary[0]; ////Datumsstring z.B. 12.01.2008
  var datBis = datary[1];
  $('#wochenplan').find('#datbereich_von').val(datVon);
  $('#wochenplan').find('#datbereich_bis').val(datBis);
  $('#wochenplan').find('#kt_von').val(datVon);
  $('#wochenplan').find('#kt_bis').val(datBis);

} //end KuferTools.getDateVonBisFromKalenderInput


/*********************************************************************************
* Diese Funktion berechnet das Datum des ersten und letzten Tages d.h. des Montags 
* und Sonntags der [intWeek]-ten Kalenderwoche
*+des Jahres [intYear] und gibt es als Array von Javascript Date()-Objekt zurück.
* Verwendet wird die DIN 1355 / ISO 8601 Kalenderwochen-Norm
* [intYear] muss nach 1990 sein, wegen Unzulänglichkeiten von Javascript.
*
*********************************************************************************/

KuferTools._getWocheVonBis = function (intWeek, intYear) {
  // VORARBEIT    
  var dat = new Date(intYear, 0, 1);    // Datum hier initalisiert auf der 1.1 des Jahres
  var firstDay = dat.getDay();    // Wochentag für den 1.1. des Jahres
  if (firstDay == 0) firstDay = 7; // (1=Montag, 2=Diestag, ..., 7=Sonntag)
  // EINGABEPRÜFUNG
  // Date-Objekt verhält sich nur gutartig für Jahre nach 1990
  // Ein jahr hat normalerweise 52 Kalenderwochen nach Definition
  // Ist der 1.1 des Jahres aber ein Donnerstag, hat es 53 Kalenderowchen
  // Negative Kalenderwochen machen keinen Sinn
  if (intYear < 1991 || intWeek < 1 || intWeek > 53 || (intWeek > 52 && firstDay != 4)) return false;
  var eintag = 24 * 60 * 60 * 1000;
  var einewoche = 7 * eintag;
  // BERECHNEN DES STARTDATUMS FÜR DIE ERSTE KALENDERWOCHE
  // Ist der 1.1 später als Donnerstag, startet die erste Kalenderwoche erst am folgenden Montag
  if (firstDay > 4)
    dat.setTime(dat.getTime() + (8 - firstDay) * eintag);
  // Sonst startet die erste Kalenderwoche am Montag vor dem 1.1 bzw. am 1.1 wenn er ein Montag ist
  else
    dat.setTime(dat.getTime() + (1 - firstDay) * eintag);
  // Die [intWeek]-te Kalenderwoche ist sieben mal [intWeek] minus eins Tage später als die erste
  var datAry = new Array(2);
  dat.setTime(dat.getTime() + (intWeek - 1) * einewoche);// Von Datumswert
  datAry[0] = KuferTools.FormatDate(dat);
  dat.setTime(dat.getTime() + 6 * eintag); //Bis Datumswert
  datAry[1] = KuferTools.FormatDate(dat);
  // RETURN DES DATUM-OBJEKTS
  return datAry;
}

// Gibt das Datum im Format dd.mm.jjjj zurück
KuferTools.FormatDate = function (pDate) {
  var day = pDate.getDate().toString();
  if (day.length < 2)
    day = "0" + day;

  var month = pDate.getMonth() + 1;
  var monthstr = month.toString();
  if (monthstr.length < 2)
    monthstr = "0" + monthstr;
  return day + "." + monthstr + "." + pDate.getFullYear();
}

//gibt die Zeit zu einem Datumswert im Format hh:mm zurück
KuferTools.FormatTime = function (pDate) {
  var hour = pDate.getHours().toString();
  if (hour.length < 2)
    hour = "0" + hour;
  var minute = pDate.getMinutes().toString();
  if (minute.length < 2)
    minute = "0" + minute;
  return hour + ":" + minute;
}


/** 
 * Formular-Validierung
 * 
 * Die Bezeichnung der fehlerhaften Felder in der Meldung wird anhand deren Label ermittelt.
 * Falls eine andere Bezeichnung verwendet werden soll oder kein Label vorhanden ist kann 
 * an das Feld .data('error_msg', Text) angehängt werden.
 * 
 * Für Sonderfälle bei der Validierung siehe Kommentar zu getAndMarkInvalidInputs() 
 **/
KuferTools.ValidateFormInput = function ($target) {
  // Aus sighbuilder.js übernommen
  var $invalidInputs = getAndMarkInvalidInputs($target);

  if ($invalidInputs.length > 0) {
    var meldung = 'Nicht alle Eingabefelder sind korrekt gef&uuml;llt. <br>' +
      'Bitte pr&uuml;fen Sie die markierten Felder, ob Pflichtfelder leer ' +
      'gelassen wurden, oder die Eingaben in einem falschen Format eingetragen sind.';
    //Sucht zu den falsch ausgefüllten Eingabefeldern die Labels raus, um diese in der Meldung angeben zu können.
    var errorLabels = [];
    $invalidInputs.each(function () {
      var optionalLabel = $(this).data('error_msg');
      if (typeof (optionalLabel) !== 'undefined') {
        if (optionalLabel !== '') {
          errorLabels[errorLabels.length] = optionalLabel;
        }
      }
      else {
        var $label = $('label[for="' + $(this).prop('id') + '"]');
        if ($label.length > 0 && KuferTools.Utils.trimS($label.text()) != '') {
          errorLabels[errorLabels.length] = $label.text();
        }
      }
    }); // end $('.form_error').each()
    //Falls Labeltexte zu den falsch ausgefüllten Eingabefeldern gefunden wurden, gib diese in der Meldung aus.
    if (errorLabels.length > 0) {
      meldung += '<br><br>Bitte &uuml;berpr&uuml;fen Sie unter anderem folgende Felder: ' + "\n" + '<ul class="errorFields">';
      for (var i = 0; i < errorLabels.length; i++) {
        meldung += '<li>' + errorLabels[i] + '</li>';
      }
      meldung += '</ul>';
    }
    KuferTools.showMessage({
      meldung: meldung,
      title: 'Nicht alle Felder sind korrekt gefüllt',
      pressEnterFunc: function () {
        $(this).dialog('close');
      }
    });
    return false;
  }
  return true;
}

KuferTools.InitValidate = function ($target) {
  $target.each(function () {
    getAndMarkInvalidInputs($(this));
    var $inputs = KuferTools.Utils.getInputableElements($(this));
    addToolTip($inputs);
    $inputs.on('change', function () { validateInput($(this)); });
  });
};


/**
 * Validiert die Eingabefelder anhand val_-Klassen.
 * 
 * Diese Funktion kann über die Hook-Funktion KuferTools.ValidateFormHandler um Sonderfälle erweitert werden.
 * KuferTools.ValidateFormHandler soll zum einen die fehlerhaften Eingabefelder als jQuery-Selector zurückgeben sowie 
 * ggf. die Klasse form_error vergeben.
 * 
 * @param {jQuery|$} $target
 * @returns {jQuery|$}
 * 
 **/
function getAndMarkInvalidInputs($target) {
  var $invalidInputs = $();
  var $inputs = KuferTools.Utils.getInputableElements($target);
  $inputs.each(function () {
    if (!validateInput($(this))) {
      $invalidInputs = $invalidInputs.add($(this));
    }
  });

  // optional handler Funktion für weitere Validierung
  if (typeof KuferTools.ValidateFormHandler === 'function') {
    $invalidInputs = $invalidInputs.add(KuferTools.ValidateFormHandler());
  }
  return $invalidInputs;
}

//Speziell für den Admin aus develop/webtools/functions.js übernommen
function FormatTime(pDate) {
  var hour = pDate.getHours().toString();
  if (hour.length < 2)
    hour = "0" + hour;
  var minute = pDate.getMinutes().toString();
  if (minute.length < 2)
    minute = "0" + minute;
  return hour + ":" + minute;
}


//Speziell für den Admin aus develop/webtools/js/project.js übernommen
function isempty(mixedvar) {
  if (mixedvar === "" ||
    mixedvar === "0" ||
    mixedvar === null ||
    mixedvar === false ||
    typeof mixedvar === 'undefined'
  ) {
    return true;
  }
  // wenn irgeine Objektvariable enthalten ist, liefert die Methode false (da nichtleer);
  // reagiert aber nicht richtig für jQuery Objekte, da diese IMMER eine length property 
  // enthalten
  if (typeof mixedvar == 'object') {
    for (var key in mixedvar) {
      return false;
    }
    return true;
  }
  return false;
}
