"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cast_de_nrw_schule_svws_core_abschluss_ge_ServiceBerechtigungMSAQ = exports.ServiceBerechtigungMSAQ = void 0;
const Service_1 = require("../../../core/Service");
const JavaString_1 = require("../../../java/lang/JavaString");
const GELeistungsdifferenzierteKursart_1 = require("../../../core/types/ge/GELeistungsdifferenzierteKursart");
const LogLevel_1 = require("../../../logger/LogLevel");
const NullPointerException_1 = require("../../../java/lang/NullPointerException");
const ServiceAbschlussMSA_1 = require("../../../core/abschluss/ge/ServiceAbschlussMSA");
const Arrays_1 = require("../../../java/util/Arrays");
const Abschluss_1 = require("../../../core/types/Abschluss");
const Vector_1 = require("../../../java/util/Vector");
const AbschlussManager_1 = require("../../../core/abschluss/AbschlussManager");
class ServiceBerechtigungMSAQ extends Service_1.Service {
    filterDefizite = { test: (f) => (f.note > 3) || ((GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note > 2)) };
    filterDefizite1NS = { test: (f) => ((!GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note === 4)) || ((GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note === 3)) };
    filterDefizite2NS = { test: (f) => ((!GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note === 5)) || ((GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note === 4)) };
    filterDefizitWP = { test: (f) => (f.note > 3) && JavaString_1.JavaString.equalsIgnoreCase("WP", f.kuerzel) };
    filterDefizitNichtWP = { test: (f) => (f.note > 3) || ((GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note > 2)) && !JavaString_1.JavaString.equalsIgnoreCase("WP", f.kuerzel) };
    filterFG1NichtAusgleichbar = { test: (f) => (f.note > 4) || ((GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note > 3)) };
    filterFG2NichtAusgleichbar = { test: (f) => (f.note > 5) || ((GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note > 3)) };
    filterAusgleiche = { test: (f) => !f.ausgleich && ((f.note < 2) || ((!GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(f.kursart)) && (f.note < 3))) };
    filterEKurse = { test: (f) => (GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.E.hat(f.kursart)) };
    constructor() {
        super();
    }
    /**
     * Führt die Abschlussberechnung (bzw. Berechtigungsberechnung) anhand der übergebenen
     * Abschlussfächer durch und gibt das Berechnungsergebnis zurück.
     *
     * @param input    die Abschlussfächer
     *
     * @return das Ergebnis der Abschlussberechnung
     */
    handle(input) {
        this.logger.logLn(LogLevel_1.LogLevel.INFO, "Prüfe MSA-Q:");
        this.logger.logLn(LogLevel_1.LogLevel.DEBUG, "============");
        if ((input.faecher === null) || (!AbschlussManager_1.AbschlussManager.pruefeHat4LeistungsdifferenzierteFaecher(input))) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, "______________________________");
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, " => Fehler: Es wurden nicht genügend leistungsdifferenzierte Fächer gefunden.");
            return AbschlussManager_1.AbschlussManager.getErgebnis(null, false);
        }
        if (!AbschlussManager_1.AbschlussManager.pruefeKuerzelDuplikate(input)) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, "______________________________");
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, " => Fehler: Es wurden Fächer mit dem gleichen Kürzel zur Abschlussprüfung übergeben. Dies ist nicht zulässig.");
            return AbschlussManager_1.AbschlussManager.getErgebnis(null, false);
        }
        let faecher = ServiceAbschlussMSA_1.ServiceAbschlussMSA.getFaechergruppen(input.faecher);
        if (!faecher.fg1.istVollstaendig(Arrays_1.Arrays.asList("D", "M", "E", "WP"))) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, "______________________________");
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, " => Fehler: Es wurden nicht alle nötigen Leistungen für die Fächergruppe 1 gefunden.");
            return AbschlussManager_1.AbschlussManager.getErgebnis(null, false);
        }
        if (faecher.fg2.isEmpty()) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, "______________________________");
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, " => Fehler: Keine Leistungen für die Fächergruppe 2 gefunden.");
            return AbschlussManager_1.AbschlussManager.getErgebnis(null, false);
        }
        let anzahlEKurse = faecher.getFaecherAnzahl(this.filterEKurse);
        if (anzahlEKurse < 3) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, "______________________________");
            this.logger.logLn(LogLevel_1.LogLevel.INFO, " => kein MSA-Q (FOR-Q) - nicht genügend E-Kurse belegt");
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
        }
        else if (anzahlEKurse > 3) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, " - Verbessern der E-Kurs-Noten für die Defizitberechnung, falls mehr als 3 E-Kurse vorhanden sind:");
            let tmpFaecher = faecher.fg2.getFaecher(this.filterEKurse);
            for (let f of tmpFaecher) {
                let note = f.note;
                let note_neu = (note === 1) ? 1 : note - 1;
                this.logger.logLn(LogLevel_1.LogLevel.DEBUG, "   " + f.kuerzel + ":(E)" + note + "->(G)" + note_neu);
                f.note = note_neu;
                f.kursart = GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.kuerzel;
            }
        }
        this.logger.logLn(LogLevel_1.LogLevel.DEBUG, " -> FG1: Fächer " + faecher.fg1.toString().valueOf());
        this.logger.logLn(LogLevel_1.LogLevel.DEBUG, " -> FG2: Fächer " + faecher.fg2.toString().valueOf());
        let abschlussergebnis = this.pruefeDefizite(faecher, "");
        if (abschlussergebnis.erworben) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, "______________________________");
            this.logger.logLn(LogLevel_1.LogLevel.INFO, " => MSA-Q (FOR-Q): APO-SI §43 (4)");
        }
        else if (AbschlussManager_1.AbschlussManager.hatNachpruefungsmoeglichkeit(abschlussergebnis)) {
            this.logger.logLn(LogLevel_1.LogLevel.INFO, " => kein MSA-Q (FOR-Q) - Nachprüfungsmöglichkeite(en) in " + AbschlussManager_1.AbschlussManager.getNPFaecherString(abschlussergebnis).valueOf());
        }
        else {
            this.logger.logLn(LogLevel_1.LogLevel.INFO, " => kein MSA-Q (FOR-Q) - KEINE Nachprüfungsmöglichkeiten!");
        }
        return abschlussergebnis;
    }
    /**
     * Prüft in Bezug auf Defizite, ob der Abschluss erworben wurde.
     *
     * @param faecher      die Asbchlussfächer nach Fächergruppen sortiert
     * @param log_indent   die Einrückung für das Logging
     *
     * @return das Ergebnis der Abschlussberechnung in Bezug die Defizitberechnung
     */
    pruefeDefizite(faecher, log_indent) {
        let fg1_defizite = faecher.fg1.getFaecher(this.filterDefizite);
        let fg2_defizite = faecher.fg2.getFaecher(this.filterDefizite);
        if (fg1_defizite.size() > 0)
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> FG1: Defizit" + (fg1_defizite.size() > 1 ? "e" : "") + ": " + faecher.fg1.getKuerzelListe(this.filterDefizite).valueOf());
        if (fg2_defizite.size() > 0)
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> FG2: Defizit" + (fg2_defizite.size() > 1 ? "e" : "") + ": " + faecher.fg2.getKuerzelListe(this.filterDefizite).valueOf());
        let nachpruefung_genutzt = false;
        let npFaecher = new Vector_1.Vector();
        let fg1_nicht_ausgleichbar = faecher.fg1.getFaecher(this.filterFG1NichtAusgleichbar);
        let fg2_nicht_ausgleichbar = faecher.fg2.getFaecher(this.filterFG2NichtAusgleichbar);
        if ((fg1_nicht_ausgleichbar.size() > 0) || (fg2_nicht_ausgleichbar.size() > 0)) {
            let str_faecher = faecher.getKuerzelListe(this.filterFG1NichtAusgleichbar, this.filterFG2NichtAusgleichbar);
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> Defizit(e) in " + str_faecher.valueOf() + " aufgrund zu hoher Abweichungen nicht ausgleichbar.");
            if ((fg1_nicht_ausgleichbar.size() === 0) && (fg2_nicht_ausgleichbar.size() === 1) && (GELeistungsdifferenzierteKursart_1.GELeistungsdifferenzierteKursart.G.hat(fg2_nicht_ausgleichbar.get(0).kursart)) && (fg2_nicht_ausgleichbar.get(0).note === 4)) {
                this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + "   -> Nachprüfung muss falls möglich in " + fg2_nicht_ausgleichbar.get(0).kuerzel + " stattfinden!");
                nachpruefung_genutzt = true;
                npFaecher.add(fg2_nicht_ausgleichbar.get(0));
            }
            else {
                return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
            }
        }
        let fg1_ausgleichsfaecher = faecher.fg1.getFaecher(this.filterAusgleiche);
        let wp_defizit = faecher.fg1.getFach(this.filterDefizitWP);
        if ((fg1_defizite.size() > 2) || ((fg1_defizite.size() === 2) && (wp_defizit === null))) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> zu viele Defizite in FG1");
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
        }
        else if ((fg1_defizite.size() === 2) && (wp_defizit !== null) && (fg1_ausgleichsfaecher.size() === 0)) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> zu viele Defizite in FG1 - kein Ausgleich möglich");
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
        }
        else if ((fg1_defizite.size() === 2) && (wp_defizit !== null) && (fg1_ausgleichsfaecher.size() > 0) && (!nachpruefung_genutzt)) {
            let defizitFach = faecher.fg1.getFach(this.filterDefizitNichtWP);
            if (defizitFach === null)
                throw new NullPointerException_1.NullPointerException();
            let ausgleichsFach = fg1_ausgleichsfaecher.get(0);
            defizitFach.ausgeglichen = true;
            ausgleichsFach.ausgleich = true;
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> Ausgleich von " + defizitFach.kuerzel + " durch " + ausgleichsFach.kuerzel);
            nachpruefung_genutzt = true;
            npFaecher.add(wp_defizit);
            let abschlussergebnis = this.pruefeFG2(faecher, log_indent, npFaecher, nachpruefung_genutzt);
            if (abschlussergebnis.erworben) {
                return AbschlussManager_1.AbschlussManager.getErgebnisNachpruefung(Abschluss_1.Abschluss.MSA_Q, AbschlussManager_1.AbschlussManager.getKuerzel(npFaecher));
            }
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
        }
        if ((fg1_defizite.size() === 1) && (wp_defizit === null) && (fg1_ausgleichsfaecher.size() === 0)) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> kein Defizit-Ausgleich in FG1");
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
        }
        if ((fg1_defizite.size() === 1) && (wp_defizit === null)) {
            let defizitFach = faecher.fg1.getFach(this.filterDefizitNichtWP);
            if (defizitFach === null)
                throw new NullPointerException_1.NullPointerException();
            let ausgleichsFach = fg1_ausgleichsfaecher.get(0);
            defizitFach.ausgeglichen = true;
            ausgleichsFach.ausgleich = true;
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> Ausgleich von " + defizitFach.kuerzel + " durch " + ausgleichsFach.kuerzel);
        }
        if ((fg1_defizite.size() === 1) && (wp_defizit !== null)) {
            if ((fg1_ausgleichsfaecher.size() > 0)) {
                let defizitFach = wp_defizit;
                let ausgleichsFach = fg1_ausgleichsfaecher.get(0);
                defizitFach.ausgeglichen = true;
                ausgleichsFach.ausgleich = true;
                this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> Prüfe FG2 mit der Option Ausgleich von " + defizitFach.kuerzel + " durch " + ausgleichsFach.kuerzel);
                let abschlussergebnis = this.pruefeFG2(faecher, log_indent.valueOf() + "  ", npFaecher, nachpruefung_genutzt);
                if (abschlussergebnis.erworben)
                    return abschlussergebnis;
                defizitFach.ausgeglichen = false;
                ausgleichsFach.ausgleich = false;
            }
            if (nachpruefung_genutzt) {
                this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> Eine Nachprüfung im WP-Fach und in dem leistungsdifferenzierten Fach der FG2 ist nicht gleichzeitig möglich.");
                return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
            }
            wp_defizit.ausgleich = true;
            wp_defizit.note--;
            let abschlussergebnis = this.pruefeFG2(faecher, log_indent, npFaecher, true);
            wp_defizit.note++;
            wp_defizit.ausgleich = false;
            if (abschlussergebnis.erworben) {
                nachpruefung_genutzt = true;
                npFaecher.add(wp_defizit);
            }
            return AbschlussManager_1.AbschlussManager.getErgebnisNachpruefung(Abschluss_1.Abschluss.MSA_Q, AbschlussManager_1.AbschlussManager.getKuerzel(npFaecher));
        }
        let log_fg2_indent = log_indent;
        if (fg2_nicht_ausgleichbar.size() === 1) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> Prüfe FG2 mit Nachprüfung in " + fg2_nicht_ausgleichbar.get(0).kuerzel);
            log_fg2_indent += "  ";
        }
        let abschlussergebnis = this.pruefeFG2(faecher, log_fg2_indent, npFaecher, nachpruefung_genutzt);
        if (((fg2_nicht_ausgleichbar.size() === 1) && abschlussergebnis.erworben) || ((!abschlussergebnis.erworben) && (AbschlussManager_1.AbschlussManager.hatNachpruefungsmoeglichkeit(abschlussergebnis)))) {
            return AbschlussManager_1.AbschlussManager.getErgebnisNachpruefung(Abschluss_1.Abschluss.MSA_Q, AbschlussManager_1.AbschlussManager.getKuerzel(npFaecher));
        }
        return abschlussergebnis;
    }
    /**
     * Führt eine Detailprüfung in der Fächergruppe 2 durch. Diese Methode wird ggf. mehrfach - auch rekursiv - aufgerufen.
     *
     * @param faecher                die Abschlussfächer nach Fächergruppen sortiert
     * @param log_indent             die Einrückung für das Logging
     * @param npFaecher              die Liste der Nachprüfungsfächer, die bisher schon feststehen
     * @param nachpruefung_genutzt   gibt an, ob die Nachprüfungsmöglichkeit bereits eingesetzt werden musste
     *
     * @return das Ergebnis der Abschlussberechnung in Bezug auf den Stand dieser Detailprüfung
     */
    pruefeFG2(faecher, log_indent, npFaecher, nachpruefung_genutzt) {
        let ges_ausgleichsfaecher = faecher.getFaecher(this.filterAusgleiche);
        let fg2_defizite_1NS = faecher.fg2.getFaecher(this.filterDefizite1NS);
        let fg2_defizite_2NS = faecher.fg2.getFaecher(this.filterDefizite2NS);
        let fg2_defizit_anzahl = fg2_defizite_1NS.size() + fg2_defizite_2NS.size();
        if (fg2_defizit_anzahl === 0) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> keine Defizite in FG2");
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, true);
        }
        if ((fg2_defizite_2NS.size() > 2) || (fg2_defizit_anzahl > (nachpruefung_genutzt ? 3 : 4))) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> zu viele Defizite in FG2 - mit Ausgleich und Nachprüfung kein Abschluss möglich");
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
        }
        if (ges_ausgleichsfaecher.size() < fg2_defizit_anzahl - (nachpruefung_genutzt ? 0 : 1)) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> zu viele Defizite in FG2 - nicht genügend Ausgleichsfächer vorhanden");
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, false);
        }
        if (fg2_defizite_2NS.size() === 2) {
            for (let defizitFach of fg2_defizite_2NS) {
                defizitFach.ausgeglichen = true;
                defizitFach.ausgleich = true;
                defizitFach.note--;
                this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> Prüfe erneut mit Nachprüfung in " + defizitFach.kuerzel);
                let abschlussergebnis = this.pruefeFG2(faecher, log_indent.valueOf() + "  ", npFaecher, true);
                this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + "   -> Nachprüfung in " + defizitFach.kuerzel + (abschlussergebnis.erworben ? " möglich" : " nicht möglich"));
                if (abschlussergebnis.erworben)
                    npFaecher.add(defizitFach);
                defizitFach.ausgeglichen = true;
                defizitFach.ausgleich = true;
                defizitFach.note++;
            }
            return AbschlussManager_1.AbschlussManager.getErgebnisNachpruefung(Abschluss_1.Abschluss.MSA_Q, AbschlussManager_1.AbschlussManager.getKuerzel(npFaecher));
        }
        if (ges_ausgleichsfaecher.size() >= fg2_defizit_anzahl) {
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> genug Ausgleichsfächer vorhanden." + (nachpruefung_genutzt ? "" : " Nachprüfung nicht nötig."));
            return AbschlussManager_1.AbschlussManager.getErgebnis(Abschluss_1.Abschluss.MSA_Q, true);
        }
        for (let defizitFach of fg2_defizite_1NS) {
            defizitFach.ausgeglichen = true;
            defizitFach.ausgleich = true;
            defizitFach.note--;
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + " -> Prüfe erneut mit Nachprüfung in " + defizitFach.kuerzel);
            let abschlussergebnis = this.pruefeFG2(faecher, log_indent.valueOf() + "  ", npFaecher, true);
            this.logger.logLn(LogLevel_1.LogLevel.DEBUG, log_indent.valueOf() + "   -> Nachprüfung in " + defizitFach.kuerzel + (abschlussergebnis.erworben ? " möglich" : " nicht möglich"));
            if (abschlussergebnis.erworben)
                npFaecher.add(defizitFach);
            defizitFach.ausgeglichen = true;
            defizitFach.ausgleich = true;
            defizitFach.note++;
        }
        return AbschlussManager_1.AbschlussManager.getErgebnisNachpruefung(Abschluss_1.Abschluss.MSA_Q, AbschlussManager_1.AbschlussManager.getKuerzel(npFaecher));
    }
    isTranspiledInstanceOf(name) {
        return ['de.nrw.schule.svws.core.Service', 'de.nrw.schule.svws.core.abschluss.ge.ServiceBerechtigungMSAQ'].includes(name);
    }
}
exports.ServiceBerechtigungMSAQ = ServiceBerechtigungMSAQ;
function cast_de_nrw_schule_svws_core_abschluss_ge_ServiceBerechtigungMSAQ(obj) {
    return obj;
}
exports.cast_de_nrw_schule_svws_core_abschluss_ge_ServiceBerechtigungMSAQ = cast_de_nrw_schule_svws_core_abschluss_ge_ServiceBerechtigungMSAQ;
//# sourceMappingURL=ServiceBerechtigungMSAQ.js.map