#According to https://flarm.com/de/produkte/powerflarm/ range is 3km

#Set variables
var max_dist=3;
running=0;

var prop_base = "instrumentation/FLARM/";
var nc_prop = prop_base~"sound/new-contact";
var warn_prop = props.globals.getNode("instrumentation/FLARM/sound/warn", 1);

var volts = props.globals.getNode("/systems/electrical/outputs/flarm", 1);

var targets=[];
var warnings=[];

#Set properties
for(var f=0; f<=30; f=f+1){
	setprop(prop_base~"targets-tracked/mp["~f~"]", 0);
	append(targets, nil);
	append(warnings, nil);
}

var relative = func (brg, heading) {
	brg=brg-heading;
	return geo.normdeg(brg);
}

var new_contact = func ()  { #Sound message for new contact
	if(getprop(nc_prop) == 1){
		setprop(nc_prop, 0);
	}else{
		setprop(nc_prop, 1);
	}
}

#var target1 = Target.new(n,scnd);
var Target = {
	new : func(n,scnd){
		m = { parents : [Target] };
		m.id=n;
		m.pos = geo.Coord.new().set_latlon(	getprop("/ai/models/multiplayer["~n~"]/position/latitude-deg"),
							getprop("/ai/models/multiplayer["~n~"]/position/longitude-deg"),
							getprop("/ai/models/multiplayer["~n~"]/position/altitude-ft"));
		m.second=0.0;
		var ac = geo.aircraft_position();
		m.last_dist=m.pos.direct_distance_to(ac);
		new_contact();
		return m;
	},
    
	update_data : func(){
		me.pos.set_latlon(	getprop("/ai/models/multiplayer["~me.id~"]/position/latitude-deg"),
					getprop("/ai/models/multiplayer["~me.id~"]/position/longitude-deg"),
					getprop("/ai/models/multiplayer["~me.id~"]/position/altitude-ft"));
	},
    
	update_LED : func(second) {
		var ac = geo.aircraft_position();
		#Time difference
		var delta_time=second-me.second;
		me.second=second;
		var actual_dist_now=me.pos.direct_distance_to(ac);
		
		#Closure rate
		var delta_dist=(me.last_dist-actual_dist_now)/delta_time;
		
		#(Theoretical) time to collision
		if(delta_dist==0){
			ttc=999;
		}else{
			var ttc=actual_dist_now/delta_dist;
		}
		
		if(ttc<=0){
			ttc=999;
		}
		
		var LED=[0,0,0,0,0,0,0,0,0,0,0,0];
		
		var bearing = ac.course_to(me.pos);
		var relative_bearing=relative(bearing,getprop("/orientation/heading-deg"));
		
		var alt_diff=math.abs((me.pos.alt()*FT2M) - ac.alt()); #Altitude difference in meters
		
		if(ttc<6 and alt_diff < 150){
			#Warn 1: all LEDs red
			warnings[me.id]=2;
			forindex(var key; LED){
				LED[key]=2;
			}
		}else if(ttc<14 and alt_diff < 300){
			#Warn 2: corresponding LED red
			warnings[me.id]=1;
			LED[int(relative_bearing/30+1)-1] = 2;
		}else{
			#Normal: corresponding LED green
			warnings[me.id]=0;
			LED[int(relative_bearing/30+1)-1] = 1;
		}
		
		me.last_dist=actual_dist_now;
		
		return LED;
	},
	update_ub : func(){
		var ac = geo.aircraft_position();
		var alt_diff=(me.pos.alt()*FT2M)-ac.alt(); #Altitude difference in meters
		var distance = ac.distance_to(me.pos);
		var angle=(math.atan(alt_diff/distance))*R2D;
		return angle;
	},
	get_distance : func() {
		return me.pos.alt();
	},
};


setlistener("/sim/signals/fdm-initialized", func{
	settimer(update_FLARM, 5);
});


var update_FLARM = func{
	for(var f=0; f<=30; f=f+1){
		if(getprop("/ai/models/multiplayer["~f~"]/position/latitude-deg") != nil){
			var temp_pos = geo.Coord.set_latlon(	getprop("/ai/models/multiplayer["~f~"]/position/latitude-deg"),
								getprop("/ai/models/multiplayer["~f~"]/position/longitude-deg"),
								getprop("/ai/models/multiplayer["~f~"]/position/altitude-ft"));
							
			#Check whether in range and target not already existing
			var distance_km = temp_pos.distance_to(geo.aircraft_position())/1000;
			if(distance_km<max_dist and getprop("/instrumentation/FLARM/targets-tracked/mp["~f~"]")==0){
				#Now generate a target
				var scnd=getprop("/sim/time/elapsed-sec") or 0;
				targets[f]=Target.new(f,scnd);
				setprop("/instrumentation/FLARM/targets-tracked/mp["~f~"]", 1);
			}else if(distance_km>max_dist and getprop("/instrumentation/FLARM/targets-tracked/mp["~f~"]")==1){
				#Target existing, but has moved meanwhile out of range
				targets[f]=nil;
				setprop("/instrumentation/FLARM/targets-tracked/mp["~f~"]", 0);
			}
		}else if(getprop("/instrumentation/FLARM/targets-tracked/mp["~f~"]")==1){
			#Target existing, but has meanwhile logged out
			targets[f]=nil;
			setprop("/instrumentation/FLARM/targets-tracked/mp["~f~"]", 0);
		}
	}
	
	receive=0;
	
	forindex(var key; targets){
		if(targets[key]!=nil){
			targets[key].update_data();
			receive=1;
		}
	}
	
	setprop("/instrumentation/FLARM/receive-internal", receive);
	
	
	
	#Check LEDs
	#12 LEDS, each cover 30 degrees	
	
	heading=getprop("/orientation/heading-deg") or 0;
	var altitude=getprop("/position/altitude-ft") or 0;
	
	var stored_distance=9999;
	var used_angle=nil;
	var LEDs=[0,0,0,0,0,0,0,0,0,0,0,0];
	forindex(var key; targets){
		if(targets[key]!=nil){
			var LED=targets[key].update_LED(getprop("/sim/time/elapsed-sec"));
			forindex(var f; LED){
				if(LED[f]==1){
					LEDs[f]=1;
				}else if(LED[f]==2){
					LEDs[f]=2;
				}
			}
			var angle=targets[key].update_ub();
			var distance=targets[key].get_distance();
			if(distance<stored_distance){
				used_angle=angle;
				stored_distance=distance;
			}
			
		}
	}
	if(used_angle!=nil){
		if(used_angle>14){
			setprop("/instrumentation/FLARM/ub-LED1", 1);
			setprop("/instrumentation/FLARM/ub-LED2", 0);
			setprop("/instrumentation/FLARM/ub-LED3", 0);
			setprop("/instrumentation/FLARM/ub-LED4", 0);
		}else if(used_angle>7){
			setprop("/instrumentation/FLARM/ub-LED1", 0);
			setprop("/instrumentation/FLARM/ub-LED2", 1);
			setprop("/instrumentation/FLARM/ub-LED3", 0);
			setprop("/instrumentation/FLARM/ub-LED4", 0);
		}else if(used_angle<-14){
			setprop("/instrumentation/FLARM/ub-LED1", 0);
			setprop("/instrumentation/FLARM/ub-LED2", 0);
			setprop("/instrumentation/FLARM/ub-LED3", 0);
			setprop("/instrumentation/FLARM/ub-LED4", 1);
		}else if(used_angle<-7){
			setprop("/instrumentation/FLARM/ub-LED1", 0);
			setprop("/instrumentation/FLARM/ub-LED2", 0);
			setprop("/instrumentation/FLARM/ub-LED3", 1);
			setprop("/instrumentation/FLARM/ub-LED4", 0);
		}else{
			setprop("/instrumentation/FLARM/ub-LED1", 0);
			setprop("/instrumentation/FLARM/ub-LED2", 0);
			setprop("/instrumentation/FLARM/ub-LED3", 0);
			setprop("/instrumentation/FLARM/ub-LED4", 0);
		}
	}else{
		setprop("/instrumentation/FLARM/ub-LED1", 0);
		setprop("/instrumentation/FLARM/ub-LED2", 0);
		setprop("/instrumentation/FLARM/ub-LED3", 0);
		setprop("/instrumentation/FLARM/ub-LED4", 0);
	}
	
	forindex(var key; LEDs){
		var a=key+1;
		if(LEDs[key]<=1){
			setprop("/instrumentation/FLARM/LED"~a~"", LEDs[key]);
			setprop("/instrumentation/FLARM/LED"~a~"-red", 0);
		}else if(LEDs[key]==2){
			setprop("/instrumentation/FLARM/LED"~a~"", 0);
			setprop("/instrumentation/FLARM/LED"~a~"-red", 1);
		}
			
	}
	
	#Check Warning sounds
	warn=0;
	forindex(var key; warnings){
		if(warnings[key]==2 and warn<2){
			warn=2;
		}else if(warnings[key]==1 and warn<1){
			warn=1;
		}
	}
	warn_prop.setValue(warn);
	
	
	
	if((getprop("/systems/electrical/outputs/flarm") or 0)>9){
		settimer(update_FLARM, 1.0);
		running=1;
	}else{
		running=0;
		setprop("/instrumentation/FLARM/LED1", 0);
		setprop("/instrumentation/FLARM/LED2", 0);
		setprop("/instrumentation/FLARM/LED3", 0);
		setprop("/instrumentation/FLARM/LED4", 0);
		setprop("/instrumentation/FLARM/LED5", 0);
		setprop("/instrumentation/FLARM/LED6", 0);
		setprop("/instrumentation/FLARM/LED7", 0);
		setprop("/instrumentation/FLARM/LED8", 0);
		setprop("/instrumentation/FLARM/LED9", 0);
		setprop("/instrumentation/FLARM/LED10", 0);
		setprop("/instrumentation/FLARM/LED11", 0);
		setprop("/instrumentation/FLARM/LED12", 0);
		setprop("/instrumentation/FLARM/LED1-red", 0);
		setprop("/instrumentation/FLARM/LED2-red", 0);
		setprop("/instrumentation/FLARM/LED3-red", 0);
		setprop("/instrumentation/FLARM/LED4-red", 0);
		setprop("/instrumentation/FLARM/LED5-red", 0);
		setprop("/instrumentation/FLARM/LED6-red", 0);
		setprop("/instrumentation/FLARM/LED7-red", 0);
		setprop("/instrumentation/FLARM/LED8-red", 0);
		setprop("/instrumentation/FLARM/LED9-red", 0);
		setprop("/instrumentation/FLARM/LED10-red", 0);
		setprop("/instrumentation/FLARM/LED11-red", 0);
		setprop("/instrumentation/FLARM/LED12-red", 0);
		setprop("/instrumentation/FLARM/ub-LED1", 0);
		setprop("/instrumentation/FLARM/ub-LED2", 0);
		setprop("/instrumentation/FLARM/ub-LED3", 0);
		setprop("/instrumentation/FLARM/ub-LED4", 0);
	}
}

setlistener("/systems/electrical/outputs/flarm", func{
	if((getprop("/systems/electrical/outputs/flarm") or 0)>9 and running==0){
		settimer(update_FLARM, 1);
		running=1;
	}
});
