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

;;;-------------------------------------------------------------------------;;;
;;;                             Global Trigger                              ;;;
;;;                                                                         ;;;
;;; Entry points for the surrounding script code. Typically, the rule       ;;;
;;; will be triggered by setting a target fact and call "produce()" on the  ;;;
;;; KnowledgeBase instance.                                                 ;;;
;;;-------------------------------------------------------------------------;;;

;;;-------------------------------------------------------------------------;;;
;;; This trigger must be called, after all dynamic setup rules have been    ;;;
;;; added to the rule set.                                                  ;;;
;;;-------------------------------------------------------------------------;;;

; [?Initialize] => ...


;;;-------------------------------------------------------------------------;;;
;;; Setting this trigger recalulates all setting values for the current     ;;;
;;; car characteristics.                                                    ;;;
;;;-------------------------------------------------------------------------;;;

; [?Calculate] => ...


priority: -5, [?Initialize] => (Clear: Initialize)


;;;-------------------------------------------------------------------------;;;
;;;                      Characteristics Initialization                     ;;;
;;;-------------------------------------------------------------------------;;;

priority: 5, {All: [?Initialize], {None: [?Characteristics.Count]}} => (Set: Characteristics.Count, 0)

addCharacteristics([])
addCharacteristics([?characteristic | ?characteristics]) <= addCharacteristic(?characteristic), addCharacteristics(?characteristics)

addCharacteristic(?characteristic) <= addCharacteristic(?characteristic, !Characteristics.Count)

addCharacteristic(?characteristic, ?index) <= ?next = ?index + 1, Set(Characteristic, ?next, ?characteristic), Set(Characteristics.Count, ?next)

allCharacteristics(?characteristics) <= allCharacteristics(?characteristics, !Characteristics.Count)

allCharacteristics([], 0)
allCharacteristics([?characteristic | ?characteristics], ?index) <= Get(Characteristic, ?index, ?characteristic), ?next = ?index - 1,
																	allCharacteristics(?characteristics, ?next)


;;;-------------------------------------------------------------------------;;;
;;;                         Settings Initialization                         ;;;
;;;-------------------------------------------------------------------------;;;

priority: 5, {All: [?Initialize], {None: [?Settings.Count]}} => (Set: Settings.Count, 0)

addSettings([])
addSettings([?setting | ?settings]) <= addSetting(?setting), addSettings(?settings)

addSetting(?setting) <= addSetting(?setting, !Settings.Count), Set(?setting, Delta, 0)

addSetting(?setting, ?index) <= ?next = ?index + 1, Set(Setting, ?next, ?setting), Set(Settings.Count, ?next)

allSettings(?settings) <= allSettings(?settings, !Settings.Count)

allSettings([], 0)
allSettings([?setting | ?settings], ?index) <= Get(Setting, ?index, ?setting), ?next = ?index - 1, allSettings(?settings, ?next)


;;;-------------------------------------------------------------------------;;;
;;;                         Simulator Configuration                         ;;;
;;;-------------------------------------------------------------------------;;;

priority: 5, [?Initialize] => (Set: Simulator.Count, 0), (Set: Workbench.Simulator, *), (Set: Workbench.Car, *), (Set: Workbench.Track, *)

addSimulator(?simulator) <= addSimulator(?simulator, !Simulator.Count)

addSimulator(?simulator, ?count) <= ?next = ?count + 1, Set(Simulator, ?next, ?simulator), Set(Simulator.Count, ?next)

addCharacteristics(?simulator, ?car, ?track, *) <= allCharacteristics(?characteristics),
												   addCharacteristics(?simulator, ?car, ?track, ?characteristics)
		
addCharacteristics(?, ?, ?, [])
addCharacteristics(?simulator, ?car, ?track, [?characteristic | ?characteristics]) <=
		addCharacteristic(?simulator, ?car, ?track, ?characteristic), addCharacteristics(?simulator, ?car, ?track, ?characteristics)

addCharacteristic(?simulator, ?car, ?track, ?characteristic) <= Set(?simulator, ?car, ?track, Characteristic, ?characteristic, Active, true)

removeCharacteristics(?simulator, ?car, ?track, *) <= allCharacteristics(?characteristics),
													  removeCharacteristics(?simulator, ?car, ?track, ?characteristics)
		
removeCharacteristics(?, ?, ?, [])
removeCharacteristics(?simulator, ?car, ?track, [?characteristic | ?characteristics]) <=
		removeCharacteristic(?simulator, ?car, ?track, ?characteristic), removeCharacteristics(?simulator, ?car, ?track, ?characteristics)

removeCharacteristic(?simulator, ?car, ?track, ?characteristic) <= Set(?simulator, ?car, ?track, Characteristic, ?characteristic, Active, false)

characteristicActive(?simulator, ?car, ?track, ?characteristic) <= characteristicActive(?simulator, ?car, ?track, ?characteristic, true)
characteristicActive(?, ?, ?, false) <= !
characteristicActive(?, ?, ?, ?) <= fail
																   
characteristicActive(?simulator, ?car, ?track, ?characteristic, ?active) <=
		Append(?simulator, ., ?car, ., ?track, .Characteristic., ?characteristic, .Active, ?fact), fact?(?fact), !, Get(?fact, ?active)
characteristicActive(?simulator, ?car, ?, ?characteristic, ?active) <=
		Append(?simulator, ., ?car, .*.Characteristic., ?characteristic, .Active, ?fact), fact?(?fact), !, Get(?fact, ?active)
characteristicActive(?simulator, ?, ?, ?characteristic, ?active) <=
		Append(?simulator, .*.*.Characteristic., ?characteristic, .Active, ?fact), fact?(?fact), !, Get(?fact, ?active)
characteristicActive(?, ?, ?, ?characteristic, ?active) <=
		Append(*.*.*.Characteristic., ?characteristic, .Active, ?fact), fact?(?fact), !, Get(?fact, ?active)
characteristicActive(?, ?, ?, ?, false)

addSettings(?simulator, ?car, *) <= allSettings(?settings), addSettings(?simulator, ?car, ?settings)
		
addSettings(?, ?, [])
addSettings(?simulator, ?car, [?setting | ?settings]) <=
		addSetting(?simulator, ?car, ?setting), addSettings(?simulator, ?car, ?settings)

addSetting(?simulator, ?car, ?setting) <= Set(?simulator, ?car, Setting, ?setting, Available, true)

removeSettings(?simulator, ?car, *) <= allSettings(?settings), removeSettings(?simulator, ?car, ?settings)

removeSettings(?, ?, [])
removeSettings(?simulator, ?car, [?setting | ?settings]) <=
		removeSetting(?simulator, ?car, ?setting), removeSettings(?simulator, ?car, ?settings)

removeSetting(?simulator, ?car, ?setting) <= Set(?simulator, ?car, Setting, ?setting, Available, false)

settingAvailable(?simulator, ?car, ?setting) <= settingAvailable(?simulator, ?car, ?setting, true)
settingAvailable(?, ?, false) <= !
settingAvailable(?, ?, ?) <= fail

settingAvailable(?simulator, ?car, ?setting, ?available) <=
		Append(?simulator, ., ?car, .Setting., ?setting, .Available, ?fact), fact?(?fact), !, Get(?fact, ?available)
settingAvailable(?simulator, ?car, ?setting, ?available) <=
		Append(?simulator, ., ?car, .Setting., ?setting, .Available, ?fact), fact?(?fact), !, Get(?fact, ?available)
settingAvailable(?simulator, ?, ?setting, ?available) <=
		Append(?simulator, .*.Setting., ?setting, .Available, ?fact), fact?(?fact), !, Get(?fact, ?available)
settingAvailable(?, ?, ?setting, ?available) <=
		Append(*.*.*.Setting., ?setting, .Available, ?fact), fact?(?fact), !, Get(?fact, ?available)
settingAvailable(?, ?, ?, ?, false)


;;;-------------------------------------------------------------------------;;;
;;;                           Settings Calculation                          ;;;
;;;-------------------------------------------------------------------------;;;

priority: 5, [?Calculate] => (Prove: resetSettings()), (Prove: resetCharacteristics())
[?Calculate] => (Prove: updateCharacteristics()), (Prove: calculateSettings()), (Prove: balanceSettings())
priority: -5, [?Calculate] => (Clear: Calculate)

resetSettings() <= resetSettings(!Settings.Count)

resetSettings(0) <= !
resetSettings(?index) <= Get(Setting, ?index, ?setting), Set(?setting, Delta, 0), ?nIndex = ?index - 1, resetSettings(?nIndex)

resetCharacteristics() <= resetCharacteristics(!Characteristics.Count)

resetCharacteristics(0) <= !
resetCharacteristics(?index) <= Get(Characteristic, ?index, ?characteristic), Set(?characteristic, Correction, 0),
									?nIndex = ?index - 1, resetCharacteristics(?nIndex)

updateCharacteristics() <= updateCharacteristics(!Workbench.Simulator, !Workbench.Car, !Workbench.Track, !Characteristics.Count)

updateCharacteristics(?, ?, ?, 0) <= !
updateCharacteristics(?simulator, ?car, ?track, ?index) <=
		Get(Characteristic, ?index, ?characteristic), updateCharacteristic(?simulator, ?car, ?track, ?characteristic),
		?nIndex = ?index - 1, updateCharacteristics(?simulator, ?car, ?track, ?nIndex)

updateCharacteristic(?simulator, ?car, ?track, ?characteristic) <=
		characteristicActive(?simulator, ?car, ?track, ?characteristic),
		Get(?characteristic, Weight, ?weight), Get(?characteristic, Value, ?value), !,
		?factor = ?weight / 100, ?correction = ?value * ?factor, ?nCorrection = ?correction / 100,
		Set(?characteristic, Correction, ?nCorrection)
updateCharacteristic(?simulator, ?car, ?track, ?characteristic) <= Set(?characteristic, Correction, 0)

changeSetting(?, [], ?, ?)
changeSetting(?setting, [?suffix | ?suffixes], ?increment, ?correction) <=
		Append(?setting, ., ?suffix, ?name), changeSetting(?name, ?increment, ?correction),
		changeSetting(?setting, ?suffixes, ?increment, ?correction)
		
changeSetting(?setting, ?increment, ?correction) <= Get(?setting, Delta, ?delta), ?value = ?increment * ?correction,
													combineDelta(?value, ?delta, ?nDelta), Set(?setting, Delta, ?nDelta)

combineDelta(0, ?delta, ?delta)
combineDelta(?delta, 0, ?delta)
combineDelta(?delta1, ?delta2, ?delta) <= ?delta1 < 0, ?delta2 < 0, !, min(?delta1, ?delta2, ?delta)
combineDelta(?delta1, ?delta2, ?delta) <= ?delta1 > 0, ?delta2 > 0, !, max(?delta1, ?delta2, ?delta)
combineDelta(?delta1, ?delta2, ?delta) <= ?delta = ?delta1 + ?delta2


;;;-------------------------------------------------------------------------;;;
;;;                               Utility Rules                             ;;;
;;;-------------------------------------------------------------------------;;;

max(?x, ?y, ?x) <= ?x > ?y, !
max(?x, ?y, ?y)

min(?x, ?y, ?x) <= ?x < ?y, !
min(?x, ?y, ?y)

fact?(?f) <= Get(?f, ?)

bound?(?x) <= unbound?(?x), !, fail
bound?(?)