# A3XX FADEC/Throttle Control System
# Copyright (c) 2021 Josh Davidson (Octal450)

if (pts.Options.eng.getValue() == "IAE") {
	io.include("fadec-iae.nas");
} else {
	io.include("fadec-cfm.nas");
}

var FADEC = {
	alphaFloor: props.globals.getNode("/fdm/jsbsim/fadec/alpha-floor"),
	clbReduc: props.globals.getNode("/fdm/jsbsim/fadec/clbreduc-ft"),
	detent: [props.globals.getNode("/fdm/jsbsim/fadec/control-1/detent", 1), props.globals.getNode("/fdm/jsbsim/fadec/control-2/detent", 1)],
	detentTemp: [0, 0],
	detentText: [props.globals.getNode("/fdm/jsbsim/fadec/control-1/detent-text"), props.globals.getNode("/fdm/jsbsim/fadec/control-2/detent-text")],
	detentTextTemp: [0, 0],
	engOut: props.globals.getNode("/fdm/jsbsim/fadec/eng-out"),
	Limit: {
		activeEpr: props.globals.getNode("/fdm/jsbsim/fadec/limit/active-epr"),
		activeMode: props.globals.getNode("/fdm/jsbsim/fadec/limit/active-mode"),
		activeModeInt: props.globals.getNode("/fdm/jsbsim/fadec/limit/active-mode-int"), # 0 TOGA, 1 MCT, 2 CL, 3 FLX, 4 MREV
		activeModeIntTemp: 0,
		activeN1: props.globals.getNode("/fdm/jsbsim/fadec/limit/active-n1"),
		flexActive: props.globals.getNode("/fdm/jsbsim/fadec/limit/flex-active"),
		flexActiveCmd: props.globals.getNode("/fdm/jsbsim/fadec/limit/flex-active-cmd"),
		flexTemp: props.globals.getNode("/fdm/jsbsim/fadec/limit/flex-temp"),
	},
	lvrClb: props.globals.getNode("/fdm/jsbsim/fadec/lvrclb"),
	lvrClbStatus: 0,
	Lock: {
		thrLockAlert: props.globals.getNode("/fdm/jsbsim/fadec/thr-locked-alert"),
		thrLockCmd: props.globals.getNode("/fdm/jsbsim/fadec/thr-locked"),
		thrLockFlash: props.globals.getNode("/fdm/jsbsim/fadec/thr-locked-flash"),
		thrLockTime: props.globals.getNode("/fdm/jsbsim/fadec/thr-locked-time"),
	},
	manThrAboveMct: [0, 0],
	maxDetent: props.globals.getNode("/fdm/jsbsim/fadec/max-detent"),
	n1Mode: [props.globals.getNode("/fdm/jsbsim/fadec/control-1/n1-mode"), props.globals.getNode("/fdm/jsbsim/fadec/control-2/n1-mode")],
	togaLk: props.globals.getNode("/fdm/jsbsim/fadec/toga-lk"),
	init: func() {
		me.engOut.setBoolValue(0);
		me.Limit.activeMode.setBoolValue("TOGA");
		me.Limit.activeModeInt.setValue(0);
		me.Limit.flexActive.setBoolValue(0);
		me.Limit.flexActiveCmd.setBoolValue(0);
		systems.FADEC_S.init();
		thrustFlashT.start();
	},
	canEngageAthr: func() {
		if (pts.Gear.wow[0].getValue() and (pts.Engines.Engine.state[0].getValue() == 3 or pts.Engines.Engine.state[1].getValue() == 3)) {
			return 1;
		} else {
			return 0;
		}
	},
	cancelFlex: func() {
		if (me.detent[0].getValue() != 4 and me.detent[1].getValue() != 4 and !pts.Gear.wow[1].getValue() and !pts.Gear.wow[2].getValue()) {
			me.Limit.flexActive.setBoolValue(0);
		}
	},
	idleAthrOff: func() {
		if (me.detent[0].getValue() == 0 and me.detent[1].getValue() == 0) { # And not in TOGA LK and not in ALPHA FLOOR
			if (fmgc.Input.athr.getValue() and pts.Position.gearAglFt.getValue() > 50) {
				fcu.athrOff("soft");
			} else {
				fcu.athrOff("none");
			}
		}
	},
	updateDetent: func(n) {
		me.detentTemp[n] = me.detent[n].getValue();
		if (me.detentTemp[n] == 6) {
			me.manThrAboveMct[n] = 1;
			me.detentText[n].setValue("TOGA");
			if (!fmgc.Output.athr.getBoolValue() and me.canEngageAthr()) {
				fmgc.Input.athr.setValue(1);
			}
		} else if (me.detentTemp[n] == 5) {
			me.manThrAboveMct[n] = 1;
			me.detentText[n].setValue("MAN THR");
		} else if (me.detentTemp[n] == 4) {
			me.manThrAboveMct[n] = 0;
			me.detentText[n].setValue("MCT");
			if (me.engOut.getValue() != 1 and me.Limit.flexActive.getBoolValue()) {
				if (!fmgc.Output.athr.getBoolValue() and me.canEngageAthr()) {
					fmgc.Input.athr.setValue(1);
				}
			}
		} else if (me.detentTemp[n] == 3) {
			me.manThrAboveMct[n] = 0;
			me.detentText[n].setValue("MAN THR");
		} else if (me.detentTemp[n] == 2) {
			me.manThrAboveMct[n] = 0;
			me.detentText[n].setValue("CL");
		} else if (me.detentTemp[n] == 1) {
			me.manThrAboveMct[n] = 0;
			me.detentText[n].setValue("MAN");
		} else if (me.detentTemp[n] == 0) {
			me.manThrAboveMct[n] = 0;
			me.detentText[n].setValue("IDLE");
			me.idleAthrOff();
		}
		
		if (me.detentTemp[n] != 4) {
			if (me.Limit.flexActiveCmd.getBoolValue()) {
				me.cancelFlex();
			}
		}
	},
	loop: func() {
		FADEC_S.loop(); # Update engine specific elements
		pts.Engines.Engine.stateTemp[0] = pts.Engines.Engine.state[0].getValue();
		pts.Engines.Engine.stateTemp[1] = pts.Engines.Engine.state[1].getValue();
		pts.Gear.wowTemp[1] = pts.Gear.wow[1].getValue();
		pts.Gear.wowTemp[2] = pts.Gear.wow[2].getValue();
		
		if (me.Limit.flexActiveCmd.getBoolValue() and !me.n1Mode[0].getValue() and !me.n1Mode[1].getValue() and pts.Gear.wowTemp[1] and pts.Gear.wowTemp[2] and pts.Velocities.groundspeedKt.getValue() < 40 and (pts.Engines.Engine.stateTemp[0] == 3 or pts.Engines.Engine.stateTemp[1] == 3)) {
			if (!me.Limit.flexActive.getBoolValue()) {
				me.Limit.flexActive.setBoolValue(1);
			}
		} else if (!me.Limit.flexActiveCmd.getBoolValue() or pts.Engines.Engine.stateTemp[0] != 3 or pts.Engines.Engine.stateTemp[1] != 3) {
			if (me.Limit.flexActive.getBoolValue()) {
				me.Limit.flexActive.setBoolValue(0);
			}
		}
	},
	thrustFlash: func() {
		me.detentTextTemp[0] = systems.FADEC.detentText[0].getValue();
		me.detentTextTemp[1] = systems.FADEC.detentText[1].getValue();
		
		if (!pts.Gear.wow[1].getValue() and !pts.Gear.wow[2].getValue() and (pts.Engines.Engine.state[0].getValue() != 3 or pts.Engines.Engine.state[1].getValue() != 3)) {
			systems.FADEC.engOut.setValue(1)
		} else {
			systems.FADEC.engOut.setValue(0)
		}
		
		if (me.detentTextTemp[0] == "CL" and me.detentTextTemp[1] == "CL" and me.engOut.getValue() != 1) {
			me.lvrClb.setValue(0);
		} else if (me.detentTextTemp[0] == "MCT" and me.detentTextTemp[1] == "MCT" and !me.Limit.flexActive.getBoolValue() and me.engOut.getValue()) {
			me.lvrClb.setValue(0);
		} else {
			me.lvrClbStatus = me.lvrClb.getValue();
			if (me.lvrClbStatus == 0) {
				if (!pts.Gear.wow[0].getValue()) {
					if (systems.FADEC.detentText[0].getValue() == "MAN" or systems.FADEC.detentText[1].getValue() == "MAN") {
						me.lvrClb.setValue(1);
					} else {
						if (pts.Instrumentation.Altimeter.indicatedFt.getValue() >= me.clbReduc.getValue() and !pts.Gear.wow[1].getValue() and !pts.Gear.wow[2].getValue()) {
							me.lvrClb.setValue(1);
						} else if ((me.detentTextTemp[0] == "CL" and me.detentTextTemp[1] != "CL") or (me.detentTextTemp[0] != "CL" and me.detentTextTemp[1] == "CL") and me.engOut.getValue() != 1) {
							me.lvrClb.setValue(1);
						} else {
							me.lvrClb.setValue(0);
						}
					}
				}
			} else if (me.lvrClbStatus == 1) {
				me.lvrClb.setValue(0);
			}
		}
	},
	updateTxt: func() {
		me.Limit.activeModeIntTemp = me.Limit.activeModeInt.getValue();
		if (me.Limit.activeModeIntTemp == 0) {
			me.Limit.activeMode.setValue("TOGA");
		} else if (me.Limit.activeModeIntTemp == 1) {
			me.Limit.activeMode.setValue("MCT");
		} else if (me.Limit.activeModeIntTemp == 2) {
			me.Limit.activeMode.setValue("CLB");
		} else if (me.Limit.activeModeIntTemp == 3) {
			me.Limit.activeMode.setValue("FLX");
		} else if (me.Limit.activeModeIntTemp == 4) {
			me.Limit.activeMode.setValue("MREV");
		}
	},
};

var thrustFlashT = maketimer(0.5, FADEC, FADEC.thrustFlash);

setlistener("/fdm/jsbsim/fadec/control-1/detent", func() {
	FADEC.updateDetent(0);
}, 0, 0);
setlistener("/fdm/jsbsim/fadec/control-2/detent", func() {
	FADEC.updateDetent(1);
}, 0, 0);
setlistener("/fdm/jsbsim/fadec/limit/active-mode-int", func() {
	FADEC.updateTxt();
}, 0, 0);

var lockThr = func() {
	state1 = systems.FADEC.detentText[0].getValue();
	state2 = systems.FADEC.detentText[1].getValue();
	if ((state1 == "CL" and state2 == "CL" and !systems.FADEC.engOut.getValue()) or (state1 == "MCT" and state2 == "MCT" and systems.FADEC.engOut.getValue())) {
		FADEC.Lock.thrLockTime.setValue(pts.Sim.Time.elapsedSec.getValue());
		FADEC.Lock.thrLockCmd.setValue(1);
		lockTimer.start();
	}
}

var checkLockThr = func() {
	if (FADEC.Lock.thrLockTime.getValue() + 5 > pts.Sim.Time.elapsedSec.getValue()) { return; }
	
	if (fmgc.Output.athr.getBoolValue()) {
		lockTimer.stop();
		FADEC.Lock.thrLockCmd.setValue(0);
		FADEC.Lock.thrLockAlert.setValue(0);
		FADEC.Lock.thrLockTime.setValue(0);
		FADEC.Lock.thrLockFlash.setValue(0);
		return;
	}
	
	if (!FADEC.Lock.thrLockCmd.getValue()) {
		lockTimer.stop();
		FADEC.Lock.thrLockCmd.setValue(0);
		FADEC.Lock.thrLockAlert.setValue(0);
		FADEC.Lock.thrLockTime.setValue(0);
		FADEC.Lock.thrLockFlash.setValue(0);
		return;
	}
	
	state1 = systems.FADEC.detentText[0].getValue();
	state2 = systems.FADEC.detentText[1].getValue();
	
	if ((state1 != "CL" and state2 != "CL" and !systems.FADEC.engOut.getValue()) or (state1 != "MCT" and state2 != "MCT" and systems.FADEC.engOut.getValue())) {
		lockTimer.stop();
		FADEC.Lock.thrLockCmd.setValue(0);
		FADEC.Lock.thrLockAlert.setValue(0);
		FADEC.Lock.thrLockTime.setValue(0);
		FADEC.Lock.thrLockFlash.setValue(0);
	} elsif ((state1 == "CL" and state2 == "CL" and !systems.FADEC.engOut.getValue()) or (state1 == "MCT" and state2 == "MCT" and systems.FADEC.engOut.getValue())) {
		FADEC.Lock.thrLockAlert.setValue(1);
		FADEC.Lock.thrLockTime.setValue(pts.Sim.Time.elapsedSec.getValue());
		FADEC.Lock.thrLockFlash.setValue(1);
		lockTimer.stop();
		lockTimer2.start();
	}
}

var checkLockThr2 = func() {
	if (fmgc.Output.athr.getBoolValue()) {
		lockTimer2.stop();
		FADEC.Lock.thrLockCmd.setValue(0);
		FADEC.Lock.thrLockAlert.setValue(0);
		FADEC.Lock.thrLockTime.setValue(0);
		FADEC.Lock.thrLockFlash.setValue(0);
		return;
	}
	
	if (!FADEC.Lock.thrLockCmd.getValue()) {
		lockTimer2.stop();
		FADEC.Lock.thrLockCmd.setValue(0);
		FADEC.Lock.thrLockAlert.setValue(0);
		FADEC.Lock.thrLockTime.setValue(0);
		FADEC.Lock.thrLockFlash.setValue(0);
		return;
	}
	
	if (FADEC.Lock.thrLockTime.getValue() + 5 < pts.Sim.Time.elapsedSec.getValue()) {
		FADEC.Lock.thrLockFlash.setValue(0);
		settimer(func() {
			FADEC.Lock.thrLockFlash.setValue(1);
			FADEC.Lock.thrLockTime.setValue(pts.Sim.Time.elapsedSec.getValue());
			ecam.athr_lock.noRepeat = 0;
			ecam.athr_lock.noRepeat2 = 0;
		}, 0.2);
	}
	
	state1 = systems.FADEC.detentText[0].getValue();
	state2 = systems.FADEC.detentText[1].getValue();
	
	if ((state1 != "CL" and state2 != "CL" and !systems.FADEC.engOut.getValue()) or (state1 != "MCT" and state2 != "MCT" and systems.FADEC.engOut.getValue())) {
		lockTimer2.stop();
		FADEC.Lock.thrLockCmd.setValue(0);
		FADEC.Lock.thrLockAlert.setValue(0);
		FADEC.Lock.thrLockFlash.setValue(0);
		FADEC.Lock.thrLockTime.setValue(0);
	}
}

var lockTimer = maketimer(0.1, checkLockThr);
var lockTimer2 = maketimer(0.1, checkLockThr2);