##########################################################
####### Single Starter/Generator electrical system #######
####################    Syd Adams    #####################
###### Based on Curtis Olson's nasal electrical code #####
##########################################################
##########################################################
######## Modified by Clement DE L'HAMAIDE for P92 ########
##########################################################
######## Modified by D-ECHO for CH750		  ########
##########################################################

# Based on information from http://www.aircraft-battery.com/search-by-your-aircraft/battery_detail/156 and http://www.zenithair.net/wp-content/uploads/stolch750/data/Draft%20POH%20STOL%20CH%20750-SLSA%20June%202009.pdf

var last_time = 0.0;
var OutPuts = props.globals.getNode("/systems/electrical/outputs",1);
var Volts = props.globals.getNode("/systems/electrical/volts",1);
var Amps = props.globals.getNode("/systems/electrical/amps",1);
var PWR = props.globals.getNode("systems/electrical/serviceable",1).getBoolValue();
var BATT = props.globals.getNode("/controls/engines/engine/master-bat",1);
var ALT = props.globals.getNode("/controls/engines/engine/master-alt",1);
var DIMMER = props.globals.getNode("/controls/lighting/instruments-norm",1);
var NORM = 0.0357;
var Battery={};
var Alternator={};
var load = 0.0;

var switches = props.globals.getNode("/controls/switches");
var cb = props.globals.getNode("/controls/circuit-breakers");

# Estimate electrical load:
# Landing Light: (based on https://aeroleds.com/products/sunspot-36lx-landing/): 45 Watts
# Navigation Lights and Strobe Lights based on https://aeroleds.com/wp-content/uploads/2018/02/0008-0006-Linear-Pulsar-NS-Series-Installation.pdf:
#	Navigation:	8.4 Watts (steady)			-> *2
#	Strobe:		70 Watts (during flash, 0.2 secs)	-> *2
#			11.2 Watts (average)			-> *2
# Fuel Pump: 50 Watts (complete guess)
var consumers_main = { 'landing-light':45, 'strobe-lights': 22.4, 'nav-lights': 16.8, 'fuel-pump': 50, };

var strobe = aircraft.light.new("/sim/model/lights/strobe-lights", [0.2, 1.25], "/systems/electrical/outputs/strobe-lights");

#var battery = Battery.new(volts,amps,amp_hours,charge_percent,charge_amps);

Battery = {
	new : func {
		m = { parents : [Battery] };
		m.ideal_volts = arg[0];
		m.ideal_amps = arg[1];
		m.amp_hours = arg[2];
		m.charge_percent = arg[3];
		m.charge_amps = arg[4];
		return m;
	},
	apply_load : func {
		var amphrs_used = arg[0] * (arg[1] / 3600.0);
		var percent_used = amphrs_used / me.amp_hours;
		me.charge_percent -= percent_used;
		if ( me.charge_percent < 0.0 ) {
			me.charge_percent = 0.0;
		} elsif ( me.charge_percent > 1.0 ) {
			me.charge_percent = 1.0;
		}
		return me.amp_hours * me.charge_percent;
	},
	get_output_volts : func {
		var x = 1.0 - me.charge_percent;
		var tmp = -(3.0 * x - 1.0);
		var factor = (tmp*tmp*tmp*tmp*tmp + 32) / 32;
		return me.ideal_volts * factor;
	},
	get_output_amps : func {
		var x = 1.0 - me.charge_percent;
		var tmp = -(3.0 * x - 1.0);
		var factor = (tmp*tmp*tmp*tmp*tmp + 32) / 32;
		return me.ideal_amps * factor;
	},	
	recharge : func {
		me.charge_percent = 1.0;
	},
};

# var alternator = Alternator.new("rpm-source",rpm_threshold,volts,amps);

Alternator = {
    new : func {
        m = { parents : [Alternator] };
        m.rpm_source =  props.globals.getNode(arg[0],1);
        m.rpm_threshold = arg[1];
        m.ideal_volts = arg[2];
        m.ideal_amps = arg[3];
        return m;
    },

    apply_load : func( amps, dt) {
        var factor = me.rpm_source.getValue() / me.rpm_threshold;
        if ( factor > 1.0 ){
            factor = 1.0;
        }
        var available_amps = me.ideal_amps * factor;
        return available_amps - amps;
    },

    get_output_volts : func {
        var factor = me.rpm_source.getValue() / me.rpm_threshold;
        if ( factor > 1.0 ) {
            factor = 1.0;
            }
        return me.ideal_volts * factor;
    },

    get_output_amps : func {
        var factor = me.rpm_source.getValue() / me.rpm_threshold;
        if ( factor > 1.0 ) {
            factor = 1.0;
        }
        return me.ideal_amps * factor;
    }
};

var battery = Battery.new(12.0, 20.0, 22.0, 1.0, 12.0);
var alternator = Alternator.new("/engines/engine[0]/rpm", 250.0, 14.0, 40.0);

setlistener("/sim/signals/fdm-initialized", func {
	foreach(var a; props.globals.getNode("/systems/electrical/outputs").getChildren()){
		a.setValue(0);
	}
	foreach(var a; switches.getChildren()){
		a.setBoolValue(0);
	}
	foreach(var a; cb.getChildren()){
		a.setBoolValue(1);
	}
	props.globals.getNode("/engines/engine/amp-v",1).setDoubleValue(0);
	props.globals.getNode("/controls/engines/engine/master-alt",1).setBoolValue(0);
	props.globals.getNode("/controls/engines/engine/master-bat",1).setBoolValue(0);
	settimer(update_electrical,1);
	print("Electrical System ... OK");
});

var bus_volts = 0.0;

var update_virtual_bus = func(dt) {
	var AltVolts = alternator.get_output_volts();
	var AltAmps = alternator.get_output_amps();
	var BatVolts = battery.get_output_volts();
	var BatAmps = battery.get_output_amps();
	var power_source = nil;

	if(PWR){									# Electrical System is serviceable
		if (ALT.getBoolValue() and (AltAmps > BatAmps)){
			bus_volts = AltVolts;
			power_source = "alternator";
			battery.apply_load(-battery.charge_amps, dt);			# Charge the battery
		}elsif (BATT.getBoolValue()){
			bus_volts = BatVolts;
			power_source = "battery";
			battery.apply_load(load, dt);	# Load in ampere
		}else {
			bus_volts = 0.0;
		}
	} else {									# Electrical System not serviceable
		bus_volts = 0.0;
	}

	load = 0.0;
	load += electrical_bus(bus_volts);
	load += avionics_bus(bus_volts);
	
	props.globals.getNode("/engines/engine/amp-v",1).setValue(bus_volts);		# TODO what does this affect?

	var bus_amps = 0.0;

	if (bus_volts > 1.0){
		if (power_source == "battery"){
			bus_amps = BatAmps-load;
		} else {
			bus_amps = battery.charge_amps;
		}
	}

	Amps.setValue(bus_amps);
	Volts.setValue(bus_volts);
	return load;
}

var electrical_bus = func(bus_volts){
	load = 0.0;

	foreach(var key; keys(consumers_main)){
		if(switches.getChild(key).getBoolValue() and cb.getChild(key).getBoolValue() ){
			OutPuts.getNode(key,1).setValue(bus_volts);
			if(bus_volts != 0){
				load += (consumers_main[key] / bus_volts);
			}
		} else {
			OutPuts.getNode(key,1).setValue(0.0);
		}
	}
	
	# Starter has about 900W power according to https://www.ulforum.de/ultraleicht/forum/2_technik-und-flugzeuge/2466_anlasser-rotax-912-uls/seite-4.html
	if (props.globals.getNode("/controls/engines/engine[0]/starter").getBoolValue()){
		OutPuts.getNode("starter",1).setValue(bus_volts);
		if(bus_volts != 0){
			load += (900 / bus_volts);
		}
	} else {
		OutPuts.getNode("starter",1).setValue(0.0);
	}

	return load;
}

var avionics_bus = func(bv) {
	
	load = 0.0;
	
	if(switches.getChild("radio-master").getBoolValue()){
		var bus_volts = bv;
		
		if (props.globals.getNode("/instrumentation/comm/serviceable").getBoolValue() and cb.getChild("radio1").getBoolValue() and cb.getChild("radio2").getBoolValue()){
			OutPuts.getNode("comm",1).setValue(bus_volts);
			load += 0.00015;
		} else {
			OutPuts.getNode("comm",1).setValue(0.0);
		}

		if (props.globals.getNode("instrumentation/transponder/serviceable").getValue() != 0 and cb.getChild("transponder").getBoolValue()){
			OutPuts.getNode("transponder",1).setValue(bus_volts);
			load += 0.00015;
		} else {
			OutPuts.getNode("transponder",1).setValue(0.0);
		}
		
		if (cb.getChild("efis1").getBoolValue() and cb.getChild("efis2").getBoolValue()){
			OutPuts.getNode("efis",1).setValue(bus_volts);
			load += 0.00015;
		} else {
			OutPuts.getNode("efis",1).setValue(0.0);
		}
	}else{
		var bus_volts = 0.0;
	}
	

	return load;
}

var update_electrical = func {
	var time = getprop("/sim/time/elapsed-sec");
	var dt = time - last_time;
	last_time = time;
	update_virtual_bus(dt);
	settimer(update_electrical, 0);
}
