
## Sjekk at combos.ini lagres med rett format



#Libraries
import ac
import acsys
import os
import sys
import configparser
import traceback
import csv

Version="5.3.1"

#Variable initialization - FFBCLIP
Histogram = []
ffbMultiplier = 1
AutoMode=1
OldGain=1
Cutoff=0.01
CarGainTarget=1
OldRAW=0
OldCarGain=0
DynamicMode=0
OldFFBMultiplier=1
DynamicTarget=1
OptionsPage=0
DynamicThreshold=1.5
DynamicSpeed=0.01

#Variable initialization - AC
dT=0
dTG=0
ffbMultiplierSmoothOld=1
DynamicAdd=0
RB=0

def acMain(acVersion):

	global Version ,appWindow
	global messageLabel,targetGainSpinner,gainLabel,DynamicButton,DDToggleButton,ManualToggle,ResetButton,DefaultGainSpinner,TorqueSpinner,OptionsButton
	global DefaultgainSpinnerLabel, StrengthLabel,GraphRefreshSpinner,DisplaymodeButtonLabel,DisplaymodeButton,DynamicThresholdSpinner,DynamicSpeedSpinner
	global errorMessage,graph
	global CarGainTarget,ffbMultiplier,Histogram,MainGain,TargetGain,CarGainCombo,OldCarGain,ComboGain,TargetCarGain
	global AutoMode,DynamicMode,ManualOverride,DDToggle,MaxTorque
	global TrackID,TrackConfigID,CarID,CarGain,config,Combo,ComboPath,FFBClip,FFBClipPath
	global DynamicSpeed,DynamicThreshold,GraphRefresh,DisplayMode,RB,RBToggle

	
	ac.log("## FFBClip section start")
	#Intializing configparser
	config = configparser.ConfigParser()
	Combo = configparser.ConfigParser()
	UserFF = configparser.ConfigParser()
	FFBClip = configparser.ConfigParser()
	
	userffPath = os.path.expanduser(r"~\Documents\Assetto Corsa\cfg\user_ff.ini")
	ComboPath= "apps/python/FFBClip/Config/Combos.ini"
	FFBClipPath="apps/python/FFBClip/Config/FFBClip.ini"

	#initialize the Histogram
	for n in range(0,300):
		Histogram.append(0)

	
#Get the car name 
	CarID = ac.getCarName(0)
	TrackID = ac.getTrackName(0)
	TrackConfigID = ac.getTrackConfiguration(0)
	ac.log("Car ID: " + CarID + ", Track ID: " + TrackID + ", TrackConfigID: " + TrackConfigID)
	
	#Read the ini file and set appropriate default values if they don't exist
	if not os.path.exists(FFBClipPath):
		with open(FFBClipPath, 'w') as configfile:
			ac.log("FFBClip.ini not found, creating")
			FFBClip.write(configfile)
			ac.log("FFBClip.ini created")
	FFBClip.read(FFBClipPath)
	ac.log("FFBClip.ini read:")

## FFBClip section
	TargetGain = float(ReadOptions(FFBClip, FFBClipPath, "Options", "targetgain", "1"))
	DynamicMode = float(ReadOptions(FFBClip, FFBClipPath, "Options", "dynamicmode", "0"))
	MaxTorque = float(ReadOptions(FFBClip, FFBClipPath, "Options", "maxtorque", "20"))
	DynamicThreshold = float(ReadOptions(FFBClip, FFBClipPath, "Options", "dynamicthreshold", "2"))
	DynamicSpeed = float(ReadOptions(FFBClip, FFBClipPath, "Options", "dynamicspeed", "0.01"))
	GraphRefresh = float(ReadOptions(FFBClip, FFBClipPath, "Options", "graphrefresh", "2"))
	DisplayMode = float(ReadOptions(FFBClip, FFBClipPath, "Options", "displaymode", "0"))
	RB = float(ReadOptions(FFBClip, FFBClipPath, "Options", "rb", "0"))
	ac.log("TargetGain:" + str(TargetGain))
	settingsPath = ReadOptions(FFBClip, FFBClipPath, "Options", "path", "")
	if settingsPath=="":
		settingsPath = os.path.expanduser("~\Documents\Assetto Corsa\cfg\controls.ini")	
## FFBClip section ends

## Combos.ini section start	
	ac.log("Combos.ini section start")
	if os.path.exists(ComboPath):
		ac.log("Combos.ini found")
		Combo.read(ComboPath)
		ac.log("loaded")
		if Combo.has_option(TrackID+"_"+TrackConfigID,CarID):
			ac.log("Has section and option")
			CarGain = float(Combo.get(TrackID+"_"+TrackConfigID,CarID))
			ComboGain=1
			#AutoMode=0
			errorMessage = "Using stored values as starting point"
			if CarGain>2:
				CarGain=2
			ac.log("Combos cargain:"+str(CarGain))
		else:
			ac.log("Combos.ini or section not found")
			CarGain = 1.0
			AutoMode=1
			ComboGain=0
			errorMessage = "Using default values as starting point"
	else:
		CarGain=1.0
		AutoMode=1
		errorMessage="Combos.ini created"
		with open('apps/python/FFBClip/Config/Combos.ini', 'w') as configfile:
			Combo.write(configfile)		
	CarGainCombo=CarGain
	ac.log("Combo loaded")
	

## Combos.ini section ends
	
## Controls.ini section start
	if os.path.exists(settingsPath):
		ac.log("Controls.ini found")
		config.read(settingsPath)
		MainGain = float(config.get("STEER","FF_GAIN"))
		ac.log("MainGain:"+str(MainGain))
	else:
	#	#exists(path) is false then we use the v1.0 value and display it
		ac.log("MainGain not found")
		MainGain = 1.0
		errorMessage = "Controls.ini is missing. Using 100%"	
## Controls.ini section ends	

## Read the GainTarget from the ini file
	CarGainTarget=float(ReadOptions(FFBClip,FFBClipPath,"targetgains",CarID,str(TargetGain)))
	ManualOverride=float(ReadOptions(FFBClip,FFBClipPath,"Options","manualoverride","0"))
	DDToggle=float(ReadOptions(FFBClip,FFBClipPath,"Options","ddtoggle","0"))
			
## MainWindow setup	
	ac.log("Setting up the main window")
	appWindow = ac.newApp("FFBClip")
	ac.setSize(appWindow,300,102)
	ac.setTitle(appWindow,"")
	ac.setIconPosition(appWindow,0,-9000)
	
	graph = ac.addGraph(appWindow,"FFB_Graph")
	ac.setPosition(graph,7,105)
	ac.setSize(graph,300,150)
	ac.setRange(graph,-0.05,2.1,300)
	ac.addSerieToGraph(graph,0,1,0)
	ac.addSerieToGraph(graph,1,0,0)
	ac.addSerieToGraph(graph,1,1,0)
	ac.addSerieToGraph(graph,1,1,1)
	ac.addSerieToGraph(graph,0,0,0)
	if DisplayMode > 0:
		ac.setVisible(graph,1)
	else:
		ac.setVisible(graph,0)
		
	targetGainSpinner = ac.addSpinner(appWindow,"")
	ac.setPosition(targetGainSpinner,7,27)
	ac.setSize(targetGainSpinner,286,20)
	ac.setRange(targetGainSpinner,10,120)
	ac.setStep(targetGainSpinner,1)
	ac.setValue(targetGainSpinner,CarGainTarget*100)
	ac.addOnValueChangeListener(targetGainSpinner,targetChange)
	
	StrengthLabel = ac.addLabel(appWindow,"FFB Strength")
	ac.setPosition(StrengthLabel,115,8)
	ac.setFontSize(StrengthLabel,11)

	gainLabel = ac.addLabel(appWindow,"")
	ac.setPosition(gainLabel,7,60)

	messageLabel = ac.addLabel(appWindow,errorMessage)
	ac.setPosition(messageLabel,7,55)
	
	# AutoButton = ac.addButton(appWindow,"Auto:ON")
	# ac.setSize(AutoButton,70,17)
	# ac.setPosition(AutoButton,7,103)
	# ac.setFontSize(AutoButton,11)
	
	DynamicButton = ac.addButton(appWindow,"Dynamic: OFF")
	if DynamicMode==1:
		ac.setText(DynamicButton,"Dynamic: ON")
	ac.setSize(DynamicButton,90,17)
	ac.setPosition(DynamicButton,7,78)
	ac.setFontSize(DynamicButton,11)
	ac.addOnClickedListener(DynamicButton,DynamicChange)
	
	ResetButton = ac.addButton(appWindow,"RESET")
	ac.setSize(ResetButton,90,17)
	ac.setPosition(ResetButton,117,78)
	ac.setFontSize(ResetButton,11)
	ac.addOnClickedListener(ResetButton,ResetChange)

	OptionsButton = ac.addButton(appWindow,"Options")
	ac.setSize(OptionsButton,70,17)
	ac.setPosition(OptionsButton,223,78)
	ac.setFontSize(OptionsButton,11)
	ac.addOnClickedListener(OptionsButton,OptionsChange)
	
## Options page
	ManualToggle = ac.addCheckBox(appWindow,"Manual override")
	ac.setPosition(ManualToggle,7,7)
	ac.setSize(ManualToggle,10,10)
	ac.setFontSize(ManualToggle,11)
	ac.setVisible(ManualToggle,0)
	if ManualOverride==1:
		ac.setValue(ManualToggle,1)
		AutoMode=0
		ac.setText(messageLabel,"Manual override, clipping is NOT prevented")
	ac.addOnCheckBoxChanged(ManualToggle,ManualToggleChange)
	
	DDToggleButton = ac.addCheckBox(appWindow,"Direct Drive mode")
	ac.setPosition(DDToggleButton,7,25)
	ac.setSize(DDToggleButton,10,10)
	ac.setFontSize(DDToggleButton,11)
	ac.setVisible(DDToggleButton,0)
	if DDToggle==1:
		ac.setValue(DDToggleButton,1)
	ac.addOnCheckBoxChanged(DDToggleButton,DDToggleButtonChange)
##DD Toggle hide
	ac.setVisible(DDToggleButton,0)
	
	RBToggle = ac.addCheckBox(appWindow,"Run in background")
	ac.setPosition(RBToggle,180,25)
	ac.setSize(RBToggle,10,10)
	ac.setFontSize(RBToggle,11)
	ac.setVisible(RBToggle,0)
	if RB==1:
		ac.setValue(RBToggle,1)
		ac.setText(messageLabel,"Running in background")
	ac.addOnCheckBoxChanged(RBToggle,RBToggleChange)
	
	TorqueSpinner = ac.addSpinner(appWindow,"Hardware max torque")
	ac.setPosition(TorqueSpinner,7,108)
	ac.setSize(TorqueSpinner,160,20)
	ac.setRange(TorqueSpinner,3,50)
	ac.setStep(TorqueSpinner,1)
	ac.setValue(TorqueSpinner,MaxTorque)
	ac.addOnValueChangeListener(TorqueSpinner,TorqueChange)
	ac.setVisible(TorqueSpinner,0)
	
	DefaultgainSpinnerLabel=ac.addLabel(appWindow,"Default FFB strength (%)")
	ac.setPosition(DefaultgainSpinnerLabel,20,44)
	ac.setVisible(DefaultgainSpinnerLabel,0)
	ac.setFontSize(DefaultgainSpinnerLabel,11)
	if DDToggle==0:
		ac.console("DefaultGainSpinner non DD mode, TargetGain=" + str(TargetGain))
		DefaultGainSpinner = ac.addSpinner(appWindow,"")
		ac.setPosition(DefaultGainSpinner,7,61)
		ac.setSize(DefaultGainSpinner,160,20)
		ac.setRange(DefaultGainSpinner,10,120)
		ac.setStep(DefaultGainSpinner,1)
		ac.setValue(DefaultGainSpinner,TargetGain*100)
		ac.addOnValueChangeListener(DefaultGainSpinner,DefaultGainChange)
		ac.setText(DefaultgainSpinnerLabel,"Default FFB strength (%)")
		ac.setText(StrengthLabel,"FFB strength")
	else:
		DefaultGainSpinner = ac.addSpinner(appWindow,"")
		ac.setPosition(DefaultGainSpinner,7,61)
		ac.setSize(DefaultGainSpinner,160,20)
		ac.setRange(DefaultGainSpinner,3,50)
		ac.setStep(DefaultGainSpinner,1)
		ac.setValue(DefaultGainSpinner,TargetGain*MaxTorque)
		ac.addOnValueChangeListener(DefaultGainSpinner,DefaultGainChange)
		ac.setText(DefaultgainSpinnerLabel,"Default torque target (Nm)")
		ac.setText(StrengthLabel,"Torque target (Nm)")
		ac.setRange(targetGainSpinner,3,50)
		ac.setValue(targetGainSpinner,CarGainTarget*MaxTorque)
	ac.setVisible(DefaultGainSpinner,0)
		
	DisplaymodeButtonLabel=ac.addLabel(appWindow,"Graph display")
	ac.setPosition(DisplaymodeButtonLabel,220,44)
	ac.setVisible(DisplaymodeButtonLabel,0)
	ac.setFontSize(DisplaymodeButtonLabel,11)
	ac.setVisible(DisplaymodeButtonLabel,0)
	DisplaymodeButton = ac.addButton(appWindow,"Off")
	ac.setSize(DisplaymodeButton,90,17)
	ac.setPosition(DisplaymodeButton,220,60)
	ac.setFontSize(DisplaymodeButton,11)
	ac.addOnClickedListener(DisplaymodeButton,DisplaymodeButtonChange)
	ac.setVisible(DisplaymodeButton,0)
	if DisplayMode==1:
		ac.setText(DisplaymodeButton,"Graph")
	if DisplayMode==2:
		ac.setText(DisplaymodeButton,"Histogram")
	
	GraphRefreshSpinner = ac.addSpinner(appWindow,"Graph refresh (Hz)")
	ac.setPosition(GraphRefreshSpinner,180,108)
	ac.setSize(GraphRefreshSpinner,160,20)
	ac.setRange(GraphRefreshSpinner,1,30)
	ac.setStep(GraphRefreshSpinner,1)
	ac.setValue(GraphRefreshSpinner,GraphRefresh)
	ac.addOnValueChangeListener(GraphRefreshSpinner,GraphRefreshChange)
	ac.setVisible(GraphRefreshSpinner,0)
	
	DynamicThresholdSpinner = ac.addSpinner(appWindow,"Dynamic threshold")
	ac.setPosition(DynamicThresholdSpinner,7,155)
	ac.setSize(DynamicThresholdSpinner,160,20)
	ac.setRange(DynamicThresholdSpinner,10,300)
	ac.setStep(DynamicThresholdSpinner,10)
	ac.setValue(DynamicThresholdSpinner,DynamicThreshold*100)
	ac.addOnValueChangeListener(DynamicThresholdSpinner,DynamicThresholdSpinnerChange)
	ac.setVisible(DynamicThresholdSpinner,0)
	
	DynamicSpeedSpinner = ac.addSpinner(appWindow,"Dynamic mode intensity")
	ac.setPosition(DynamicSpeedSpinner,180,155)
	ac.setSize(DynamicSpeedSpinner,160,20)
	ac.setRange(DynamicSpeedSpinner,50,500)
	ac.setStep(DynamicSpeedSpinner,10)
	ac.setValue(DynamicSpeedSpinner,DynamicSpeed*10000)
	ac.addOnValueChangeListener(DynamicSpeedSpinner,DynamicSpeedSpinnerChange)
	ac.setVisible(DynamicSpeedSpinner,0)
	
	ac.addRenderCallback(appWindow,onFormRender)
	ac.console("FFBClip successful")
	return "FFBClip"
	
def acUpdate(deltaT):

	global OldRAW,Histogram,MainGain,CarGain,CarGainCombo,CurrentForce,i,RB,dT

## Runs every tick
	CurrentForce = abs(ac.getCarState(0,acsys.CS.LastFF))

	n=int(CurrentForce*200)
	if n>0 and OldRAW != CurrentForce:
		a=Histogram.pop(n)
		if n<(50*MainGain):
			inc=n/(50*MainGain)
		else:
			inc=1	
		a += inc
		Histogram.insert(n,a)
		#ac.console(str(n) + " - " + str(a))
	OldRAW=CurrentForce
	
	if RB == 1:
		dT += deltaT
		
		RunAll(deltaT)

def onFormRender(deltaT):
	
	global Version,appWindow
	global messageLabel,gainLabel
	global errorMessage,graph
	global CarGainTarget,ffbMultiplier,Histogram,dT,CarGain,OldCarGain,CurrentForce,OldFFBMultiplier
	global AutoMode,OldGain,Cutoff, DynamicMode, TargetGain,DynamicTarget,MainGain,OldRAW,ffbMultiplierSmooth,ffbMultiplierSmoothOld
	global DynamicThreshold,DynamicSpeed,DynamicAdd,dTG,GraphRefresh,i,RB
	
	dT += deltaT
	dTG += deltaT
	
	RunAll(deltaT)
	
	if DisplayMode == 1 and dTG > (1/GraphRefresh):
		ac.addValueToGraph(graph,0,CurrentForce)
		ac.addValueToGraph(graph,1,CarGainTarget)
		#ac.addValueToGraph(graph,2,ffbMultiplier)
		#ac.addValueToGraph(graph,3,DynamicAdd)
		dTG=0
		
	if DisplayMode == 2 and dTG > 1:
		HMax = max(Histogram)+1
		n=i
		for i in range(0,300):
			ac.addValueToGraph(graph,0,(Histogram[i]/HMax))
			if i<200:
				ac.addValueToGraph(graph,2,0)
			else:
				ac.addValueToGraph(graph,2,1)
				#ac.addValueToGraph(graph,1,Cutoff)
				#if i>n:
				#	ac.addValueToGraph(graph,3,1)
				#else:
				#	ac.addValueToGraph(graph,3,0)
				#if i>(CarGainTarget*200):
				#	ac.addValueToGraph(graph,4,1)
				#else:
				#	ac.addValueToGraph(graph,4,0)
		dTG=0	
		
			
def acShutdown(*args):

	global TrackID,TrackConfigID,CarID,CarGain,config,Combo,ComboPath,CurrentProfile,FFBClip,FFBClipPath,ManualOverride,MaxTorque,TargetGain
	global DDToggle,GraphRefresh,DisplayMode,DynamicThreshold,DynamicSpeed,RB

	
	ac.log("shutdown")
	
	if os.path.exists(ComboPath):
		if Combo.has_section(TrackID+"_"+TrackConfigID):
			ac.log("found track")
			if Combo.has_option(TrackID+"_"+TrackConfigID,CarID):
				ac.log("Car found")
				Combo.remove_option(TrackID+"_"+TrackConfigID,CarID)
				Combo.set(TrackID+"_"+TrackConfigID,CarID,str(CarGain))
			else:
				ac.log("Car not found")
				Combo.set(TrackID+"_"+TrackConfigID,CarID,str(CarGain))
				ac.log("add")
		else:
			ac.log("Track not found")
			Combo.add_section(TrackID+"_"+TrackConfigID)
			
			Combo.set(TrackID+"_"+TrackConfigID,CarID,str(CarGain))
	else:
		ac.log("Not Found")
	
	with open('apps/python/FFBClip/Config/Combos.ini', 'w') as configfile:
		ac.log("Write")
		Combo.write(configfile)
		
	if Cutoff > 0.01 and DDToggle==0:
		WriteOptions(FFBClip,FFBClipPath,"targetgains",CarID,str(CarGainTarget+Cutoff))
	else:
		WriteOptions(FFBClip,FFBClipPath,"targetgains",CarID,str(CarGainTarget))
		
	WriteOptions(FFBClip,FFBClipPath,"Options","dynamicmode",str(DynamicMode))
	WriteOptions(FFBClip,FFBClipPath,"Options","maxtorque",str(MaxTorque))
	WriteOptions(FFBClip,FFBClipPath,"Options","targetgain",str(TargetGain))
	WriteOptions(FFBClip,FFBClipPath,"Options","graphrefresh",str(GraphRefresh))
	WriteOptions(FFBClip,FFBClipPath,"Options","displaymode",str(DisplayMode))
	WriteOptions(FFBClip,FFBClipPath,"Options","dynamicthreshold",str(DynamicThreshold))
	WriteOptions(FFBClip,FFBClipPath,"Options","dynamicspeed",str(DynamicSpeed))
	WriteOptions(FFBClip,FFBClipPath,"Options","rb",str(RB))
	
	if AutoMode==0:
		WriteOptions(FFBClip,FFBClipPath,"Options","manualoverride","1")
	else:
		WriteOptions(FFBClip,FFBClipPath,"Options","manualoverride","0")
	
	WriteOptions(FFBClip,FFBClipPath,"Options","ddtoggle",str(DDToggle))
	
	ac.log("## FFBClip section end")
	
def ReadOptions(File, FilePath, Section, Option, Default):
	
	File.read(FilePath)
	
	if File.has_section(Section):
		#ac.log(Section + " section found")
		if File.has_option(Section,Option):
			#ac.log("ReadOptions: " + Option + " found in " + FilePath)
			ReturnValue = File.get(Section,Option)
			ac.log("ReadOptions: " + Option + ": " + ReturnValue)
		else:
			#ac.log("ReadOptions: " + Option + " not found in " + FilePath)
			File.set(Section,Option,Default)
			ReturnValue=Default
			ac.log("ReadOptions: " + Option + "="+Default + " created in " + FilePath)
	else:
		#ac.log("ReadOptions: " + Section + " not found, creating")
		File.add_section(Section)
		#ac.log("ReadOptions: " + Section + " section created in " + FilePath)
		File.set(Section,Option,Default)
		ReturnValue=Default
		ac.log("ReadOptions: " + Option + "=" + Default + " created in " + FilePath)
			
	with open(FilePath, 'w') as configfile:
		#ac.log("ReadOptions: " + FilePath + " write")
		File.write(configfile)
		
	return str(ReturnValue)
			
def WriteOptions(File, FilePath, Section, Option, Value):


		
	#ac.log("WriteOption") #Debug
	
	File.read(FilePath)
	
	ac.log("Write "+ Section + "-" + Option + " = " + Value )
	if File.has_option(Section,Option):
		#ac.log("ConfigWrite option found")
		File.remove_option(Section, Option)
		File.set(Section, Option, Value)
		
	with open(FilePath, 'w') as configfile:
		#ac.log("Config Write")
		File.write(configfile)
	#ac.log("Close config file")
	
	return ""
	
def targetChange(value):
	global errorMessage,messageLabel,CarGainTarget,Cutoff,targetGainSpinner,ManualOverride,MaxTorque,DDToggle
	
	ac.console("TargetChange:" + str(value))
	if DDToggle==1:
		value=(value/MaxTorque)*100
		
	if value>100:
		Cutoff=((value/100)-1)
		CarGainTarget=1
		if ManualOverride==0:
			ac.setText(messageLabel,"FFB strength {:.0%}, some clipping allowed".format(value/100))
		else:
			ac.setText(messageLabel,"Manual override, clipping is NOT prevented")
	else:
		Cutoff=0.01
		CarGainTarget=(value/100)
		if ManualOverride==0:
			ac.setText(messageLabel,"FFB strength {:.0%}, clipping prevented".format(CarGainTarget))
		else:
			ac.setText(messageLabel,"Manual override, clipping is NOT prevented")
			
	if DDToggle==1:
		Cutoff=0.05
		ac.setText(messageLabel,"Average cornering torque {}Nm".format(round(CarGainTarget*MaxTorque)))
		
	ac.console("Cargaintarget: " + str(CarGainTarget) + " - Cutoff: " + str(Cutoff))
	
def ResetChange(val1,val2):
	global Histogram,ffbMultiplier,messageLabel,targetGainSpinner,TargetGain,OldCarGain,ComboGain

	del Histogram[:]
		
	for n in range(0,300):
		Histogram.append(0)
	
	
	ffbMultiplier=1
	CarGain=round(ac.getCarFFB()/100,2)	
	ffbMultiplier=round(ffbMultiplier,2)
	GainChange=ffbMultiplier-CarGain	
	if GainChange != 0:# and AutoMode==1:
		ac.setCarFFB(GainChange*100)
	ac.setValue(targetGainSpinner,TargetGain)
	OldCarGain=ComboGain
	
	ac.setText(messageLabel,"Reset solution")
	
def DynamicChange(val1, val2):
	global DynamicMode, DynamicButton
	
	if DynamicMode==1:
		DynamicMode=0
		ResetChange(0,0)
		ac.setText(DynamicButton,"Dynamic: OFF")
		ac.console("Dynamicmode=0")
	else:
		DynamicMode=1
		ac.setText(DynamicButton,"Dynamic: ON")
		ac.console("Dynamicmode=1")
	
	
		
def OptionsChange(val1, val2):

	global messageLabel,targetGainSpinner,gainLabel,DynamicButton,DDToggleButton,ManualToggle,ResetButton,OptionsButton,DefaultGainSpinner,TorqueSpinner
	global DefaultgainSpinnerLabel,StrengthLabel,DisplaymodeButtonLabel,DisplaymodeButton
	global OptionsPage,DDToggle,appWindow,DisplayMode,RBToggle
	
	if OptionsPage==0:
		ac.setVisible(messageLabel,0)
		ac.setVisible(gainLabel,0)
		ac.setVisible(targetGainSpinner,0)
		ac.setVisible(StrengthLabel,0)
		ac.setVisible(DynamicButton,0)
		ac.setVisible(ResetButton,0)
		ac.setVisible(DDToggleButton,1)
		ac.setVisible(ManualToggle,1)
		ac.setVisible(DefaultGainSpinner,1)
		ac.setVisible(DefaultgainSpinnerLabel,1)
		ac.setVisible(GraphRefreshSpinner,1)
		ac.setVisible(DisplaymodeButtonLabel,1)
		ac.setVisible(DisplaymodeButton,1)
		ac.setVisible(DynamicThresholdSpinner,1)
		ac.setVisible(DynamicSpeedSpinner,1)
		ac.setVisible(RBToggle,1)
		
		
		if DDToggle==1:
			ac.setVisible(TorqueSpinner,1)
		else:
			ac.setVisible(TorqueSpinner,0)
		OptionsPage=1
		ac.setSize(appWindow,350,257)
		ac.setPosition(OptionsButton,273,233)
		ac.setVisible(graph,0)
		ac.setText(OptionsButton,"Exit")
	else:
		ac.setVisible(messageLabel,1)
		ac.setVisible(gainLabel,1)
		ac.setVisible(targetGainSpinner,1)
		ac.setVisible(StrengthLabel,1)
		ac.setVisible(DynamicButton,1)
		ac.setVisible(ResetButton,1)
		ac.setVisible(DDToggleButton,0)
		ac.setVisible(ManualToggle,0)
		ac.setVisible(DefaultGainSpinner,0)
		ac.setVisible(TorqueSpinner,0)
		ac.setVisible(DefaultgainSpinnerLabel,0)
		ac.setVisible(GraphRefreshSpinner,0)
		ac.setVisible(DisplaymodeButtonLabel,0)
		ac.setVisible(DisplaymodeButton,0)
		ac.setVisible(DynamicThresholdSpinner,0)
		ac.setVisible(DynamicSpeedSpinner,0)
		ac.setVisible(RBToggle,0)
	
		OptionsPage=0
		ac.setSize(appWindow,300,102)
		ac.setPosition(OptionsButton,223,78)
		if DisplayMode>0:
			ac.setVisible(graph,1)
		ac.setText(OptionsButton,"Options")
		
def ManualToggleChange(val1, val2):
	global AutoMode,messageLabel
	
	if AutoMode==0:
		AutoMode=1
		ac.console("Automode on")
		ac.setText(messageLabel,"Auto mode engaged")
	else:
		AutoMode=0
		ac.console("Automode off")
		ac.setText(messageLabel,"Manual override, clipping is NOT prevented")
		
def DDToggleButtonChange(val1, val2):
	global DDToggle,targetGainSpinner,TorqueSpinner,OptionsPage,DefaultGainSpinner,DefaultgainSpinnerLabel,StrengthLabel,TargetGain,CarGainTarget,MaxTorque
	
	ac.console("DDToggle:" + str(DDToggleButton))
	if DDToggle==0:
		DDToggle=1
		ac.setText(StrengthLabel,"Torque target (Nm)")
		ac.setText(DefaultgainSpinnerLabel,"Default Torque target (Nm)")
		#ac.setRange(DefaultGainSpinner,3,50)
		ac.setValue(DefaultGainSpinner,TargetGain*MaxTorque)
		ac.setRange(targetGainSpinner,3,50)
		targetChange(CarGainTarget*MaxTorque)
		ac.setValue(targetGainSpinner,CarGainTarget*MaxTorque)
		if OptionsPage==0:
			ac.setVisible(TorqueSpinner,0)
		else:
			ac.setVisible(TorqueSpinner,1)
		ac.console("DDmode engaged")
	else:
		DDToggle=0
		ac.setText(StrengthLabel,"FFB strength")
		ac.setText(DefaultgainSpinnerLabel,"Default FFB strength (%)")
		ac.setVisible(TorqueSpinner,0)
		ac.setRange(DefaultGainSpinner,10,120)
		ac.setValue(DefaultGainSpinner,TargetGain*100)
		ac.setRange(targetGainSpinner,10,120)
		ac.console("Setvalue")
		ac.setValue(targetGainSpinner,CarGainTarget*100)
		ac.console("Changetarget")
		targetChange(CarGainTarget*100)
		#ac.setValue(targetGainSpinner,CarGainTarget*100)
		ac.console("DDmode disengaged")
	ac.console("DDmode button finished")
	
def RBToggleChange(val1, val2):
	
	global RB
	
	if RB == 1:
		RB=0
	else:
		RB=1
	
def TorqueChange(value):

	global MaxTorque,DefaultGainSpinner,TorqueSpinner,targetGainSpinner,TargetGain,CarGainTarget
	
	ac.console("TorqueChange:" + str(value))
	MaxTorque = value
	targetChange(CarGainTarget*MaxTorque)
	ac.setValue(targetGainSpinner,CarGainTarget*MaxTorque)
	DefaultGainChange(TargetGain*MaxTorque)
	ac.setValue(DefaultGainSpinner,TargetGain*MaxTorque)
	
	
def DefaultGainChange(value):
	
	global MaxTorque,DDToggle,TargetGain,DefaultGainSpinner
	
	ac.console("DefaultGainChange:" + str(value))
	
	if DDToggle==1:
		TargetGain=value/MaxTorque
		ac.setRange(DefaultGainSpinner,3,MaxTorque)
	else:
		TargetGain = value/100
		ac.setRange(DefaultGainSpinner,10,120)
		
def GraphRefreshChange(value):

	global GraphRefresh
	
	GraphRefresh=value
	
def DisplaymodeButtonChange(val1, val2):

	global DisplayMode,DisplaymodeButton
	
	DisplayMode += 1
	
	if DisplayMode>2:
		DisplayMode=0
		ac.setText(DisplaymodeButton,"Off")
	if DisplayMode == 1:
		DisplayMode=1
		ac.setText(DisplaymodeButton,"Graph")
	if DisplayMode == 2:
		DisplayMode=2
		ac.setText(DisplaymodeButton,"Histogram")
		
def DynamicThresholdSpinnerChange(value):

	global DynamicThreshold
	
	DynamicThreshold = value/100
		
def DynamicSpeedSpinnerChange(value):

	global DynamicSpeed
	
	DynamicSpeed = value/10000
	
def RunAll(deltaT):

	global Version,appWindow
	global messageLabel,gainLabel
	global errorMessage,graph
	global CarGainTarget,ffbMultiplier,Histogram,dT,CarGain,OldCarGain,CurrentForce,OldFFBMultiplier
	global AutoMode,OldGain,Cutoff, DynamicMode, TargetGain,DynamicTarget,MainGain,OldRAW,ffbMultiplierSmooth,ffbMultiplierSmoothOld
	global DynamicThreshold,DynamicSpeed,DynamicAdd,dTG,GraphRefresh,i
	
## Runs every frame
	
		
	# CurrentForce = abs(ac.getCarState(0,acsys.CS.LastFF))

	# n=int(CurrentForce*200)
	# if n>0 and OldRAW != CurrentForce:
		# a=Histogram.pop(n)
		# if n<(50*MainGain):
			# inc=n/(50*MainGain)
		# else:
			# inc=1	
		# a += inc
		# Histogram.insert(n,a)
		# #ac.console(str(n) + " - " + str(a))
	# OldRAW=CurrentForce
	
	if DynamicMode==1:
		Interval=0.03
	else:
		Interval=0.5
	
	if dT > Interval:
		CarGain=round(ac.getCarFFB()/100,2)
		#ac.log("CurrentGain: " + str(CarGain) + "OldGain: " + str(OldCarGain))
		if CarGain>OldCarGain and OldCarGain>0 and AutoMode>0:
			#ac.log("Gain Up pressed")
			CurrentSpinner=ac.getValue(targetGainSpinner)
			ac.console(str(CurrentSpinner))
			CurrentSpinner += 1
			ac.setValue(targetGainSpinner,CurrentSpinner)
		if CarGain<OldCarGain and OldCarGain>0 and AutoMode>0:
			#ac.log("Gain Down Pressed")
			CurrentSpinner=ac.getValue(targetGainSpinner)
			ac.console(str(CurrentSpinner))
			CurrentSpinner += -1
			ac.setValue(targetGainSpinner,CurrentSpinner)
		
		HMax = max(Histogram)+1
		for i in range(299,1,-1):
			if (Histogram[i]/HMax) > Cutoff:
				#ffbMultiplier=(CarGainTarget*200)
				ffbMultiplier=(CarGainTarget*(CarGainTarget/MainGain))/((i/200))
				#ac.console("Index: " + str(i) + " HMax: " + str(HMax) + "Hist/Hmax: " + str(Histogram[i]/HMax))
				#ac.console("Index: " + str(i) + " Target: " + str(CarGainTarget*200))
				#ac.console(str(ffbMultiplier))
				break
		if HMax < (CarGainCombo*100):
			if ffbMultiplier>CarGainCombo:
				ffbMultiplier=CarGainCombo
		if HMax < 200 and HMax > (CarGainCombo*100):
			if ffbMultiplier > (HMax/100):
				ffbMultiplier=HMax/100

		if DynamicMode==1:
			if CurrentForce > CarGainTarget:
				ffbMultiplier=(CarGainTarget*(CarGainTarget/MainGain))/((i/200))
				DynamicAdd=0
			else:
				ffbMultiplier=ffbMultiplier+DynamicAdd
			DynamicAdd = DynamicAdd+DynamicSpeed
		
		ffbMultiplier=round(ffbMultiplier,2)
		if DynamicMode==0:
			if ffbMultiplier > 3:
				ffbMultiplier=3
				CarGain=3
			ffbMultiplierSmooth=ffbMultiplier*0.1+ffbMultiplierSmoothOld*0.9
		else:
			if ffbMultiplier > DynamicThreshold:
				ffbMultiplier=DynamicThreshold
				CarGain=DynamicThreshold
			ffbMultiplierSmooth=ffbMultiplier
		
		if AutoMode==1:
			GainChange=round(ffbMultiplierSmooth,2)-CarGain
			#ac.log("GainChange: " + str(GainChange))
		else:
			GainChange=OldGain-CarGain
			Change=CarGain/OldGain
			OldGain=CarGain
					
		if GainChange != 0:# and AutoMode==1:

			if AutoMode==1:
				Change=ffbMultiplier/CarGain
				ac.setCarFFB(GainChange*100)
		
		OldCarGain=round(ac.getCarFFB()/100,2)
		ffbMultiplierSmoothOld=ffbMultiplierSmooth
		ac.setText(messageLabel,"Current gain (T,S,A): {:.0%}, {:.0%}, {:.0%}".format(ffbMultiplier,ffbMultiplierSmooth,CarGain))
		
		dT=0
		
	
		