using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using ZusiCLIProject.EntryPoints.ReihenschlussHelper;
using ZusiCLIProject.FileLibrary.Zusi3;
using KombiSchalterFunktion = ZusiCLIProject.FileLibrary.Zusi3.NativeMethods.KombiSchalterFunktion;

#if NETCOREAPP
namespace ZusiCLIProject.EntryPoints;
#else
namespace ZusiCLIProject.EntryPoints
{
#endif

public class Steuergeraet111
{
	public struct GrenzwertueberwachungEin
	{
		public float ImotIst { get; set; }
		public float IoberIst { get; set; }
		public float Fist { get; set; }
		public float UmotIst { get; set; }
		public float FsollZ { get; set; }
		public float FsollAFB { get; set; }
		public bool Faktiv { get; set; }
		public bool FahrschalterAuf { get; set; }
		public bool FahrschalterAb { get; set; }
		public bool Stoerschalter { get; set; }
		public bool Schleuderschutzkipptaster { get; set; }
		public bool KsAnfahrUeberwachung { get; set; }
		public bool MotorstromdiffSchleudern { get; set; }
	}
	public struct GrenzwertueberwachungAus
	{
		public bool AbSchuetz { get; set; }
		public bool AufSchuetz { get; set; }
		public bool Schleuderschutzbremse { get; set; }
		public bool LMAnfahrueberwachung { get; set; }
		public bool LMFunktionsbereit { get; set; }
		public static GrenzwertueberwachungAus Generate(GrenzwertueberwachungEin input)
		{
			var value = new GrenzwertueberwachungAus();
			value.LMFunktionsbereit = input.KsAnfahrUeberwachung;
			float iSollCurtis;
			if (Math.Abs(input.UmotIst) < 150)
				iSollCurtis = 3500;
			else if (Math.Abs(input.UmotIst) < 300)
				iSollCurtis = (Math.Abs(input.UmotIst) - 300) / (300 - 150) * (3200 - 3500) + 3200;
			else if (Math.Abs(input.UmotIst) < 450)
				iSollCurtis = (Math.Abs(input.UmotIst) - 450) / (450 - 300) * (2900 - 3200) + 2900;
			else
				iSollCurtis = 2900;
			bool abEin = false;
			bool aufStop = false;
			if ((input.ImotIst > iSollCurtis) ||
				(input.Faktiv && (input.Fist > input.FsollZ)) ||
				(input.Fist > input.FsollAFB)
				)
			{
				abEin = true;
				aufStop = true;
			}
			if (input.IoberIst > 420)
				abEin = true;
			if (input.IoberIst > 380)
				aufStop = true;
			if (input.UmotIst > 510)
				abEin = true;
			if (input.UmotIst > 465)
				aufStop = true;
			if (input.IoberIst > 3500)
				abEin = true;
			if (input.IoberIst > 3430)
				aufStop = true;
			if (input.MotorstromdiffSchleudern)
				aufStop = true;
			value.Schleuderschutzbremse = ((input.MotorstromdiffSchleudern && !input.Stoerschalter) || input.Schleuderschutzkipptaster);
			bool aufAuftrag = input.FahrschalterAuf || input.Faktiv;
			value.AufSchuetz = aufAuftrag && (!aufStop || input.Stoerschalter);
			bool abAuftrag = input.FahrschalterAb;
			value.AbSchuetz = abAuftrag || (abEin && !input.Stoerschalter);
			value.LMAnfahrueberwachung = !input.KsAnfahrUeberwachung || input.Stoerschalter; //Oder noch irgendwas (vmtl. irgendwas mit Motor).

			return value;
		}
	}
}
public class Schuetzsteuerung
{
	public Schuetzsteuerung(AntriebsmodellElektrischReihenschluss.NachlaufsteuerungTyp daten)
	{
		Daten = daten;
	}
	public bool AbSchuetz { get; set; }
	public bool AufSchuetz { get; set; }
	private double m_deltaStufe = 0;
	public void Berechnung(double deltaT) 
	{
		if (AufSchuetz && (Stufe < Daten.AnzahlSchaltstufen))
			m_deltaStufe += deltaT * Daten.GeschwAuf;
		else if (AbSchuetz && (Stufe > 0))
			m_deltaStufe -= deltaT * Daten.GeschwAb;
		else if (m_deltaStufe > 0)
			m_deltaStufe = System.Math.Max(m_deltaStufe - deltaT * Daten.GeschwAb, 0);
		else if (m_deltaStufe < 0) 
			//m_deltaStufe = System.Math.Min(m_deltaStufe + deltaT * Daten.GeschwAuf, 0);
			m_deltaStufe = System.Math.Min(m_deltaStufe - deltaT * Daten.GeschwAb, -1.0f); //Original-Verhalten beim Wegfall des Auf/Ab-Befehls
																							//während des Laufens: Geht sofort in den Ab-Modus bis wieder eine gerade Stufe gefunden wurde.

		if (m_deltaStufe >= 1)
		{
			++Stufe;
			m_deltaStufe -= 1;
		}
		else if (m_deltaStufe <= -1)
		{
			--Stufe;
			m_deltaStufe += 1;
			if (!AbSchuetz)
				m_deltaStufe = 0; //Vermeiden von Endlosschleifen wegen Rundungsfehlern bei float.
		}

		if (Stufe <= 0)
			Stufe = System.Math.Max(Stufe, 0);
		if (Stufe >= Daten.AnzahlSchaltstufen)
			Stufe = System.Math.Min(Stufe, Daten.AnzahlSchaltstufen);
	}
	public int Stufe {get; private set;}
	public AntriebsmodellElektrischReihenschluss.NachlaufsteuerungTyp Daten { get; private set; }
}
public class HauptschalterSteuerung
{
	public HauptschalterSteuerung(Antriebssystem111 parent) {this.Parent = parent;}
	public void Bedienung(NativeMethods.ProtokollFstRef fstProtokoll)
	{
		bool StromabnehmerHilfsschuetz = true; //Vorerst nicht vorhanden.
		HauptschalterHilfsschuetz = (Hauptschalterzustand == 0);
		if (RichtungsschalterHilfsschuetz)
		{
			if (fstProtokoll.Value.Hauptschalter.Funktion == KombiSchalterFunktion.HauptschalterAus)
				HauptschalterHilfsschuetz = false;
			else if (fstProtokoll.Value.Hauptschalter.Funktion == KombiSchalterFunktion.HauptschalterEin &&
							fstProtokoll.Value.SchaltstufenSteller.Funktion == KombiSchalterFunktion.FahrstufeSchnellAus)
				HauptschalterHilfsschuetz = true;
		}
		if (!StromabnehmerHilfsschuetz)
			HauptschalterHilfsschuetz = false;
	}
	//Eigener Wert, ist ein Carry zu Berechnung.
	public bool HauptschalterHilfsschuetz {get; private set;}
	
	//Eigener Wert, von außen sinnvoll Zugreifbar
	public byte Hauptschalterzustand { get; set; }
	public bool HasHauptschalterausloesungWgOberstrom { get; private set; }
	
	//Getter vom Parent
	protected Antriebssystem111 Parent {get; private set;}
	protected AntriebsmodellElektrischReihenschluss.MotorenWerte MotorenWerte {get {return Parent.MotorenWerte;} }
	protected AntriebsmodellElektrischReihenschluss Antriebsdaten {get {return Parent.Antriebsdaten;} }
	protected bool RichtungsschalterHilfsschuetz {get {return Parent.RichtungsschalterSteuerung.RichtungsschalterHilfsschuetz;} }
	protected Schuetzsteuerung Schuetzsteuerung {get {return Parent.Schuetzsteuerung;} }
	
	//Config:
	public bool UnterspannungsStoerschalter {get; set;}
	
	public void Berechnung(NativeMethods.MehrfachtraktionsdatenRef mehrfachtraktionsdaten) 
	{
		//bool thyristerolastschalterschuz;
		//bool oelueberdruckschutz;
		//bool buchholzschutz;
		//Hauptschalter-Hilfsschütz
		//bool motoruebersromschutz = MotorenWerte.IMotor > xxx
		//bool ueberstromZugheizung
		//bool erdstromueberwachung = xxx > 70;
		bool oberstromausloesung = MotorenWerte.IOber > Antriebsdaten.MaxOberstrom;
		bool unterspannungsausloesung = mehrfachtraktionsdaten.Value.FahrlSpannungsfaktor < (10.0f / 15);
		if (UnterspannungsStoerschalter)
			unterspannungsausloesung = false;
		//Hilfsdruckluft min. 4,9...5,8 bar (von 10,5 aus der 10-Bar-Leitung, Hilfslufpresser kann nur 7,5.)
		bool haltestromkreis = !oberstromausloesung && !unterspannungsausloesung && HauptschalterHilfsschuetz;
		
		bool einschaltstromkreis = Parent.Schuetzsteuerung.Stufe == 0 && haltestromkreis;
		
		if (Hauptschalterzustand == 0 && !haltestromkreis && oberstromausloesung)
			HasHauptschalterausloesungWgOberstrom = true;
		
		if (haltestromkreis && Hauptschalterzustand == 0)
			Hauptschalterzustand = 0;
		else if (einschaltstromkreis)
			Hauptschalterzustand = 0;
		else
			Hauptschalterzustand = 1;
		
		if (Hauptschalterzustand == 0)
			HasHauptschalterausloesungWgOberstrom = false;
	}
}
public class RichtungsschalterSteuerung
{
	//public RichtungsschalterSteuerung(Antriebssystem111 parent) {this.Parent = parent;}
	public void Bedienung(NativeMethods.ProtokollFstRef fstProtokoll)
	{
		RichtungsschalterHilfsschuetz = fstProtokoll.Value.Rischa.Funktion != KombiSchalterFunktion.Rischa0; //RischaV..M..0..R
	}
	public bool RichtungsschalterHilfsschuetz {get; private set;}
	public void Berechnung(NativeMethods.MehrfachtraktionsdatenRef mehrfachtraktionsdaten) 
	{
	}
}
public class Lueftersteuerung
{
	public Lueftersteuerung(Antriebssystem111 parent) {this.Parent = parent;}
	public void Bedienung(NativeMethods.ProtokollFstRef fstProtokoll)
	{
		//Ein Schalter "Schwach-Aus-Stark"
		//Auf Stufe 2 ab Schaltwerk 9, wenn E-Bremse läuft, oder wenn Stufe 2 angewählt.
		//Sonnst Stufe 1, wenn angewählt (ohne Automatik)
		//Sonnst Stufe 0, 
		//Umschaltverzögerung 1->0->2, auch wenn Automatische Aktionen dazu führen, da eine Spannungsumschaltung stattfindet.
		//Steuer-Druckluft erforderlich.
		//Hochlauf-Schütze in der tatsächlichen Steuerung.
		//Schalter Schwach wird über die KWS d25 übertragen, stark nicht.
		bool kippschalterStufe1 = fstProtokoll.Value.LuefterEin;
		bool kippschalterStufe2 = false;
		bool eBremse = false; //Derzeit noch nicht möglich, nur Antrieb.
		if (Schuetzsteuerung.Stufe >= 9 || eBremse || kippschalterStufe2)
			LueferFahrmotorStufe = (LueferFahrmotorStufe == 0 || LueferFahrmotorStufe == 2) ? 2 : 0;
		else if (kippschalterStufe1)
			LueferFahrmotorStufe = (LueferFahrmotorStufe == 0 || LueferFahrmotorStufe == 1) ? 1 : 0;
		else
			LueferFahrmotorStufe = 0;
	}
	//Eigener Wert
	public int LueferFahrmotorStufe {get; private set;} //Rückübertragung vom Parent.
	
	//Getter vom Parent
	protected Antriebssystem111 Parent {get; private set;}
	public Schuetzsteuerung Schuetzsteuerung {get {return Parent.Schuetzsteuerung;} }
	public void Berechnung(NativeMethods.MehrfachtraktionsdatenRef mehrfachtraktionsdaten) 
	{
	}
}
public class Fahrsteuerung
{
	public Fahrsteuerung(Antriebssystem111 parent) { this.Parent = parent; }

	public void Bedienung(NativeMethods.ProtokollFstRef fstProtokoll)
	{
		NotbremseHilfsschuetz = DruckHL > 3.0f; //3,5..2,5 bar

		//Druckwächter HLL := > 3,5..2,5 bar
		//DynBremsSteller := 0
		//Druckwächter Sifa := > 3,2..4,2 bar
		//Sperrrelais: ist das Relais für alle Nullstellungszwänge.
		//Druckwächter HLL erzeugt eine E-Bremse.
		//Sperrelais geht wieder ein, wenn Hauptfahrschalter in 0 oder Hilfsfahrschalter in 0 und aktiv.
		//Hilfsfahrschalter (Seitenfahrschalter) aktiv, wenn Hauptsteuerung in Fahrt und Taster Hilfsfahrschalter frei. Selbstabfall wen HLL oder E-Bremse oder RiScha oder Hauptsteerung Fahrt verlassen.
		//Alles deaktiviert, wenn Hilfsschütz Richtungsschalter nicht an.
		//Antriebs-Aktivierungs-Leitung wenn Hauptsteuerung nicht 0 und entweder Hilfssteuerung nicht 0 oder Hilfssteuerung nicht aktiv.
		//Result -> local bool richtungswenderfreigabe

		bool richtungswenderfreigabe1 =
			//KS Fahrsteuerung
			NotbremseHilfsschuetz &&
			(fstProtokoll.Value.DynBremsSteller.Funktion == KombiSchalterFunktion.DynBremsenull || //:= Stufe L
			(fstProtokoll.Value.DynBremsSteller.Funktion == KombiSchalterFunktion.DynBremseX && //:= Stufe F
			fstProtokoll.Value.DynBremsSteller.Parameter == 0.0f)) &&
			RichtungsschalterHilfsschuetz;

		FahrsteuerSperrelais =
			richtungswenderfreigabe1 &&
			(
			(fstProtokoll.Value.SchaltstufenSteller.Funktion == KombiSchalterFunktion.FahrstufeSchnellAus)
			||
			(HilfsfahrschalterHilfsschuetz &&
			(fstProtokoll.Value.Ganghebel.Funktion == KombiSchalterFunktion.GangWahlnull)
			) ||
			FahrsteuerSperrelais
			)
			// && DW Sifa oder Sifa-Störschalter
			;

		HilfsfahrschalterHilfsschuetz =
			richtungswenderfreigabe1 &&
			(fstProtokoll.Value.SchaltstufenSteller.Funktion == KombiSchalterFunktion.FahrstufeFahren) &&
			(
			HilfsfahrschalterHilfsschuetz
			||
			((fstProtokoll.Value.Ganghebel.Funktion == KombiSchalterFunktion.GangWahlnull) &&
			(fstProtokoll.Value.GetFtdIntern(Antriebssystem111.IdHilfsfahrschalterFrei) > 0)
			)
			);

		Richtungswenderfreigabe =
			richtungswenderfreigabe1 &&
			RichtungsschalterHilfsschuetz &&
			(fstProtokoll.Value.SchaltstufenSteller.Funktion != KombiSchalterFunktion.FahrstufeSchnellAus) &&
			(!HilfsfahrschalterHilfsschuetz ||
			(fstProtokoll.Value.Ganghebel.Funktion != KombiSchalterFunktion.GangWahlnull));

		RichtungVHilfsschuetz = fstProtokoll.Value.Rischa.Funktion == KombiSchalterFunktion.RischaV;
		RichtungRHilfsschuetz = fstProtokoll.Value.Rischa.Funktion == KombiSchalterFunktion.RischaR;
	}
	private float DruckHL = 0;
	private bool Richtungswenderfreigabe = false;
	private int stufeAlt = 0;

	public bool NotbremseHilfsschuetz { get; private set; }
	public bool HilfsfahrschalterHilfsschuetz { get; private set; }
	public bool FahrsteuerSperrelais { get; private set; }
	public bool RichtungVHilfsschuetz { get; private set; }
	public bool RichtungRHilfsschuetz { get; private set; }

	public bool Richtungswender1V { get; private set; }
	public bool Richtungswender2V { get; private set; }

	public bool Bremswender1F { get; private set; }
	public bool Bremswender2F { get; private set; }

	public bool FahrmotorTrennschuetz { get; private set; }

	public float LeistungsfaktorTrennschuetzRichtungswender { get; private set; }

	//Getter vom Parent
	protected Antriebssystem111 Parent { get; private set; }
	protected AntriebsmodellElektrischReihenschluss.MotorenWerte MotorenWerte { get { return Parent.MotorenWerte; } }
	protected AntriebsmodellElektrischReihenschluss Antriebsdaten { get { return Parent.Antriebsdaten; } }
	protected bool RichtungsschalterHilfsschuetz { get { return Parent.RichtungsschalterSteuerung.RichtungsschalterHilfsschuetz; } }
	public void Berechnung(NativeMethods.MehrfachtraktionsdatenRef mehrfachtraktionsdaten)
	{
		DruckHL = mehrfachtraktionsdaten.Value.DruckHL;
		//Bringe Richungswender 1 je nach V oder R in Richtige Lage, wenn Schaltwerk abgelaufen.
		//Bringe RiSach2 je nach V oder R in Richtige Lage, wenn 1 umgelaufen ist (Schaltwerk egal)
		//Bringe Fahrbremswener 1 und 2 in richtig Lage, aber deren Zuständigkeit ist Bremswender
		//Result -> local bool Trennschuetzfreigabe

		if (Richtungswenderfreigabe &&
			!RichtungRHilfsschuetz &&
			RichtungVHilfsschuetz &&
			!Richtungswender1V &&
			//Fahr-Brems-Umschaltung (1,5 sek) &&
			Parent.Schuetzsteuerung.Stufe == 0)
			Richtungswender1V = true;

		if (Richtungswenderfreigabe &&
			!RichtungVHilfsschuetz &&
			RichtungRHilfsschuetz &&
			Richtungswender1V &&
			//Fahr-Brems-Umschaltung (1,5 sek) &&
			Parent.Schuetzsteuerung.Stufe == 0)
			Richtungswender1V = false;

		if (Richtungswenderfreigabe &&
			!RichtungRHilfsschuetz &&
			RichtungVHilfsschuetz &&
			Richtungswender1V &&
			!Richtungswender2V)
			Richtungswender2V = true;

		if (Richtungswenderfreigabe &&
			!RichtungVHilfsschuetz &&
			RichtungRHilfsschuetz &&
			!Richtungswender1V &&
			Richtungswender2V)
			Richtungswender2V = false;

		bool fahrbremswenderfreigabe =
			(
			(Richtungswenderfreigabe &&
			!RichtungRHilfsschuetz &&
			RichtungVHilfsschuetz &&
			Richtungswender1V &&
			Richtungswender2V) ||
			(Richtungswenderfreigabe &&
			!RichtungVHilfsschuetz &&
			RichtungRHilfsschuetz &&
			!Richtungswender1V &&
			!Richtungswender2V)
			)
			&& true; //Fahr-Brems-Umschaltung (1,5 sek)

		if (fahrbremswenderfreigabe && 
			//!Bremsen Hilfsschütz &&
			!Bremswender1F &&
			!FahrmotorTrennschuetz &&
			!Bremswender1F)
			Bremswender1F = true;

		if (fahrbremswenderfreigabe &&
			Bremswender1F &&
			!Bremswender2F)
			Bremswender2F = true;

		bool trennschueztfreigabe =
			fahrbremswenderfreigabe &&
			Bremswender1F &&
			Bremswender2F;

		//Trennschütz:
		//Hilfsschütz Notbremse
		//Steuerrelais (ist eine Dauer-Ein-Sicherung, erst mal ignorierbar)
		//Schaltwerk != 0
		//Je FM dasFM-Übertrom-Relais
		//FM-Handabschaltung
		//Schaltwerk war 0 oder Trennschütz ist ein. (Achtung mit der andern Schaltwerk-Bedinung oben...)
		FahrmotorTrennschuetz =
			trennschueztfreigabe &&
			NotbremseHilfsschuetz &&
			//Steuerrelais (ist eine Dauer-Ein-Sicherung, erst mal ignorierbar)
			(Parent.Schuetzsteuerung.Stufe != 0) &&
			//FM-Übertrom-Relais (Überstrom pro Fahrmotor)
			//FM-Handabschaltung
			(
			stufeAlt == 0 || //In der Doku so eingezeichnet, dass sie mit Stufe != 0 kollidieren würde...
			FahrmotorTrennschuetz
			);

		stufeAlt = Parent.Schuetzsteuerung.Stufe;

		if (FahrmotorTrennschuetz && Richtungswender1V && Richtungswender2V && Bremswender1F && Bremswender2F)
			LeistungsfaktorTrennschuetzRichtungswender = 1;
		else if (FahrmotorTrennschuetz && !Richtungswender1V && !Richtungswender2V && Bremswender1F && Bremswender2F)
			LeistungsfaktorTrennschuetzRichtungswender = -1;
		else
			LeistungsfaktorTrennschuetzRichtungswender = 0;
	}

}







#if NETCOREAPP
#else
}
#endif
