// anmeldung.js   rxf   2020-10.12
// Dynamik für die Anmelde-Seite
//

$(document).ready(() => {

    const ajaxURL="../DB4js.php";
    const maxPersonen = 10;

    const dummyTln = {
        name:"Zuname{z}",
        vorname:"",
        email:"rxf{z}@gmx.de",
        telefon:"0711123456789",
        plz:"12345",
        stadt:"Ort{z}",
        strasse:"Straße {z}",
        fid: "",
        anzahl:1,
        teilgenommen: 0,
        remarks:"Bemerkung Nr {z}",
        abgesagt: 0,
        angemeldet: moment().format("YYYY-MM-DD")
        };

    let aktualTln = {
        name:"",
        vorname:"",
        email:"",
        telefon:"",
        plz:"",
        stadt:"",
        strasse:"",
        fid: "",
        anzahl:1,
        teilgenommen: 0,
        remarks:"",
        abgesagt: 0,
        angemeldet: ""
    };

    const mandatory = {
        name:true,
        vorname:false,
        email:true,
        telefon:false,
        plz:true,
        stadt:true,
        strasse:true,
        fid: false,
        anzahl:false,
        teilgenommen: false,
        remarks:false,
        abgesagt: false,
        angemeldet: true
    };

    let allParticipants = [];
    let errtext = "";


    // Von der Datenbank Werte abholen
    // Param:
    //      body: Object mit cmd und param
    // Return:
    //      angeforderte Daten als JSON
    const fetchFromDbase = async (body) => {
        const response = await fetch(ajaxURL,{
            method: 'POST',
            headers: {'Content-Type': 'application/js'},
            body: JSON.stringify(body)
        });
        return await response.json();
    }


    // In die Datenbank Werte eintragen
    // Param:
    //      body: Object mit cmd und param
    // Return:
    //      angeforderte Daten als JSON
    const putToDbase = async (body) => {
        const response = await fetch(ajaxURL,{
            method: 'POST',
            headers: {'Content-Type': 'application/js'},
            body: JSON.stringify(body)
        });
        return await response.json();
    }


    // Beim Senden der Anmeldeseite die Nummer der Führung mit schicken
    $('form').submit((event) => {
        let nr = $('#ftermin').find(':selected');
        console.log('nr: ', nr[0].value);
        $('#fid').val(nr[0].value);
    });


    // zum Testen die Anmelde-Seite automatisch ausfüllen
    $('#autofillbutton').click(() => {
        let rand = Math.floor(Math.random() * 100);
        for (let f in dummyTln) {
            if (f=='fid') {
                continue;
            }
            let x = dummyTln[f].toString();
            aktualTln[f] = x.replace("{z}",rand);
            $('#'+f).val(x.replace("{z}",rand));
        }
    });


    // Aus dem rohen Führungsdatum von der Datenbank ein besser
    // leserliches Format erzeugen
    // Params:
    //      w -> Wocjentag
    //      d -> Datum in DBase-Format
    //      t -> Uhrzeit
    // Return
    //      neu formatierter Datums-String
    const bauDate = (w,d,t) => {
        let dd = d.replace(/^(\d{4})(\d{2})(\d{2})$/, '$3.$2.$1',);
        return w.substr(0,2) + ', ' + dd + ' ' + t;
    }


    // Aus der Datenbank die nächsten 'n' Führungsdaten holen und
    // in den <option>-Tags anzeigen.
    // Zusätzlich für jeden Tag zählen, wieviel schon angemeldet sind.
    // Sind es >= 10, dass diese <option> als "disbaled" markieren.
    // Die Anzahl der noch freien Plätze mit anzeigen
    async function buildfuehrungdates(n) {
        const dates = await fetchFromDbase({cmd:'GET_DATES',anzahl:n, fid:0});

        str = "";
        for (let d of dates) {
            const count = await fetchFromDbase({cmd: 'GET_COUNTS', fid: d.fid});
            str += `<option ${count >= maxPersonen ? "disabled" : ""} ` +
            `value=${d.fid}> ${bauDate(d.weekday, d.date, d.time)} &nbsp;&nbsp;Frei: ${maxPersonen - count}</>`;
        }
        $('#fid').append(str);
    }


    // Mit der fid das Führungsdatum aus der DB holen und in leserliche
    // Form umsetzen
    // Params:
    //      fid ->  ID des Eintrages in der DB
    // Return
    //      String mit dem Führungsdatum
    const getfdateformatted = async (fid) => {
        const nxd = await fetchFromDbase({cmd: 'GET_DATES', anzahl: 1, fid: fid});
        let newdate = bauDate(nxd[0].weekday, nxd[0].date, nxd[0].time);
        return newdate.replace(/(\d+) Uhr/, "um $1 Uhr");
    }

    // Infomail über die Anmeldung bzw. Stornierung an rexfue@gmail.com senden
    // Parameters:
    //      storno  ->  true: Stornierung, fals: Anmeldung
    const sendInfoMail = async(storno) => {
        const fdatum = await getfdateformatted(aktualTln.fid);
        const subj = storno ? "Stornierung einer Stern-Führung" : "Neue Anmeldung zu einer Stern-Führung";
        const ret = await putToDbase({
            cmd: 'SEND_INFO_MAIL',
            to: 'rexfue@gmail.com',
            subject: subj,
            body: '<html>' +
                '<body><table>' +
                '<tr><td>Name, Vorname</td><td style="text-align: right;">' + aktualTln.name + ', ' + aktualTln.vorname +  '</td></tr>' +
                '<tr><td>Strasse</td><td style="text-align: right;">' + aktualTln.strasse  +  '</td></tr>' +
                '<tr><td>Ort</td><td style="text-align: right;">' + aktualTln.plz + ', ' + aktualTln.stadt +  '</td></tr>' +
                '<tr><td>Telefon</td><td style="text-align: right;">' + aktualTln.telefon +  '</td></tr>' +
                '<tr><td>E-mail</td><td style="text-align: right;">' + aktualTln.email +  '</td></tr>' +
                '<tr><td>Termin</td><td style="text-align: right;">' + fdatum +  '</td></tr>' +
                '<tr><td>Personen</td><td style="text-align: right;">' + aktualTln.anzahl +  '</td></tr>' +
                '<tr><td>Bemerkungen</td><td class="fr">' + aktualTln.remarks +  '</td></tr>' +
                '</table></body></html>'
        });
    }


    // Bestätigungsmail an den Anmeldeneden senden
    // Params:
    //      storno  ->  true: Stornierung, fals: Anmeldung
    const sendConfirmation = async (storno) => {
        const fdatum = await getfdateformatted(aktualTln.fid);
        let body = "Sehr geehrte Dame, sehr geehrter Herr, \r\n\r\nhiermit bestätigen wir Ihre "
        body += storno ? "Stornierung der " : "";
        body += "Anmeldung zu der Führung auf der Sternwarte Welzheim am\r\n\r\n" +
            `${fdatum} für ${aktualTln.name} ${aktualTln.vorname} mit ${aktualTln.anzahl} ${aktualTln.anzahl==1?"Person.":"Personen."}` +
            "\r\n\r\n";
        if (!storno) {
            body +=
                "Bitte bringen Sie diese Bestätigung als Ausdruck oder digital zur Führung mit. \r\n" +
                "Ohne diese Bestätigung erfolgt ausnahmslos k e i n Einlass.\r\n\r\n" +
                "Falls Sie den Führungstermin absagen wollen, verwenden Sie bitte folgenden Link \r\n";
            body += develop == "true" ?
                "http://localhost:8082/anmeldung.php?storno=" :
                "https://sternwarte-welzheim.de/anmeldung.php?storno=";
            body += md5(aktualTln.email + aktualTln.fid) + "\n\r";
            body += "Die Führung findet NUR bei sternklarem Himmel statt. Falls der Himmel bedeckt ist \r\n" +
                "und die Führung ausfällt, bitten wir Sie um eine neue Anmeldung.\r\n\r\n" +
                "Die Hygienevorschriften sind zu beachten: Die Teilnehmer/-innen müssen Gesichtsmasken \r\n" +
                "tragen und den vorgeschriebenen Abstand halten. " +
                "Nicht teilnehmen dürfen Personen, \r\ndie in den letzten vierzehn Tagen Kontakt " +
                "mit einem Coronavirus-Infizierten \r\nhatten oder Infektionssymptome zeigen.\r\n\r\n";
        }
        body += "Mit freundlichen Grüßen\r\n\r\n" +
        "Beobachterteam der Sternwarte Welzheim\r\n\r\n" +
        "www.sternwarte-welzheim.de"
        const ret = await putToDbase({
            cmd: 'SEND_MAIL',
            to: aktualTln.email,
            subject: storno ?
                "Stornierung Ihrer Anmeldung zu einer Führung auf der Sternwarte Welzheim" :
                "Anmeldung zu einer Führung auf der Sternwarte Welzheim",
            body: body,
        });
        console.log("hier wird die Email gesendet");
        sendInfoMail(storno);
    }


    // MD5-Hash ausrechnen
    const md5 = (value) => {
            return CryptoJS.MD5(value).toString();
        }


    // Den neuen Teilnehmer in die DB eintragen
    const insertEntry = async () => {
        let ret = await putToDbase({cmd: 'INSERT_TLN', data: aktualTln})
        sendConfirmation(false);
    }


    //  Den Teilnehmer mit der ID id aus der DB löschen
    const deleteEntry = async (id) => {
        let ret = await putToDbase({cmd: 'DELETE_TLN', id:id});
        return ret;
    }


    // Den Teilnehmer mit der ID id mit den neuen Daten versorgen
    const updateEntry = async (id) => {
        let ret = await putToDbase({cmd: 'UPDATE_TLN', data: aktualTln, id: id })
        sendConfirmation(false);
    }


    // Dialogbox für 'doppelt eingetragen'
    $("#dialogdoppelt").dialog({
        dialogClass: 'no-close',
        autoOpen: false,
        closeOnEscape: false,
        width: 700,
        modal: true,
        position: 'center',
        title: 'Doppelter Eintrag',
        open: () => {
            showdoppelText();
        },
        buttons: [
            {
                text: 'Auswahl übernehmen',
                click: async function() {
                    let gewaehlt = [];
                    $.each($("input[name='dopp']:checked"), function() {
                        gewaehlt.push($(this).val());
                    });
                    let tln = $("#dialogdoppelt").data('fids').otln;
                    if (gewaehlt.length === 1) {
                        if (gewaehlt[0] == "new") {
                            deleteEntry($("#dialogdoppelt").data('fids').otln.id);
                            insertEntry();
                            tln = $("#dialogdoppelt").data('fids').ntln;
                        }
                    } else {
                        insertEntry();
                        tln = $("#dialogdoppelt").data('fids').ntln;
                    }
                    $(this).dialog('close');
                    let meld = await afterDialogtext(tln);
                    $('#mainContent').html(meld);
                    $('#mainContent').css('height','430px');
                }
            }
        ]
    }).prev(".ui-dialog-titlebar").css("background","red");


    // Der Eintrag wird jetzt doppelt: dieses melden in einer
    // kleinen Dialog-Box
    function showDoppelt(oldone, newone) {
        $('#dialogdoppelt').data('fids', {otln: oldone, ntln: newone}).dialog('open');

    }


    // Text für doppelten Eintrag anzeigen
    async function showdoppelText() {
        const ofdate = await fetchFromDbase({
            cmd: 'GET_ONE_DATE',
            fid: $("#dialogdoppelt").data('fids').otln.fid
        });
        const nfdate = await fetchFromDbase({
            cmd: 'GET_ONE_DATE',
            fid: $("#dialogdoppelt").data('fids').ntln.fid
        });
        $('#dialogdoppelttext').html('Sie haben sich doppelt eingetragen.<br />' +
            'Wenn das so gewollt ist, dann kreuzen Sie bitte unten beide Führungen an,<br />' +
            'andernfalls nur diejenige, an der Sie wirklich teilnehmen wollen.<br /> <br />' +
            '<input type="checkbox" name="dopp" value="new" checked style="margin-right:10px;">' +
            bauDate(nfdate.wtag, nfdate.datum, nfdate.uhrzeit) + '<br />' +
            '<input type="checkbox" value="old" name="dopp" style="margin-right:10px;">' +
            bauDate(ofdate.wtag, ofdate.datum, ofdate.uhrzeit) + '<br />');
    }

    const errnum = {'no':1, 'error':2, 'double':3};


    // Alle Einträge auf Plausibilität prüfen
    // Return:
    //      Object mit:
    //          error: 'true', 'false'
    //          action: 'store', 'exit', 'none'
    async function checkPlausibilität() {
        let error = false;
        // Zuerst prüfen, ob auch alle notwendigen Felder ausgefüllt sind
        for (let feld in aktualTln) {
            aktualTln[feld] = $('#' + feld).val();          // Feld des actualTln auf dem Wert setzen
            if (!mandatory[feld]) {
                continue;
            }
            if (aktualTln[feld]  == "") {             // Falls das Feld leer ist, den Rahmen
                $('#' + feld).css('border-color', 'red'); // rot machen und das
                error = true;                               // errorfralg setzen
            }
        }
        if (error) {                                        // wenn Error, dieses melden
            errtext = "Bitte korrigieren Sie die fehlenden Einträge in den rot umrandeten Feldern";
            return errnum.error;                            // und raus
        }
        // Als Nächstes die PLZ prüfen: Das müssen 5 Ziffern sein
        const plz = $('#plz').val();
        let re = RegExp(/^[0-9]{5}$/);
        if(!re.test(plz)) {
            $('#plz').css('border-color', 'red');
            errtext = "Bitte geben Sie bei der Postleitzahl mindestens fünf Ziffern und keine Buchstaben ein";
            return errnum.error;                            // und raus
        }
        // Die Email prüfen
        re = RegExp(/^[a-z0-9]+([-_\.]?[a-z0-9])+@[a-z0-9]+([-_\.]?[a-z0-9])+\.[a-z]{2,4}/);
        let mail = $('#email').val().toLowerCase();
        if(!re.test(mail)) {
            $('#email').css('border-color', 'red');
            errtext = "Bitte geben Sie eine gültige E-Mail-Adresse ein";
            return errnum.error;                            // und raus
        }
        // Nun noch doppelte Einträge checken
        // dazu prüfen, ob die email_Adresse in den Teilnehmern schon enthalten ist
        const aktMail = aktualTln.email;
        let allParticipants = await fetchAlleTln();
        const find = allParticipants.findIndex((f) => f.email === aktMail);
        if (find == -1) {
            insertEntry();
            return errnum.no;
        }
        let oldTln = allParticipants[find];
        // Email enthalten. Ist der Führungstag identisch? Wenn ja, dann einfach die neuen
        // Werte eintragen (also überschreiben)
        if (aktualTln.fid === oldTln.fid) {
            updateEntry(oldTln.id);
            return errnum.no;
        } else {
            // Hier nun 'Doppelt' melden
            showDoppelt(oldTln, aktualTln);
            return errnum.double;
        }
        return errnum.no;
    }


    // Text für den Dialog der Anmeldung
    const afterDialogtext = async(tln) => {
        let fdate = await getfdateformatted(tln.fid);
        return '<p>Vielen Dank für Ihre Anmeldung. <br /><br />' +
        'Wir freuen uns über Ihren Besuch auf der Sternwarte Welzheim am<br /> ' +
        '<div id="antwort_fdatum" style="text-align:center;">' +
        `${fdate} mit ${tln.anzahl} ${tln.anzahl == 1 ? "Person" : "Personen"}` +
        '</div> <br />' +
        'Wir haben Ihnen die Anmelde-Bestätigung per Email zugesandt.</p>' +
        '<p><a class="button" href="/index.php">Zurück</a></p>';
    }


    // Formular ist ausgefüllt - der Anmelde-Knopf wurde gerdückt.
    // Alle Eingaben in den aktuelTln eintragen und dann
    // eine Plausibilitäts-Prüfung durchführen und wenn Alles
    // OK ist, die Einträge in die Datenbank schreiben
    $('input[name="submit"]').click(async () => {
        $('#errordiv').css('visibility','hidden');          // erst mal die evtl. vorhandenen Fehlermeldung
        for ( let f in aktualTln) {                         // löschen und alle Rahmen
            $('#'+f).css('border-color','black');           // wieder schwarz machen
        }
        let nr = $('#fid').find(':selected');
        aktualTln.fid =  nr[0].value;                       // selektiertes Führungsdatum merken
        const ret = await checkPlausibilität();
        if (ret === errnum.error) {
            $('#errordiv').html(errtext);
            $('#errordiv').css('visibility', 'visible');
        } else if (ret === errnum.no) {
            let meld = await afterDialogtext(aktualTln);
            $('#mainContent').html(meld);
            $('#mainContent').css('height','430px');
        }
    });


    // Storno
    // Der Link für die Stornierung wurde aufgerufen:
    // Zuerst die email-Adresse suchen (mit Hilfe des übergebenen md5-hash),
    // dann die Stornierung anzeigen und dann noch eine Bestätigung senden
    const doStorno = async(md5hash) => {
        let emails = await fetchFromDbase({cmd:'GET_ALL_EMAILS'});
        for (let em of emails) {
            if(md5((em.email+em.fid)) == md5hash) {
                // komplette Info dieses teilnehmers holen
                let teilnehmer = await fetchFromDbase({cmd: 'GET_TEILN', id: em.id, isid: true});
                aktualTln = Object.assign({}, teilnehmer[0]);
                // Löschen des Eintrages
                let ret = putToDbase({cmd:'DELETE_TLN', id: em.id});
                // Meldung anzeigen
                let fdate = await getfdateformatted(em.fid);
                let meld = '<p><h1 style="text-align:center">Stornierung</h1><br />' +
                    'Ihre Anmeldung für die Führung auf der Sternwarte Welzheim am<br /><br />' +
                    '<div id="antwort_fdatum" style="text-align:center;">' +
                    `${fdate} mit ${aktualTln.anzahl} ${aktualTln.anzahl == 1 ? "Person" : "Personen"}` +
                    '</div> <br />' +
                    'wurde storniert.<br /><br /> Wir haben Ihnen die Stornierungs-Bestätigung per Email zugesandt.</p>' +
                    '<p><a class="button" href="/index.php">Zurück</a></p>';
                $('#mainContent').html(meld);
                $('#mainContent').css('height','430px');
                sendConfirmation(true);
                return;
            }
        }
    }

    // Alle eingetragenen Teilnehmer ab 'morgen' in das globale Array einlesen
    const fetchAlleTln = async () => {
        const nxtDate = await fetchFromDbase({cmd: 'GET_DATES', anzahl: 1, fid:0});
        return await fetchFromDbase({cmd: 'GET_ALLTEILN', fid: nxtDate[0].fid});
    }


    async function main() {
        // Falls Storno angefordert, dann anzeigen
        if(md5Hash != "") {
            await doStorno(md5Hash);
            return;
        }
        // Alle eingetragenen Teilnehmer ab 'morgen' in das globale Array einlesen
        // die nächste 30 Führungsdaten anzeigen
        buildfuehrungdates(30);
    }

    main().catch(console.err);

});
