-- Place this file in your railworks plugins folder
-- Usually C:\Program Files (x86)\Steam\steamapps\common\railworks\plugins (for 64 bit windows)
-- or C:\Program Files\Steam\steamapps\common\railworks\plugins (for 32 bit windows)

--The command used to check if a certain control exists or not and if it does
-- retreive its value is:-

-- if Call("*:ControlExists", Name of control, 0) == 1 then
-- variable = Call( "*:GetControlValue", Name of control, 0 )
--end

--This code block as you will see is used throughout the script to retrieve
--the data for each control required and can easily be added to or deleted from.
--I have included in the files 'Railworks EngineData.pdf' which lists all the
--control names I have found along with their min/max/default values.
--I then use the local variable data to store the name of the control followed by a colon
-- and the return value and a new line. The data variable is added to as each control is read
-- throughout the script and at the end of the script we open the plugins/GetData.txt file
-- and write the whole data variable to the file ready for reading into your program.

--A word of warning, be careful with your syntax when editing lua script files because
--the only way you know something is wrong is when the script does not work. That is
--why I have included the line gCurrentTime = Call( "*:GetSimulationTime", 0 ). If your
--script is OK then the line at the end of the textbox display in my C# program will
--display "Current Time = :" followed by the time in seconds counting up. If this line
--is static then there is an error in your script. So my advice is make small changes
--and test your script regularly. 

-------------------  GetData function --------------------
gData = ""
delay = 5 
counter = 3 --Loop counter to only update every number of itterations set bt delay variable
dataread = 0
previousValues = {}
speedoType = 0 -- 0 = none, 1 = MPH, 2 = KPH
MPH = 2.23693629 -- 2.23694 --Convert meters per second to MPH
KPH = 3.60	--Convert meters per second to KPH
delete_Files = 1 --We need to delete the Getdata.txt and sendcommand.txt files on first run so updated data is received
function getdata ()
--If this is the first run then delete the getdata.txt and sendcommand.txt files
	if delete_Files == 1 then
		deleteFiles() --Delete old data first.
	end
	counter = counter + 1
	if counter >= delay then
		if Call ("GetIsEngineWithKey") == 1 then --Check we are driving the train.
			GetSpeedInfo()
			GetControlData () -- Extract data for controls only.
			GetSpeedLimits () -- Get current & next speed limits as well as distance to next speed limit.
			WriteData () -- Write the data extracted by GetControlData() to GetData.txt.
			SendData () -- Reads 'SendCommand.txt' file generated by 'TS2015 Raildriver Interface.exe' & passes data back to TS2015.
		end
		counter = 0
		gData = ""
	end
end

function GetSpeedInfo()
	local data = "" --Data storage for data to write to output file
	local ControlType = "Speed"
	local ControlName = ""
	local ControlMin = 0
	local ControlMax = 0
	local ControlValue = 0
	
	if Call("ControlExists", "SpeedometerMPH", 0) == 1 then
		speedoType = 1
		ControlName = "SpeedoType"
		ControlMin = 0
		ControlMax = 2 --Call("GetControlMaximum", "SpeedometerMPH", 0)
		ControlValue = 1 -- MPH
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	elseif Call("ControlExists", "MySpeedometerMPH", 0) == 1 then
		speedoType = 1
		ControlName = "SpeedoType"
		ControlMin = 0
		ControlMax = 2 --Call("GetControlMaximum", "MySpeedometerMPH", 0)
		ControlValue = 1 -- MPH
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	elseif Call("ControlExists", "SpeedometerKPH", 0) == 1 then
		speedoType = 2
		ControlName = "SpeedoType"
		ControlMin = 0
		ControlMax = 2 --Call("GetControlMaximum", "SpeedometerKPH", 0)
		ControlValue = 2 -- KPH
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	elseif Call("ControlExists", "MySpeedometerKPH", 0) == 1 then
		speedoType = 2
		ControlName = "SpeedoType"
		ControlMin = 0
		ControlMax = 2 --Call("GetControlMaximum", "MySpeedometerKPH", 0)
		ControlValue = 2 -- KPH
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	else
		speedoType = 0
		ControlName = "SpeedoType"
		ControlMin = 0
		ControlMax = 0
		ControlValue = 0 -- No Speedo Fitted
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	end

	ControlName = "CurrentSpeed"
	ControlMin = 0
	--ControlMax = 3000
	ControlValue = Call("GetSpeed")
	
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	gData = gData ..data
end

function GetControlData()

	local data = "" --Data storage for data to write to output file
	local ControlType = "Speed"
	local ControlName = ""
	local ControlMin = 0
	local ControlMax = 0
	local ControlValue = 0
	
	ControlType = "TimeOfDay"
	ControlName = "TimeOfDay"
	ControlMin = 0
	ControlMax = 0
	ControlValue = SysCall("ScenarioManager:GetTimeOfDay")
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	
	ControlType = "_Acceleration"
	ControlName = "Acceleration"
	ControlMin = 0
	ControlMax = 0
	ControlValue = Call("GetAcceleration")
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	
	ControlType = "_Gradient"
	ControlName = "Gradient"
	ControlMin = 0
	ControlMax = 0
	ControlValue = Call("GetGradient")
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	
	local TenderWaterCapacity = Call("GetTenderWaterCapacity")
	if TenderWaterCapacity then
		ControlType = "_TenderWaterCapacity"
		ControlName = "TenderWaterCapacity"
		ControlMin = 0
		ControlMax = 0
		ControlValue = TenderWaterCapacity
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	end
	
	local TenderWaterCurrent = Call("GetTenderWaterCurrent")
	if TenderWaterCurrent then
		ControlType = "_TenderWaterLevel"
		ControlName = "TenderWaterLevel"
		ControlMin = 0
		ControlMax = 0
		ControlValue = TenderWaterCurrent
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	end
	
	local FuelLevel = Call("GetFuelLevel")
	if FuelLevel then
		ControlType = "_FuelLevel"
		ControlName = "FuelLevel"
		ControlMin = 0 -- Call("GetControlMinimum", "GetFuelLevel", 0) 
		ControlMax = 0 --Call("GetControlMaximum", "GetFuelLevel", 0)
		ControlValue = string.format("%1.3f",FuelLevel)
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	end
	
	local FireboxMass = Call("GetFireboxMass")
	if FireboxMass then
		ControlType = "_FireboxMass"
		ControlName = "FireboxMass"
		ControlMin = 0
		ControlMax = 0
		ControlValue = FireboxMass -- Call("GetFireboxMass") -- string.format("%1.3f",Call("GetFireboxMass"))
		data = data.."ControlType:"..ControlType.."\n"
		data = data .."ControlName:"..ControlName.."\n"
		data = data .."ControlMin:"..ControlMin.."\n"
		data = data .."ControlMax:"..ControlMax.."\n"
		data = data .."ControlValue:"..ControlValue.."\n"
	end

	gData = gData ..data
end

function GetSpeedLimits ()
	local data = "" --Data storage for data to write to output file
	local ControlType = "Speed"
	local ControlName = ""
	local ControlMin = 0
	local ControlMax = 0
	local ControlValue = ""
	
	ControlValue = Call( "GetCurrentSpeedLimit" )
	if (speedoType <= 1) then
		ControlValue = string.format("%1.1f", ControlValue * MPH)
	elseif (speedoType == 2) then 
		ControlValue = string.format("%1.1f", ControlValue * KPH)
	end
	ControlName = "CurrentSpeedLimit"
	ControlMin = 0
	ControlMax = 300
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"

	NextSpeedLimitType, NextSpeedLimitSpeed, NextSpeedLimitDistance = Call("GetNextSpeedLimit", 0)

	ControlValue = NextSpeedLimitType
	ControlName = "NextSpeedLimitType"
	ControlMin = 0
	ControlMax = 10
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	-- currentvalues[ControlName] = ControlValue

	ControlValue = NextSpeedLimitSpeed
	ControlName = "NextSpeedLimitSpeed"
	ControlMin = 0
	ControlMax = 500
	-- Check speedlimit does not exceed 1000 as some tracks report no speed limit as very high value
	-- 1225016488463523100000000000000000000000.0 which crashes the C# program
	if (ControlValue >= 1000) then 
		ControlValue = string.format("%1.1f", 0)
	end
	
	if (speedoType <= 1 ) then 
		ControlValue = string.format("%1.1f", ControlValue * MPH)
	elseif (speedoType == 2) then 
		ControlValue = string.format("%1.1f", ControlValue * KPH)
	end
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	-- currentvalues[ControlName] = ControlValue

	ControlValue = string.format("%d", NextSpeedLimitDistance)
	ControlName = "NextSpeedLimitDistance"
	ControlMin = 0
	ControlMax = 10000
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	-- currentvalues[ControlName] = ControlValue
	
	NextSpeedLimitBackType, NextSpeedLimitBackSpeed, NextSpeedLimitBackDistance = Call("GetNextSpeedLimit", 1)

	ControlValue = NextSpeedLimitBackType
	ControlName = "NextSpeedLimitBackType"
	ControlMin = 0
	ControlMax = 10
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	-- currentvalues[ControlName] = ControlValue

	ControlValue = NextSpeedLimitBackSpeed
	ControlName = "NextSpeedLimitBackSpeed"
	ControlMin = 0
	ControlMax = 500
	-- Check speedlimit does not exceed 1000 as some tracks report no speed limit as very high value
	-- 1225016488463523100000000000000000000000.0 which crashes the C# program
	if (ControlValue >= 1000) then 
		ControlValue = string.format("%1.1f", 0)
	end
	
	if (speedoType <= 1 ) then 
		ControlValue = string.format("%1.1f", ControlValue * MPH)
	elseif (speedoType == 2) then 
		ControlValue = string.format("%1.1f", ControlValue * KPH)
	end
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	-- currentvalues[ControlName] = ControlValue

	ControlValue = string.format("%d", NextSpeedLimitBackDistance)
	ControlName = "NextSpeedLimitBackDistance"
	ControlMin = 0
	ControlMax = 10000
	data = data.."ControlType:"..ControlType.."\n"
	data = data .."ControlName:"..ControlName.."\n"
	data = data .."ControlMin:"..ControlMin.."\n"
	data = data .."ControlMax:"..ControlMax.."\n"
	data = data .."ControlValue:"..ControlValue.."\n"
	gData = gData ..data
				
end
	
function WriteData ()

	gData = gData .."ControlType:SimulationTime".."\n"
	gData = gData .."ControlName:SimulationTime".."\n"
	gData = gData .."ControlMin:0".."\n"
	gData = gData .."ControlMax:0".."\n"
	gData = gData .."ControlValue:"..Call( "GetSimulationTime", 0 ).."\n"

	-- Write data to file
	file = io.open("plugins/GetData.txt", "w")
	file:write(gData)
	file:flush()
	file:close()
	--Clear values 
	gData = ""
	-- controlTypes = {}
end

function SendData ()

	-- Read file & send data to Railworks
	--1st we read a line from the SendCommand.txt file
	for line in io.lines("plugins/SendCommand.txt") do 
		--Check to make sure it isn't a blank line
		if line ~= "" then
			--it isn't blank so create a table(array) to hold the variables
			t = {}
			i = 1
			--Look for the colon(:) in the file that separates the control name
			-- from the value to send
			for str in string.gfind(line, "[^:]+") do
				--Place the control name in t[1] then increment i
				--and place the value for the control in t[2]
				t[i] = str
				i = i + 1
			end
			
			--Force controls to 0 on first run
			if dataread == 0 then
				previousValues[t[1]] = -1
				t[2] = 0
			end

			if t[1]~= "Wipers" and t[1] ~= "WiperSpeed" and t[1] ~= "swDriverWiper" then
				if previousValues[t[1]] ~= t[2] then
					--Send the command to railworks. The format is:-
					--Call("*:SetControlValue", Control name, 0 (for lead engine), value for the control)
					if OnControlValueChange then
						OnControlValueChange(t[1], 0, tonumber(t[2]))
					else
						Call( "SetControlValue", t[1], 0, tonumber(t[2])) 
					end
					Call("SetControlTargetValue", t[1], 0, tonumber(t[2]))
					previousValues[t[1]] = t[2]
				end
			end
			
			if t[1] == "Wipers" or t[1] == "WiperSpeed" or t[1] == "swDriverWiper" then
				if previousValues[t[1]] ~= 0 or previousValues[t[1]] ~= t[2] then 
					--Send the command to railworks. The format is:-
					--Call("SetControlValue", Control name, 0 (for lead engine), value for the control)
					if OnControlValueChange then
						OnControlValueChange(t[1], 0, tonumber(t[2]))
					else
						Call( "SetControlValue", t[1], 0, tonumber(t[2])) 
					end
					Call("SetControlTargetValue", t[1], 0, tonumber(t[2]))
				end
				previousValues[t[1]] = t[2]
			end
		end
	end
	dataread = 1
end

function deleteFiles()

	os.remove("Plugins/GetData.txt")
	os.remove("Plugins/sendcommand.txt")
	delete_Files = 0
end