import { JavaObject, cast_java_lang_Object } from '../../../java/lang/JavaObject';
import { JavaInteger, cast_java_lang_Integer } from '../../../java/lang/JavaInteger';
import { HashMap, cast_java_util_HashMap } from '../../../java/util/HashMap';
import { Schulgliederung, cast_de_nrw_schule_svws_core_types_statkue_Schulgliederung } from '../../../core/types/statkue/Schulgliederung';
import { List, cast_java_util_List } from '../../../java/util/List';
import { JavaString, cast_java_lang_String } from '../../../java/lang/JavaString';
import { Vector, cast_java_util_Vector } from '../../../java/util/Vector';

export class Schulform extends JavaObject {

	/** the name of the enumeration value */
	private readonly __name : String;

	/** the ordinal value for the enumeration value */
	private readonly __ordinal : number;

	/** an array containing all values of this enumeration */
	private static readonly all_values_by_ordinal : Array<Schulform> = [];

	/** an array containing all values of this enumeration indexed by their name*/
	private static readonly all_values_by_name : Map<String, Schulform> = new Map<String, Schulform>();

	public static readonly AS : Schulform = new Schulform("AS", 0, "AS", null, "Ausländische Schüler, die zugewandert sind", null, null);

	public static readonly BK : Schulform = new Schulform("BK", 1, "BK", "30", "Berufskolleg", null, null);

	public static readonly FW : Schulform = new Schulform("FW", 2, "FW", "17", "Freie Waldorfschule / Hibernia", null, null);

	public static readonly G : Schulform = new Schulform("G", 3, "G", "02", "Grundschule", null, null);

	public static readonly GE : Schulform = new Schulform("GE", 4, "GE", "15", "Gesamtschule", null, null);

	public static readonly GM : Schulform = new Schulform("GM", 5, "GM", "16", "Gemeinschaftsschule", null, null);

	public static readonly GY : Schulform = new Schulform("GY", 6, "GY", "20", "Gymnasium", null, null);

	public static readonly H : Schulform = new Schulform("H", 7, "H", "04", "Hauptschule", null, null);

	public static readonly HU : Schulform = new Schulform("HU", 8, "HU", null, "Hochschule, Universität", null, null);

	public static readonly LB : Schulform = new Schulform("LB", 9, "LB", null, "Förderschule, Schwerpunkt Lernen", null, null);

	public static readonly PS : Schulform = new Schulform("PS", 10, "PS", "13", "Schulversuch PRIMUS", null, null);

	public static readonly R : Schulform = new Schulform("R", 11, "R", "10", "Realschule", null, null);

	public static readonly S : Schulform = new Schulform("S", 12, "S", "08", "Förderschule im Bereich G/H / Schule für Kranke", null, null);

	public static readonly SB : Schulform = new Schulform("SB", 13, "SB", "88", "Förderschule im Bereich Berufskolleg", null, null);

	public static readonly SG : Schulform = new Schulform("SG", 14, "SG", "87", "Förderschule im Bereich Gymnasium", null, null);

	public static readonly SK : Schulform = new Schulform("SK", 15, "SK", "14", "Sekundarschule", null, null);

	public static readonly SO : Schulform = new Schulform("SO", 16, "SO", null, "Sonstige Förderschulen", null, null);

	public static readonly SP : Schulform = new Schulform("SP", 17, "SP", null, "Ausgesiedelte Schüler, die zugewandert sind", null, null);

	public static readonly SR : Schulform = new Schulform("SR", 18, "SR", "85", "Förderschule im Bereich Realschule", null, null);

	public static readonly V : Schulform = new Schulform("V", 19, "V", "06", "nicht umorganisierte Volksschule", null, null);

	public static readonly WB : Schulform = new Schulform("WB", 20, "WB", "25", "Weiterbildungskolleg", null, null);

	public static readonly WZ : Schulform = new Schulform("WZ", 21, "WZ", null, "Wehrdienst bzw. Zivildienst", null, null);

	public static readonly XB : Schulform = new Schulform("XB", 22, "XB", null, "Berufstätigkeit, z.B. vor Besuch einer Fachschule", null, null);

	public static readonly XS : Schulform = new Schulform("XS", 23, "XS", null, "Sonstige Schulen bzw. keine Schule", null, null);

	private static readonly _schulformen : HashMap<String, Schulform> = new HashMap();

	private static readonly _schulformenNummer : HashMap<String, Schulform> = new HashMap();

	public readonly kuerzel : String;

	private readonly nummer : String | null;

	public readonly bezeichnung : String;

	public readonly hatGymOb : boolean;

	public readonly gueltigVon : String | null;

	public readonly gueltigBis : String | null;

	/**
	 * Erzeugt eine neue Schulform in der Aufzählung.
	 * 
	 * @param kuerzel           das Kürzel, welche im Rahmen der amtlichen Schulstatistik verwendet wird
	 * @param nummer            die Nummer, welche im Rahmen der amtlichen Schulstatistik verwendet wird
	 * @param bezeichnung       die textuelle Bezeichnung der Schulform
	 * @param gueltigVon        gibt an, wann die Schulform einführt wurde - ist kein Datum bekannt, so wird null gesetzt
	 * @param gueltigBis        gibt an, bis wann die Schulform gültig ist - ist kein Datum bekannt, so wird null gesetzt
	 */
	private constructor(name : string, ordinal : number, kuerzel : String, nummer : String | null, bezeichnung : String, gueltigVon : String | null, gueltigBis : String | null) {
		super();
		this.__name = name;
		this.__ordinal = ordinal;
		Schulform.all_values_by_ordinal.push(this);
		Schulform.all_values_by_name.set(name, this);
		this.kuerzel = kuerzel;
		this.nummer = nummer;
		this.bezeichnung = bezeichnung;
		this.hatGymOb = JavaObject.equalsTranspiler("GY", (kuerzel)) || JavaObject.equalsTranspiler("GE", (kuerzel)) || JavaObject.equalsTranspiler("FW", (kuerzel));
		this.gueltigVon = gueltigVon;
		this.gueltigBis = gueltigBis;
	}

	/**
	 * Gibt eine Map von den Kürzels der Schulformen auf die zugehörigen Schulformen
	 * zurück. Sollte diese noch nicht initialisiert sein, so wird sie initielisiert.
	 *    
	 * @return die Map von den Kürzels der Schulformen auf die zugehörigen Schulformen
	 */
	private static getMapSchulformenByKuerzel() : HashMap<String, Schulform> {
		if (Schulform._schulformen.size() === 0) 
			for (let s of Schulform.values()) 
				Schulform._schulformen.put(s.kuerzel, s);
		return Schulform._schulformen;
	}

	/**
	 * Gibt eine Map von den Kürzels der Schulformen auf die zugehörigen Schulformen
	 * zurück. Sollte diese noch nicht initialisiert sein, so wird sie initielisiert.
	 *    
	 * @return die Map von den Kürzels der Schulformen auf die zugehörigen Schulformen
	 */
	private static getMapSchulformenByNummer() : HashMap<String, Schulform> {
		if (Schulform._schulformenNummer.size() === 0) 
			for (let s of Schulform.values()) 
				if (s.nummer !== null) 
					Schulform._schulformenNummer.put(s.nummer, s);
		return Schulform._schulformenNummer;
	}

	/**
	 * Gibt die Schulform für das angegebene Kürzel zurück.
	 * 
	 * @param kuerzel   das Kürzel der Schulform
	 * 
	 * @return die Schulform oder null, falls das Kürzel ungültig ist
	 */
	public static getByKuerzel(kuerzel : String | null) : Schulform | null {
		return Schulform.getMapSchulformenByKuerzel().get(kuerzel);
	}

	/**
	 * Gibt die Schulform für die angegebene Nummer zurück.
	 * 
	 * @param nummer   die Nummer der Schulform
	 * 
	 * @return die Schulform oder null, falls keine Schulform mit dieser Nummer vorhanden ist
	 */
	public static getByNummer(nummer : String | null) : Schulform | null {
		return Schulform.getMapSchulformenByNummer().get(nummer);
	}

	/**
	 * Gibt alle "echten" Schulformen dieser Aufzählung zurück.
	 * Das bedeutet, dass Pseudoschulformen, die in NRW nicht 
	 * existieren, nicht zurückgegeben werden.
	 * 
	 * @return eine {@link List} mit alle "echten" Schulformen
	 */
	public static get() : List<Schulform> {
		let result : Vector<Schulform> = new Vector();
		for (let sf of Schulform.values()) 
			if (sf.nummer !== null) 
				result.add(sf);
		return result;
	}

	/**
	 * Bestimmt für diese Schulform, die übergebene Schulgliederung (auch beim Schüler eingetragenen Schulgliederung)
	 * und den angegebenen Jahrgang die restlichen Jahre an der Schule.
	 * Ist keine Berechnung für diese Kombination implementiert,
	 * so wird null zurückgegeben.
	 *   
	 * @param gliederung   die Schulgliederung
	 * @param jahrgang     der Jahrgang, für den die restlichen Jahre bestimmt werden sollen
	 * 
	 * @return die restlichen Jahre oder null 
	 */
	public getRestlicheJahre(gliederung : Schulgliederung, jahrgang : String) : Number | null {
		if (gliederung === null) 
			return null;
		if ((this as unknown === Schulform.FW as unknown) || (this as unknown === Schulform.WB as unknown) || (this as unknown === Schulform.BK as unknown) || (this as unknown === Schulform.SB as unknown)) 
			return null;
		if (this as unknown === Schulform.GY as unknown) {
			switch (jahrgang) {
				case "05": 
					return gliederung.istG8() || (gliederung as unknown === Schulgliederung.DEFAULT as unknown) ? 8 : 9;
				case "06": 
					return gliederung.istG8() || (gliederung as unknown === Schulgliederung.DEFAULT as unknown) ? 7 : 8;
				case "07": 
					return gliederung.istG8() || (gliederung as unknown === Schulgliederung.DEFAULT as unknown) ? 6 : 7;
				case "08": 
					return gliederung.istG8() || (gliederung as unknown === Schulgliederung.DEFAULT as unknown) ? 5 : 6;
				case "09": 
					return gliederung.istG8() || (gliederung as unknown === Schulgliederung.DEFAULT as unknown) ? 4 : 5;
				case "10": 
					return gliederung.istG8() ? null : 4;
				case "EF": 
					return 3;
				case "Q1": 
					return 2;
				case "Q2": 
					return 1;
				case "11": 
					return 3;
				case "12": 
					return 2;
				case "13": 
					return 1;
			}
		} else {
			switch (jahrgang) {
				case "E1": 
					return 4;
				case "E2": 
					return 3;
				case "E3": 
					return 3;
				case "03": 
					return 2;
				case "04": 
					return 1;
				case "05": 
					return 6;
				case "06": 
					return 5;
				case "07": 
					return 4;
				case "08": 
					return 3;
				case "09": 
					return 2;
				case "10": 
					return 1;
				case "EF": 
					return 3;
				case "Q1": 
					return 2;
				case "Q2": 
					return 1;
				case "11": 
					return 3;
				case "12": 
					return 2;
				case "13": 
					return 1;
			}
		}
		return null;
	}

	/**
	 * Bestimmt für das übergegebene Schuljahr eines Schülers das Kalenderjahr, in welchem ein Schüler 
	 * der gymnasialen Oberstufe Abitur gemacht hat, macht oder machen wird. Hierbei wird für die 
	 * Bestimmung die Schulgliederung bei dem Schüler sowie das aktuelle Schuljahr und der 
	 * Statistik-Jahrgang, in welchem sich der Schüler befindet, benötigt.
	 * 
	 * @param gliederung           die Schul-Gliederung des Schülers
	 * @param aktuellesSchuljahr   das aktuelle Schuljahr, in welchem sich der Schüler befindet
	 * @param jahrgang             der Statistik-Jahrgang des Schülers
	 * 
	 * @return das Kalenderjahr des Abiturs oder null, falls das Jahr des Abiturs nicht bestimmt werden kann.
	 */
	public getGostAbiturjahr(gliederung : Schulgliederung, aktuellesSchuljahr : number, jahrgang : String) : Number | null {
		if (!this.hatGymOb) 
			return null;
		let restjahre : Number | null = this.getRestlicheJahre(gliederung, jahrgang);
		return restjahre === null ? null : aktuellesSchuljahr + restjahre.valueOf();
	}

	/**
	 * Bestimmt für das angegebene Abiturjahr, das angegebene aktuelles Schuljahr, in dem sich die
	 * Schule befindet, und der angegebenen Schulgliederung den zugrhörigen Statistik-Jahrgang 
	 * einer Schule mit gymnasialer Oberstufe.  
	 * 
	 * @param gliederung    die Schulgliederung
	 * @param schuljahr     das Schuljahr, in dem sich die Schule befindet
	 * @param abiturjahr    das Abiturjahr, für welches der Statistik-Jahrgang ermittelt werden soll. 
	 * 
	 * @return der Statistik-Jahrgang zu dem angegeben Abiturjahrgang
	 */
	public getGostAbiturjahrJahrgang(gliederung : Schulgliederung, schuljahr : number, abiturjahr : number) : String | null {
		if (!this.hatGymOb) 
			return null;
		let restlicheJahre : number = abiturjahr - schuljahr;
		if (restlicheJahre <= 1) 
			return "Q2";
		if (restlicheJahre === 2) 
			return "Q1";
		if (restlicheJahre === 3) 
			return "EF";
		let sekIJahre : number = gliederung.istG8() || ((this as unknown === Schulform.GY as unknown) && (gliederung as unknown === Schulgliederung.DEFAULT as unknown)) ? 9 : 10;
		if (restlicheJahre >= sekIJahre) 
			return null;
		let strJG : String | null = "" + (sekIJahre - (restlicheJahre - 4));
		if (strJG.length === 1) 
			strJG = "0" + strJG.valueOf();
		return strJG;
	}

	/**
	 * Returns the name of this enumeration value.
	 *
	 * @returns the name
	 */
	private name() : String {
		return this.__name;
	}

	/**
	 * Returns the ordinal value of this enumeration value.
	 *
	 * @returns the ordinal value
	 */
	private ordinal() : number {
		return this.__ordinal;
	}

	/**
	 * Returns the name of this enumeration value.
	 *
	 * @returns the name
	 */
	public toString() : String {
		return this.__name;
	}

	/**
	 * Returns true if this and the other enumeration values are equal.
	 *
	 * @param other   the other enumeration value
	 *
	 * @returns true if they are equal and false otherwise
	 */
	public equals(other : JavaObject) : boolean {
		if (!(other instanceof Schulform))
			return false;
		return this === other;
	}

	/**
	 * Returns the ordinal value as hashcode, since the ordinal value is unique.
	 *
	 * @returns the ordinal value as hashcode
	 */
	public hashCode() : number {
		return this.__ordinal;
	}

	/**
	 * Compares this enumeration value with the other enumeration value by their ordinal value.
	 *
	 * @param other   the other enumeration value
	 *
	 * @returns a negative, zero or postive value as this enumeration value is less than, equal to
	 *          or greater than the other enumeration value
	 */
	public compareTo(other : Schulform) : number {
		return this.__ordinal - other.__ordinal;
	}

	/**
	 * Returns an array with enumeration values.
	 *
	 * @returns the array with enumeration values
	 */
	public static values() : Array<Schulform> {
		return [...this.all_values_by_ordinal];
	}

	/**
	 * Returns the enumeration value with the specified name.
	 *
	 * @param name   the name of the enumeration value
	 *
	 * @returns the enumeration values or null
	 */
	public static valueOf(name : String) : Schulform | null {
		let tmp : Schulform | undefined = this.all_values_by_name.get(name);
		return (!tmp) ? null : tmp;
	}

	isTranspiledInstanceOf(name : string): boolean {
		return ['de.nrw.schule.svws.core.types.statkue.Schulform'].includes(name);
	}

}

export function cast_de_nrw_schule_svws_core_types_statkue_Schulform(obj : unknown) : Schulform {
	return obj as Schulform;
}
