-- This Source Code Form is subject to the terms of the bCDDL, v. 1.1.
-- If a copy of the bCDDL was not distributed with this
-- file, You can obtain one at http://beamng.com/bCDDL-1.1.txt

local M = {}
local htmlTexture = require("htmlTexture")

local updateTimer = 0
local updateFPS = 60

local hasSentMapData = false
local vehicleID = obj:getID()
--local naviScreenName = "@R60_Nav"
--local clusterScreenName = "@sat_gauges_screen"


local alreadyParked = 1;
local alreadyParkedMajor = 1;
local alreadyHigh = 0;


local menuOption = 0;
local menuOpen = 0;
local lastMenuOption = 50

local cruiseOn = false;
local cruiseTarget = 0;
local cruiseCurThrottle = 0;

local cruiseOffRoad = false;
local cruiseOffRoadThrottle = 0;
local cruiseOffRoadBrake = 0;

local cruisePause = false;
local cruisePauseEnd = false;

local function onInit()
   -- hasSentMapData = false
    obj:queueGameEngineLua("extensions.load('ui/uinavi')")
    
	--obj:queueGameEngineLua('be:getObjectByID('..vehicleID..'):createUITexture("'..naviScreenName..'", "local://local/vehicles/sat/navi_screen.html", 256, 128, UI_TEXTURE_USAGE_AUTOMATIC, 30)')
    --obj:queueGameEngineLua("uinavi.requestVehicleDashboardMap('"..naviScreenName.."')")
	
	htmlTexture.create("@R60Nav", "local://local/vehicles/sat/navi_screen.html", 420, 128, 30, 'automatic')
	htmlTexture.create("@sat_gauges_screen", "local://local/vehicles/common/vw_screens/gauges_screen/gauges_screen.html", 544, 128, 30, 'automatic')
	
	--Init function for dashboard
    htmlTexture.call("@sat_gauges_screen", "init")
	obj:queueGameEngineLua(string.format('extensions.ui_uinavi.requestVehicleDashboardMap(%q)', "@R60Nav"))
	
	hasSentMapData = true
	
	--Resets the last menu option when the car is respawned to force an update
	lastMenuOption = 50;
	--Turns cruise control off when car is respawned
	cruiseOn = false
	cruiseOffRoad = false
	cruisePause = false
	cruisePauseEnd = false
end

local function onReset()
    --local destroy = 'be:getObjectByID('..vehicleID..'):destroyUITexture("'..naviScreenName..'")'
    --obj:queueGameEngineLua(destroy)
    onInit()
end



local function updateGFX(dt)

	--map
    if hasSentMapData then
        --local pos = obj:getPosition()
		--local posX = pos.x
		--local posY = pos.y
        --local rotation = math.deg(obj:getDirection()) + 180
       -- local speed = (electrics.values.airspeed or 0) * 3.6
        --local zoom = math.min(300 + speed * 1.5, 500)

        --obj:queueGameEngineLua("if be:getObjectByID("..vehicleID..") then be:getObjectByID("..vehicleID.."):queueJSUITexture('"..naviScreenName.."', 'map.setPosition("..pos.x..", "..pos.y..", "..rotation..")') end")
        --obj:queueGameEngineLua("if be:getObjectByID("..vehicleID..") then be:getObjectByID("..vehicleID.."):queueJSUITexture('"..naviScreenName.."', 'map.setZoom("..zoom..")') end")
    
		--htmlTexture.call("@R60Nav", "map.setPosition",{posX=posX,posY=posY,rotation=rotation})
		--htmlTexture.call("@R60Nav", "map.setZoom", zoom)
		
		local pos = obj:getPosition()
		local rotation = math.deg(obj:getDirection()) + 180
		local speed = electrics.values.wheelspeed * 1.609
		local zoom = math.min(300 + speed * 1.5, 500)
		
		local data = {x = pos.x, y = pos.y, rotation = rotation, zoom = zoom}
		htmlTexture.call("@R60Nav", "map.updateData", data)
	end	
	
	
	--Dashboard
	local wSpeed = math.floor( electrics.values.wheelspeed * 3.6 or 0) 
	local fuel = ( electrics.values.fuel * 100 or 0) 
	local fuelVolume = ( electrics.values.fuelVolume * 100 or 0) 
	local rpm = math.floor( electrics.values.rpm + 0.5 or 0)
	local gear = electrics.values.gear
	local parked = math.floor(electrics.values.parkingbrake + 0.5 or 0)
	local high = math.floor(electrics.values.highbeam + 0.5 or 0)
	local gx = sensors.gx / 9.81
	local gy = sensors.gy / 9.81
	local gz = sensors.gz / 9.81
	local indicatorL = electrics.values.signal_L
	local indicatorR = electrics.values.signal_R
	local tcs = electrics.values.tcs
	local esc = electrics.values.esc
	local temp = math.floor(obj:getEnvTemperature() - 273.15) 
	local time = os.date("%H") .. ":" .. os.date("%M")

	

	
	--Dashboard menu system
	local menuSelect = electrics.values["select"]
	local menuUp = electrics.values["menuUp"]
	local menuDown = electrics.values["menuDown"]
	
	electrics.values["menuDown"] = false;
	electrics.values["menuUp"] = false;
	
	
	--Makes sure boolean logic can be applied to these values
	if (menuUp == nil) then
		menuUp = 0
	end
	if (menuDown == nil) then
		menuDown = 0
	end
	if (menuSelect == nil) then
		menuSelect = 0
	end

	
	--htmlTexture.call("@sat_gauges_screen", "updateMenu", {menuSelect = menuSelect,menuUp = menuUp,menuDown = menuDown,wSpeed = wSpeed})
	
	--Menu System
	--Controls
		if (menuUp == 1) then
			menuOption = menuOption -1
		end
		if (menuDown == 1) then
			menuOption = menuOption +1
		end
		
		--Sets if the menu should be open or closed
		if (menuSelect == 1) then
			menuOpen = 1
			htmlTexture.call("@sat_gauges_screen", "mainMenuOpen")
		else
			menuOpen = 0
			htmlTexture.call("@sat_gauges_screen", "mainMenuClose")
		end
		
		
	--Menu Navigation
		if (menuOpen == 1) then
			--Makes system loop only when the menu is open
			if(menuOption > 3) then
					menuOption = -1
			end
			if(menuOption <-1) then
					menuOption = 3
			end
			
			--Lua doesn't seem to support Switch statements, so here, have a list of 'if' statements instead, because screw it...
			if(menuOption == -1) then
				htmlTexture.call("@sat_gauges_screen", "mainMenuCruise")
			end
			if(menuOption == 0) then
				htmlTexture.call("@sat_gauges_screen", "mainMenuStandard")
			end
			if(menuOption == 1) then
				htmlTexture.call("@sat_gauges_screen", "mainMenuSport")
			end
			if(menuOption == 2) then
				htmlTexture.call("@sat_gauges_screen", "mainMenuRace")
			end
			if(menuOption == 3) then
				htmlTexture.call("@sat_gauges_screen", "mainMenuHill")
			end
		else
			--Checks for changes in input before updating anything to ensure greater performance
			if(lastMenuOption ~= menuOption) then
				if(menuOption < -1) then
					htmlTexture.call("@sat_gauges_screen", "screenCruise")
					--Sets cruise control to the current player speed when turned on
					if(cruiseOn == false) then
						cruiseTarget = wSpeed
						cruiseOn = true
						cruiseOffRoad = false
					end
					menuOption = 0
				end
				if(menuOption == -1) then
					htmlTexture.call("@sat_gauges_screen", "screenCruiseWarning")
				end
				if(menuOption == 0) then
					htmlTexture.call("@sat_gauges_screen", "screenStandard")
				end
				if(menuOption == 1) then
					htmlTexture.call("@sat_gauges_screen", "screenSport")
				end
				if(menuOption == 2) then
					htmlTexture.call("@sat_gauges_screen", "screenRace")
				end
				if(menuOption == 3) then
					htmlTexture.call("@sat_gauges_screen", "screenHillWarning")
				end
				if(menuOption > 3) then
					htmlTexture.call("@sat_gauges_screen", "screenHill")
					if(cruiseOffRoad == false) then
						cruiseTarget = wSpeed
						cruiseOffRoad = true
						cruiseOn = false
					end
				end
			end
			lastMenuOption = menuOption
		end
	
	
	--Checking if gear == null to prevent any issues

	htmlTexture.call("@sat_gauges_screen", "updateGear", gear)

	
	htmlTexture.call("@sat_gauges_screen", "updateSpeed", wSpeed)
	htmlTexture.call("@sat_gauges_screen", "updateFuel", {fuel=fuel,fuelVolume=fuelVolume,wSpeed=wSpeed})
	htmlTexture.call("@sat_gauges_screen", "updateRPM", rpm)
	htmlTexture.call("@sat_gauges_screen", "updateGForce", {gx=gx,gy=gy,gz=gz})
	htmlTexture.call("@sat_gauges_screen", "updateTcs", {tcs=tcs,esc=esc})
	htmlTexture.call("@sat_gauges_screen", "updateIndicators", {indicatorL = indicatorL,indicatorR = indicatorR})
	htmlTexture.call("@sat_gauges_screen", "updateTemp", {temp})
	htmlTexture.call("@sat_gauges_screen", "updateTime", {time})
	htmlTexture.call("@sat_gauges_screen", "updateCons", {cons})
	
	if (high < 0.5) then
		--headLights are turned off
		if (alreadyHigh == 1) then
			--Headlights were turned off this cycle
			
			htmlTexture.call("@sat_gauges_screen", "updateHeadLightsOff")
			alreadyHigh = 0
		end
	else
		--headlights are turned on
		if (alreadyHigh == 0) then
			--Headlights were turned on this cycle
			htmlTexture.call("@sat_gauges_screen", "updateHeadLightsOn")
			alreadyHigh = 1
		end
	end
	
	if (parked < 0.5) then
		--If parking brake is off
		if (alreadyParked == 1) then
			--parking brake was turned off this cycle therefore disable warning
			htmlTexture.call("@sat_gauges_screen", "updateParkingBrakeOff")
			alreadyParked = 0
		end
	else
		--If parking brake is on
		
		--If RPM goes over 1000 while parking brake is on display major warning
		if (rpm > 1000) then
			htmlTexture.call("@sat_gauges_screen", "updateParkingBrakeMajor")
		end
		
		if (rpm < 1000) then
			htmlTexture.call("@sat_gauges_screen", "updateParkingBrakeMajorOff")
		end
		
		if (alreadyParked == 0) then
			--Parking brake was turned on this cycle therefore enable warning
			htmlTexture.call("@sat_gauges_screen", "updateParkingBrakeOn")
			alreadyParked = 1
		end
	end
	
	
	
	--Cruise Control
	if (cruiseOn == true) then
		--###Interesting algorithm stuff###
		--=================================
		
		local cruiseDiff = cruiseTarget - ( electrics.values.wheelspeed * 2.25 or 0)
		
		cruiseCurThrottle = cruiseDiff * 0.2
		
		--The above cruise control is usually pretty great, but when the going gets tuff it starts to lag behind, the code below detects slacking, calculates, and administers an appropriately sized kick in the balls to make sure it keeps up.
		if (cruiseDiff / cruiseTarget < 0.9 and cruiseDiff / cruiseTarget > 0.0) then
			cruiseCurThrottle = cruiseCurThrottle * ((cruiseDiff / cruiseTarget) + 1)
		end	
        
		--Auto Brakes the vehicle if required when going downhill
		if (cruisePause == false) then
			if(cruisePauseEnd == false) then
				if ( cruiseDiff / cruiseTarget < -0.05) then
					electrics.values.brake = - cruiseCurThrottle - 0.05
				end
			else
				if ( wSpeed < (cruiseTarget + 1) ) then
					cruisePauseEnd = false
				end
				electrics.values.brake = 0.1
			end
		end
		
		
		--###Boring Stuff###
		--==================
		
		--Keeps the applied throttle always within limits
		if ( cruiseCurThrottle > 1) then
			cruiseCurThrottle = 1
		end
		if ( cruiseCurThrottle < 0) then
			cruiseCurThrottle = 0
		end
		
		--Disables Cruise Control if brakes are applied
		if( electrics.values.brake_input > 0) then
			cruiseOn = false
			cruiseOffRoad = false
			menuOption = -1
		end
		
		--Pauses Cruise Control if player presses clutch in
		if( electrics.values.clutch_input > 0 or electrics.values.throttle_input > 0) then
			cruisePause = true;
		else
			if( cruisePause == true) then
				cruisePauseEnd = true
			end
			cruisePause = false
		end	
		
		--Adjusts throttle based on clutch to allow gear changes
		--cruiseCurThrottle = cruiseCurThrottle * ( 1 - (electrics.values.clutch * 0.8) )
		
		if (cruisePause == false) then
			electrics.values.throttle = cruiseCurThrottle
		end
	end
	
	
	
	--Offroad cruise control
	--Offroad cruise control use seperate brake and throttle axis, meaning brakes and throttle can be applied at the same time, desirable for off road use because better control, not deirable on road because extra vehicle wear and tear 
	if(cruiseOffRoad == true) then
		--###Interesting algorithm stuff###
		--=================================
		local cruiseDiff = cruiseTarget - ( electrics.values.wheelspeed * 2.25 or 0)
		
		cruiseOffRoadThrottle = cruiseOffRoadThrottle + cruiseDiff * 0.004
		if ( cruiseDiff / cruiseTarget > 0.01) then
			cruiseOffRoadThrottle = cruiseOffRoadThrottle + cruiseDiff * 0.004
		else
			cruiseOffRoadThrottle = cruiseOffRoadThrottle - 0.01
		end
		
		if ( cruiseDiff / cruiseTarget < -0.05) then
			cruiseOffRoadBrake = cruiseOffRoadBrake - cruiseDiff * 0.005
		else
			cruiseOffRoadBrake = cruiseOffRoadBrake - 0.02
		end
		
		--###Boring Stuff###
		--==================
		
		--Keeps the applied throttle always within limits
		if ( cruiseOffRoadThrottle > 1) then
			cruiseOffRoadThrottle = 1
		end
		if ( cruiseOffRoadThrottle < 0) then
			cruiseOffRoadThrottle = 0
		end
		--Keeps the applied braking always within limits
		if ( cruiseOffRoadBrake > 1) then
			cruiseOffRoadBrake = 1
		end
		if ( cruiseOffRoadBrake < 0) then
			cruiseOffRoadBrake = 0
		end
		
		--Disables Cruise Control if brakes are applied
		if( electrics.values.brake_input ~= 0) then
			cruiseOn = false
			cruiseOffRoad = false
			menuOption = 3
		end
		
		electrics.values.throttle = cruiseOffRoadThrottle
		electrics.values.brake = cruiseOffRoadBrake
	
	
			--if (cruiseDiff / cruiseTarget > 1.1) then
			--	cruiseCurThrottle = cruiseCurThrottle * ((cruiseDiff / cruiseTarget) + 1) * 1.1
			--end	
			
			--Offroad Auto Brakes the vehicle if required when going downhill
			--if ( cruiseDiff / cruiseTarget < -0.05) then
				--electrics.values.brake = - (cruiseCurThrottle - 0.04) * 1.2
			--end
			--if ( cruiseDiff / cruiseTarget < -0.2) then
				--electrics.values.brake = - (cruiseCurThrottle - 0.04) * 1.4
			--end
	end
	
	htmlTexture.call("@sat_gauges_screen", "updateCruise", {cruiseTarget=cruiseTarget, cruiseOn=cruiseOn})
	
end



-- public interface
M.onInit    = onInit
M.onReset   = onReset
M.updateGFX = updateGFX

return M
