;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;   Modular Simulator Controller System - Standings Computations          ;;;
;;;                                                                         ;;;
;;;   Author:     Oliver Juwig (TheBigO)                                    ;;;
;;;   License:    (2026) Creative Commons - BY-NC-SA                        ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;-------------------------------------------------------------------------;;;
;;;                            Rule Include Section                         ;;;
;;;-------------------------------------------------------------------------;;;

#Include %kResourcesDirectory%Rules\Lap Information Retrieval.rules
#Include %kResourcesDirectory%Rules\Car Information Retrieval.rules


;;;-------------------------------------------------------------------------;;;
;;;                            Public Rules Section                         ;;;
;;;-------------------------------------------------------------------------;;;

priority: 5, {Any: [?Lap], [?Sector], [?Standings]} =>
		(Clear: Position.Standings.Overall.Ahead.Car), (Clear: Position.Standings.Overall.Ahead.Distance),
		(Clear: Position.Standings.Overall.Ahead.Delta),
		(Clear: Position.Standings.Overall.Behind.Car), (Clear: Position.Standings.Overall.Behind.Distance),
		(Clear: Position.Standings.Overall.Behind.Delta),
		(Clear: Position.Standings.Overall.Leader.Car), (Clear: Position.Standings.Overall.Leader.Distance),
		(Clear: Position.Standings.Overall.Leader.Delta),
		(Clear: Position.Standings.Class.Ahead.Car), (Clear: Position.Standings.Class.Ahead.Distance),
		(Clear: Position.Standings.Class.Ahead.Delta),
		(Clear: Position.Standings.Class.Behind.Car), (Clear: Position.Standings.Class.Behind.Distance),
		(Clear: Position.Standings.Class.Behind.Delta),
		(Clear: Position.Standings.Class.Leader.Car), (Clear: Position.Standings.Class.Leader.Distance),
		(Clear: Position.Standings.Class.Leader.Delta),
		(Clear: Position.Track.Ahead.Car), (Clear: Position.Track.Ahead.Distance), (Clear: Position.Track.Ahead.Delta),
		(Clear: Position.Track.Behind.Car), (Clear: Position.Track.Behind.Distance), (Clear: Position.Track.Behind.Delta)
{Any: [?Lap], [?Sector], [?Standings]} => (Prove: updateGrid(?Lap)), (Prove: updatePositions(?Lap)),
										  (Prove: updateTrackAhead(?Lap)), (Prove: updateTrackBehind(?Lap))
priority: -5, [?Standings] => (Clear: Standings)

updateGrid(?lap) <= Set(Standings.Lap, ?lap, Weather, !Weather.Weather.Now),
					:%getTime%=(?time), Set(Standings.Lap, ?lap, Time, ?time),
					Set(Standings.Lap, ?lap, Car.Count, !Car.Count), updateGrid(?lap, !Car.Count)

updateGrid(?, ?car) <= ?car =< 0, !
updateGrid(?lap, ?car) <= carDriverForname(?car, ?forname), carDriverSurname(?car, ?surname),
						  carDriverNickname(?car, ?nickname), carDriverCategory(?car, ?category),
						  carNumber(?car, ?carNumber), carID(?car, ?carID),
						  Append(Standings.Lap., ?lap, .Car., ?car, ?prefix),
						  Set(?prefix, Nr, ?carNumber), Set(?prefix, ID, ?carID),
						  Set(?prefix, Driver.Forname, ?forname), Set(?prefix, Driver.Surname, ?surname),
						  Set(?prefix, Driver.Nickname, ?nickname), Set(?prefix, Driver.Category, ?category),
						  ?nextCar = ?car - 1, updateGrid(?lap, ?nextCar)

updatePositions(?lap) <= carLaps(!Driver.Car, FULL, ?driverLaps), carLaps(!Driver.Car, RUNNING, ?driverRunning),
						 updatePositions(?lap, !Car.Count, ?driverLaps, ?driverRunning)

updatePositions(?, ?car, ?, ?) <= ?car =< 0, !
updatePositions(?lap, !Driver.Car, ?driverLaps, ?driverRunning) <=
		carLapTime(!Driver.Car, ?lapTime), carSectorsTime(!Driver.Car, ?sectorTimes), carPosition(!Driver.Car, ?position),
		Set(Position, ?position), Set(Standings.Lap, ?lap, Position, ?position),
		Append(Standings.Lap., ?lap, .Car., !Driver.Car, ?prefix),
		Set(?prefix, Time, ?lapTime), Set(?prefix, Time.Sectors, ?sectorTimes),
		Set(?prefix, Delta, 0), Set(?prefix, Laps, ?driverLaps), Set(?prefix, Position, ?position),
		carClass(!Driver.Car, ?class),
		updateStandingsClassLeader(?class, ?lap, !Driver.Car, 0, 0), updateStandingsOverallLeader(?lap, !Driver.Car, 0, 0), !,
		?nextCar = !Driver.Car - 1, updatePositions(?lap, ?nextCar, ?driverLaps, ?driverRunning)
updatePositions(?lap, ?car, ?driverLaps, ?driverRunning) <=
		carLaps(?car, FULL, ?carLaps), ?carLaps > 1, carLaps(?car, RUNNING, ?carRunning),
		?car != !Driver.Car, carLapTime(?car, ?carLapTime), carSectorsTime(?car, ?carSectorTimes),
		lapTime(?lap, ?lapTime), carPosition(?car, ?position),
		?standingsDistance = ?carLaps - ?driverLaps, ?standingsDelta = ?lapTime * ?standingsDistance,
		Append(Standings.Lap., ?lap, .Car., ?car, ?prefix),
		Set(?prefix, Time, ?carLapTime), Set(?prefix, Time.Sectors, ?carSectorTimes),
		Set(?prefix, Delta, ?standingsDelta), Set(?prefix, Laps, ?carLaps), Set(?prefix, Position, ?position),
		carClass(!Driver.Car, ?class), updateStandings(?class, ?lap, ?car, ?standingsDistance, ?standingsDelta),
		?trackDistance = ?driverRunning - ?carRunning, ?temp = ?lapTime * ?trackDistance, ?trackDelta = ?temp * -1,
		updateTrack(?lap, ?car, ?trackDistance, ?trackDelta), !,
		?nextCar = ?car - 1, updatePositions(?lap, ?nextCar, ?driverLaps, ?driverRunning)
updatePositions(?lap, ?car, ?driverLaps, ?driverRunning) <=
		carLaps(?car, FULL, ?carLaps), ?carLaps =< 1, ?car != !Driver.Car,
		carLapTime(?car, ?carLapTime), carSectorsTime(?car, ?carSectorTimes),
		lapTime(?lap, ?lapTime), carPosition(?car, ?position),
		?standingsDistance = ?carLaps - ?driverLaps, ?standingsDelta = ?lapTime * ?standingsDistance,
		Append(Standings.Lap., ?lap, .Car., ?car, ?prefix),
		Set(?prefix, Time, ?carLapTime), Set(?prefix, Time.Sectors, ?carSectorTimes),
		Set(?prefix, Delta, ?standingsDelta), Set(?prefix, Laps, ?carLaps), Set(?prefix, Position, ?position), !,
		?nextCar = ?car - 1, updatePositions(?lap, ?nextCar, ?driverLaps, ?driverRunning)
updatePositions(?lap, ?car, ?driverLaps, ?driverRunning) <= ?nextCar = ?car - 1, updatePositions(?lap, ?nextCar, ?driverLaps, ?driverRunning)

updateStandings(?class, ?lap, ?car, ?standingsDistance, ?standingsDelta) <=
		updateStandingsClassAhead(?class, ?lap, ?car, ?standingsDistance, ?standingsDelta),
		updateStandingsClassBehind(?class, ?lap, ?car, ?standingsDistance, ?standingsDelta),
		updateStandingsClassLeader(?class, ?lap, ?car, ?standingsDistance, ?standingsDelta),
		updateStandingsOverallAhead(?lap, ?car, ?standingsDistance, ?standingsDelta),
		updateStandingsOverallBehind(?lap, ?car, ?standingsDistance, ?standingsDelta),
		updateStandingsOverallLeader(?lap, ?car, ?standingsDistance, ?standingsDelta), !
updateStandings(?, ?, ?, ?, ?)

updateTrack(?lap, ?car, ?trackDistance, ?trackDelta) <=
	updateTrackAhead(?lap, ?car, ?trackDistance, ?trackDelta), updateTrackBehind(?lap, ?car, ?trackDistance, ?trackDelta), !
updateTrack(?, ?, ?, ?)

updateStandingsOverallAhead(?, ?car, ?distance, ?delta) <= ?delta > 0, unbound?(!Position.Standings.Overall.Ahead.Car), !,
														   Set(Position.Standings.Overall.Ahead.Car, ?car),
														   Set(Position.Standings.Overall.Ahead.Distance, ?distance),
														   Set(Position.Standings.Overall.Ahead.Delta, ?delta)
updateStandingsOverallAhead(?, ?car, ?distance, ?delta) <= ?delta > 0,
														   Get(Position.Standings.Overall.Ahead.Delta, ?curDelta), ?delta < ?curDelta, !,
														   Set(Position.Standings.Overall.Ahead.Car, ?car),
														   Set(Position.Standings.Overall.Ahead.Distance, ?distance),
														   Set(Position.Standings.Overall.Ahead.Delta, ?delta)
updateStandingsOverallAhead(?, ?, ?, ?)

updateStandingsOverallBehind(?, ?car, ?distance, ?delta) <= ?delta < 0, unbound?(!Position.Standings.Overall.Behind.Car), !,
															Set(Position.Standings.Overall.Behind.Car, ?car),
															Set(Position.Standings.Overall.Behind.Distance, ?distance),
															Set(Position.Standings.Overall.Behind.Delta, ?delta)
updateStandingsOverallBehind(?, ?car, ?distance, ?delta) <= ?delta < 0,
															Get(Position.Standings.Overall.Behind.Delta, ?curDelta), ?delta > ?curDelta, !,
															Set(Position.Standings.Overall.Behind.Car, ?car),
															Set(Position.Standings.Overall.Behind.Distance, ?distance),
															Set(Position.Standings.Overall.Behind.Delta, ?delta)
updateStandingsOverallBehind(?, ?, ?, ?)

updateStandingsOverallLeader(?, ?car, ?distance, ?delta) <= carPosition(?car, 1), !,
															Set(Position.Standings.Overall.Leader.Car, ?car),
															Set(Position.Standings.Overall.Leader.Distance, ?distance),
															Set(Position.Standings.Overall.Leader.Delta, ?delta)
updateStandingsOverallLeader(?, ?, ?, ?)

updateStandingsClassAhead(?class, ?, ?car, ?distance, ?delta) <= carClass(?car, ?class),
																 unbound?(!Position.Standings.Class.Ahead.Car), ?delta > 0, !,
																 Set(Position.Standings.Class.Ahead.Car, ?car),
																 Set(Position.Standings.Class.Ahead.Distance, ?distance),
																 Set(Position.Standings.Class.Ahead.Delta, ?delta)
updateStandingsClassAhead(?class, ?, ?car, ?distance, ?delta) <= carClass(?car, ?class), ?delta > 0,
																 Get(Position.Standings.Class.Ahead.Delta, ?curDelta), ?delta < ?curDelta, !,
																 Set(Position.Standings.Class.Ahead.Car, ?car),
																 Set(Position.Standings.Class.Ahead.Distance, ?distance),
																 Set(Position.Standings.Class.Ahead.Delta, ?delta)
updateStandingsClassAhead(?, ?, ?, ?, ?)

updateStandingsClassBehind(?class, ?, ?car, ?distance, ?delta) <= carClass(?car, ?class),
																  unbound?(!Position.Standings.Class.Behind.Car), ?delta < 0, !,
																  Set(Position.Standings.Class.Behind.Car, ?car),
																  Set(Position.Standings.Class.Behind.Distance, ?distance),
																  Set(Position.Standings.Class.Behind.Delta, ?delta)
updateStandingsClassBehind(?class, ?, ?car, ?distance, ?delta) <= carClass(?car, ?class), ?delta < 0,
																  Get(Position.Standings.Class.Behind.Delta, ?curDelta), ?delta > ?curDelta, !,
																  Set(Position.Standings.Class.Behind.Car, ?car),
																  Set(Position.Standings.Class.Behind.Distance, ?distance),
																  Set(Position.Standings.Class.Behind.Delta, ?delta)
updateStandingsClassBehind(?, ?, ?, ?, ?)

updateStandingsClassLeader(?class, ?, ?car, ?distance, ?delta) <= carClass(?car, ?class), unbound?(!Position.Standings.Class.Leader.Car), !,
																  Set(Position.Standings.Class.Leader.Car, ?car),
																  Set(Position.Standings.Class.Leader.Distance, ?distance),
																  Set(Position.Standings.Class.Leader.Delta, ?delta)
updateStandingsClassLeader(?class, ?, ?car, ?distance, ?delta) <= carClass(?car, ?class), bound?(!Position.Standings.Class.Leader.Car),
																  carPosition(?car, ?carPosition),
																  carPosition(!Position.Standings.Class.Leader.Car, ?leaderPosition),
																  ?carPosition < ?leaderPosition, !,
																  Set(Position.Standings.Class.Leader.Car, ?car),
																  Set(Position.Standings.Class.Leader.Distance, ?distance),
																  Set(Position.Standings.Class.Leader.Delta, ?delta)
updateStandingsClassLeader(?, ?, ?, ?, ?)
						
updateTrackAhead(?, ?car, ?distance, ?delta) <= ?distance < 0, unbound?(!Position.Track.Ahead.Car), !, Set(Position.Track.Ahead.Car, ?car),
												Set(Position.Track.Ahead.Distance, ?distance), Set(Position.Track.Ahead.Delta, ?delta)
updateTrackAhead(?, ?car, ?distance, ?delta) <= ?distance < 0, Get(Position.Track.Ahead.Distance, ?curDistance), ?distance > ?curDistance,
												Set(Position.Track.Ahead.Car, ?car), Set(Position.Track.Ahead.Distance, ?distance),
												Set(Position.Track.Ahead.Delta, ?delta)
updateTrackAhead(?, ?, ?, ?)

updateTrackAhead(?) <= bound?(!Position.Track.Ahead.Car), !
updateTrackAhead(?lap) <= carLaps(!Driver.Car, RUNNING, ?running), ?remaining = 1 - ?running, updateTrackAhead(?lap, ?remaining, !Car.Count)
		
updateTrackAhead(?, ?, ?car) <= ?car =< 0, !
updateTrackAhead(?lap, ?driverRemaining, !Driver.Car) <= ?nextCar = !Driver.Car - 1, updateTrackAhead(?lap, ?driverRemaining, ?nextCar), !
updateTrackAhead(?lap, ?driverRemaining, ?car) <=
		unbound?(!Position.Track.Ahead.Car), carLaps(?car, RUNNING, ?carRunning), lapTime(?lap, ?lapTime),
		?distance = ?driverRemaining + ?carRunning, ?trackDistance = ?distance * -1, ?trackDelta = ?lapTime * ?distance,
		Set(Position.Track.Ahead.Car, ?car), Set(Position.Track.Ahead.Distance, ?trackDistance),
		Set(Position.Track.Ahead.Delta, ?trackDelta), !,
		?nextCar = ?car - 1, updateTrackAhead(?lap, ?driverRemaining, ?nextCar)
updateTrackAhead(?lap, ?driverRemaining, ?car) <=
		carLaps(?car, RUNNING, ?carRunning), lapTime(?lap, ?lapTime),
		?distance = ?driverRemaining + ?carRunning, ?trackDistance = ?distance * -1,
		Get(Position.Track.Ahead.Distance, ?curDistance), ?trackDistance > ?curDistance,
		?trackDelta = ?lapTime * ?distance,
		Set(Position.Track.Ahead.Car, ?car), Set(Position.Track.Ahead.Distance, ?trackDistance),
		Set(Position.Track.Ahead.Delta, ?trackDelta), !,
		?nextCar = ?car - 1, updateTrackAhead(?lap, ?driverRemaining, ?nextCar)
updateTrackAhead(?lap, ?driverRemaining, ?car) <= ?nextCar = ?car - 1, updateTrackAhead(?lap, ?driverRemaining, ?nextCar)

updateTrackBehind(?, ?car, ?distance, ?delta) <= ?distance > 0, unbound?(!Position.Track.Behind.Car), !, Set(Position.Track.Behind.Car, ?car),
												 Set(Position.Track.Behind.Distance, ?distance), Set(Position.Track.Behind.Delta, ?delta)
updateTrackBehind(?, ?car, ?distance, ?delta) <= ?distance > 0, Get(Position.Track.Behind.Distance, ?curDistance), ?distance < ?curDistance,
												 Set(Position.Track.Behind.Car, ?car), Set(Position.Track.Behind.Distance, ?distance),
												 Set(Position.Track.Behind.Delta, ?delta)
updateTrackBehind(?, ?, ?, ?)

updateTrackBehind(?) <= bound?(!Position.Track.Behind.Car), !
updateTrackBehind(?lap) <= carLaps(!Driver.Car, RUNNING, ?running), updateTrackBehind(?lap, ?running, !Car.Count)

updateTrackBehind(?, ?, ?car) <= ?car =< 0, !
updateTrackBehind(?lap, ?driverRunning, !Driver.Car) <= ?nextCar = !Driver.Car - 1, updateTrackBehind(?lap, ?driverRunning, ?nextCar), !
updateTrackBehind(?lap, ?driverRunning, ?car) <=
		unbound?(!Position.Track.Behind.Car), carLaps(?car, RUNNING, ?carRunning), lapTime(?lap, ?lapTime),
		?remaining = 1 - ?carRunning, ?trackDistance = ?remaining + ?driverRunning,
		?temp = ?trackDistance * -1, ?trackDelta = ?lapTime * ?temp,
		Set(Position.Track.Behind.Car, ?car), Set(Position.Track.Behind.Distance, ?trackDistance),
		Set(Position.Track.Behind.Delta, ?trackDelta), !,
		?nextCar = ?car - 1, updateTrackBehind(?lap, ?driverRunning, ?nextCar)
updateTrackBehind(?lap, ?driverRunning, ?car) <=
		carLaps(?car, RUNNING, ?carRunning), lapTime(?lap, ?lapTime),
		?remaining = 1 - ?carRunning, ?trackDistance = ?remaining + ?driverRunning,
		Get(Position.Track.Behind.Distance, ?curDistance), ?trackDistance < ?curDistance,
		?temp = ?trackDistance * -1, ?trackDelta = ?lapTime * ?temp,
		Set(Position.Track.Behind.Car, ?car), Set(Position.Track.Behind.Distance, ?trackDistance),
		Set(Position.Track.Behind.Delta, ?trackDelta), !,
		?nextCar = ?car - 1, updateTrackBehind(?lap, ?driverRunning, ?nextCar)
updateTrackBehind(?lap, ?driverRunning, ?car) <= ?nextCar = ?car - 1, updateTrackBehind(?lap, ?driverRunning, ?nextCar)
