"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynSchueler = exports.KursblockungDynSchueler = void 0;
const JavaObject_1 = require("../../java/lang/JavaObject");
const KursblockungStatic_1 = require("../../core/kursblockung/KursblockungStatic");
const KursblockungMatrix_1 = require("../../core/kursblockung/KursblockungMatrix");
const System_1 = require("../../java/lang/System");
const KursblockungOutputFachwahlZuKurs_1 = require("../../core/data/kursblockung/KursblockungOutputFachwahlZuKurs");
class KursblockungDynSchueler extends JavaObject_1.JavaObject {
    representation;
    fachartArr;
    fachartZuGUI;
    fachartZuKurs;
    fachartZuKursSaveS;
    fachartZuKursSaveK;
    statistik;
    nichtwahlen = 0;
    schieneBelegt;
    static dummy = new KursblockungMatrix_1.KursblockungMatrix(0, 0);
    matrix;
    /**
     * Im Konstruktor wird {@code pSchueler} in ein Objekt dieser Klasse
     * umgewandelt.
     *
     * @param pStatistik      Referenz um die Nichtwahlen mitzuteilen.
     * @param pSchueler       Die Schüler-Daten von der GUI/DB.
     * @param pSchienenAnzahl Wir benötigt, um {@link #schieneBelegt} zu
     *                        initialisieren.
     */
    constructor(pSchueler, pStatistik, pSchienenAnzahl) {
        super();
        this.representation = pSchueler.representation;
        this.statistik = pStatistik;
        this.fachartArr = Array(0).fill(null);
        this.fachartZuGUI = Array(0).fill(0);
        this.fachartZuKurs = Array(0).fill(null);
        this.fachartZuKursSaveS = Array(0).fill(null);
        this.fachartZuKursSaveK = Array(0).fill(null);
        this.nichtwahlen = 0;
        this.schieneBelegt = Array(pSchienenAnzahl).fill(false);
        this.matrix = KursblockungDynSchueler.dummy;
    }
    toString() {
        return this.representation;
    }
    /**
     * Eine String-Darstellung des Schülers. Beinhaltet meistens den Vornamen, den
     * Nachnamen, das Geburtsdatum und das Geschlecht.
     *
     * @return Eine String-Darstellung des Schülers.
     */
    gibRepresentation() {
        return this.representation;
    }
    /**
     * Liefert die aktuelle Anzahl an Nichtwahlen.
     *
     * @return Die aktuelle Anzahl an Nichtwahlen.
     */
    gibNichtwahlen() {
        return this.nichtwahlen;
    }
    /**
     * Liefert ein Array aller Facherten (= Fachwahlen) des Schülers.
     *
     * @return Ein Array aller Facherten (= Fachwahlen) des Schülers.
     */
    gibFacharten() {
        return this.fachartArr;
    }
    /**
     * Setzt alle Facharten (=Fachwahlen) des Schülers.
     *
     * @param pFacharten Die Facharten des Schülers.
     * @param pIDs       Die zur Fachwahl zugehörige ID der GUI bzw. Datenbank.
     */
    aktionSetzeFachartenUndIDs(pFacharten, pIDs) {
        let nFacharten = pFacharten.length;
        this.fachartArr = pFacharten;
        this.fachartZuGUI = pIDs;
        this.fachartZuKurs = Array(nFacharten).fill(null);
        this.fachartZuKursSaveS = Array(nFacharten).fill(null);
        this.fachartZuKursSaveK = Array(nFacharten).fill(null);
        this.statistik.aktionNichtwahlenVeraendern(nFacharten);
        this.nichtwahlen = nFacharten;
        for (let i = 1; i < nFacharten; i++) {
            for (let j = i; j >= 1; j--) {
                let anzL = this.fachartArr[j - 1].gibKurseMax();
                let anzR = this.fachartArr[j].gibKurseMax();
                if (anzL > anzR) {
                    let fL = this.fachartArr[j - 1];
                    let fR = this.fachartArr[j];
                    let valL = this.fachartZuGUI[j - 1];
                    let valR = this.fachartZuGUI[j];
                    this.fachartArr[j - 1] = fR;
                    this.fachartArr[j] = fL;
                    this.fachartZuGUI[j - 1] = valR;
                    this.fachartZuGUI[j] = valL;
                }
            }
        }
        this.matrix = new KursblockungMatrix_1.KursblockungMatrix(nFacharten, this.schieneBelegt.length);
    }
    /**
     * Speichert die aktuell belegten Kurse im Zustand S.
     */
    aktionZustandSpeichernS() {
        System_1.System.arraycopy(this.fachartZuKurs, 0, this.fachartZuKursSaveS, 0, this.fachartZuKurs.length);
    }
    /**
     * Speichert die aktuell belegten Kurse im Zustand K.
     */
    aktionZustandSpeichernK() {
        System_1.System.arraycopy(this.fachartZuKurs, 0, this.fachartZuKursSaveK, 0, this.fachartZuKurs.length);
    }
    /**
     * Entfernt zunächst den Schüler aus seinen aktuellen Kursen und setzt ihn dann
     * in die Kurse, die zuvor im Zustand S gespeichert wurden.
     */
    aktionZustandLadenS() {
        this.aktionWaehleKurse(this.fachartZuKursSaveS);
    }
    /**
     * Entfernt zunächst den Schüler aus seinen aktuellen Kursen und setzt ihn dann
     * in die Kurse, die zuvor im Zustand K gespeichert wurden.
     */
    aktionZustandLadenK() {
        this.aktionWaehleKurse(this.fachartZuKursSaveK);
    }
    aktionWaehleKurse(wahl) {
        this.aktionKurseAlleEntfernen();
        for (let i = 0; i < this.fachartZuKurs.length; i++) {
            let kurs = wahl[i];
            if (kurs !== null) {
                this.aktionKursHinzufuegen(i, kurs);
            }
        }
    }
    /**
     * Entfernt den Schüler aus seinen aktuell zugeordneten Kursen.
     */
    aktionKurseAlleEntfernen() {
        for (let i = 0; i < this.fachartArr.length; i++) {
            let kurs = this.fachartZuKurs[i];
            if (kurs !== null) {
                this.aktionKursEntfernen(i, kurs);
            }
        }
    }
    /**
     * Geht die Facharten durch (Facharten mit einer kleineren Kursanzahl zuerst)
     * und geht dann pro Fachart alle Kurse durch (Kurse mit kleinerer Schüleranzahl
     * zuerst). Falls der Kurs wählbar ist, wird der Schüler hinzugefügt und es geht
     * weiter mit der nächsten Fachart. Ein Kurs ist wählbar, wenn nicht bereits ein
     * Kurs zugeordnet wurde und die Schienen in den der Kurs sind frei sind.<br>
     *
     * Falls der Paramter {@code pNurMultikurse} TRUE ist, dann werden nur
     * Multikurse verteilt.
     *
     * @param pNurMultikurse Falls TRUE ist, dann werden nur Multikurse verteilt.
     */
    aktionKurseZufaelligVerteilen(pNurMultikurse) {
        let perm = KursblockungStatic_1.KursblockungStatic.gibPermutation(this.fachartArr.length);
        for (let p = 0; p < this.fachartArr.length; p++) {
            let i = perm[p];
            if (this.fachartZuKurs[i] !== null) {
                continue;
            }
            let fachart = this.fachartArr[i];
            if (pNurMultikurse) {
                if (!fachart.gibHatMultikurs()) {
                    continue;
                }
            }
            let kurse = fachart.gibKurse();
            let perm2 = KursblockungStatic_1.KursblockungStatic.gibPermutation(kurse.length);
            for (let p2 = 0; p2 < perm2.length; p2++) {
                let i2 = p2;
                let kurs = kurse[i2];
                let waehlbar = true;
                for (let nr of kurs.gibSchienenLage()) {
                    if (this.schieneBelegt[nr]) {
                        waehlbar = false;
                    }
                }
                if (waehlbar) {
                    this.aktionKursHinzufuegen(i, kurs);
                    break;
                }
            }
        }
    }
    /**
     * Verteilt alle Kurse die über genau 1 Schiene gehen mit Hilfe eines Matching
     * Algorithmus.
     */
    aktionKurseMitBipartiteMatchingVerteilen() {
        let data = this.matrix.getMatrix();
        for (let r = 0; r < this.fachartArr.length; r++) {
            for (let c = 0; c < this.schieneBelegt.length; c++) {
                data[r][c] = 0;
            }
            if (this.fachartZuKurs[r] !== null) {
                continue;
            }
            if (this.fachartArr[r].gibHatMultikurs()) {
                continue;
            }
            for (let kurs of this.fachartArr[r].gibKurse()) {
                for (let nr of kurs.gibSchienenLage()) {
                    if (!this.schieneBelegt[nr]) {
                        data[r][nr] = 1;
                    }
                }
            }
        }
        let r2c = this.matrix.gibMaximalesBipartitesMatching(true);
        for (let r = 0; r < this.fachartArr.length; r++) {
            if (this.fachartZuKurs[r] !== null) {
                continue;
            }
            let c = r2c[r];
            if (c === -1) {
                continue;
            }
            let kursGefunden = null;
            for (let kurs of this.fachartArr[r].gibKurse()) {
                for (let nr of kurs.gibSchienenLage()) {
                    if ((nr === c) && (kursGefunden === null)) {
                        kursGefunden = kurs;
                    }
                }
            }
            if (kursGefunden !== null)
                this.aktionKursHinzufuegen(r, kursGefunden);
        }
    }
    /**
     * Erzeugt pro Fachwahl ein Objekt des Typs
     * {@link KursblockungOutputFachwahlZuKurs} und fügt es dem Vector
     * {@code vFachwahlZuKurs} hinzu. Die GUI kann daraus die
     * Schüler-Zu-Kurs-Zuordnungen rekonstruiern.
     *
     * @param vFachwahlZuKurs Fügt diesem Vector pro Fachwahl ein Objekt des Typs
     *                        {@link KursblockungOutputFachwahlZuKurs} hinzu.
     */
    aktionOutputsErzeugen(vFachwahlZuKurs) {
        for (let i = 0; i < this.fachartArr.length; i++) {
            let fachwahlZuKurs = new KursblockungOutputFachwahlZuKurs_1.KursblockungOutputFachwahlZuKurs();
            fachwahlZuKurs.fachwahl = this.fachartZuGUI[i];
            let tmpKurs = this.fachartZuKurs[i];
            fachwahlZuKurs.kurs = (tmpKurs === null) ? -1 : tmpKurs.gibID();
            vFachwahlZuKurs.add(fachwahlZuKurs);
        }
    }
    /**
     * Liefert TRUE, falls der Schüler mindestens einen Multikurs hat. Ein Multikurs
     * ist ein Kurs, der über mehr als eine Schiene geht.
     *
     * @return TRUE, falls der Schüler mindestens einen Multikurs hat.
     */
    gibHatMultikurs() {
        for (let fachart of this.fachartArr) {
            if (fachart.gibHatMultikurs()) {
                return true;
            }
        }
        return false;
    }
    aktionKursHinzufuegen(fachartIndex, kurs) {
        kurs.aktionSchuelerHinzufügen();
        this.statistik.aktionNichtwahlenVeraendern(-1);
        this.nichtwahlen--;
        for (let nr of kurs.gibSchienenLage()) {
            if (this.schieneBelegt[nr]) {
                console.log(JSON.stringify("FEHLER: Schienen-Doppelbelegung! " + this.representation.valueOf()));
            }
            this.schieneBelegt[nr] = true;
        }
        this.fachartZuKurs[fachartIndex] = kurs;
    }
    aktionKursEntfernen(fachartIndex, kurs) {
        kurs.aktionSchuelerEntfernen();
        this.statistik.aktionNichtwahlenVeraendern(+1);
        this.nichtwahlen++;
        for (let nr of kurs.gibSchienenLage()) {
            if (!this.schieneBelegt[nr]) {
                console.log(JSON.stringify("FEHLER: Kurs ist gar nicht in Schiene ! " + this.representation.valueOf()));
            }
            this.schieneBelegt[nr] = false;
        }
        this.fachartZuKurs[fachartIndex] = null;
    }
    isTranspiledInstanceOf(name) {
        return ['de.nrw.schule.svws.core.kursblockung.KursblockungDynSchueler'].includes(name);
    }
}
exports.KursblockungDynSchueler = KursblockungDynSchueler;
function cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynSchueler(obj) {
    return obj;
}
exports.cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynSchueler = cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynSchueler;
//# sourceMappingURL=KursblockungDynSchueler.js.map