-- Written by Miata lover
-- Do not reuse/modify without permission!
local M = {}

local timer = 0
local timerR = 0
local wiperMode = 0
local wiperModeR = 0
local wiperSleep = 0
local spd = 0
local spdR = 0
local ignitionIndependent
local hasRearWiper
local wiperOffset
local wipersNode
local wipersSound
local soundVolume

local stalkSmoother = newExponentialSmoothing(10)

local function init(jbeamData)
  electrics.values.wiperVal = 0
  electrics.values.wiperVal2 = 0
  electrics.values.wiperValR = 0
  electrics.values.wipers = 0
  wiperMode = 0
  wiperModeR = 0
  spd = 0
  spdR = 0
  ignitionIndependent = jbeamData.ignitionIndependent or false
  hasRearWiper = jbeamData.hasRearWiper or false
  wiperOffset = jbeamData.wiperOffset or nil
  wipersNode = jbeamData.wipersNode

  for v, n in pairs(v.data.nodes) do
    if n.name == wipersNode then
      wipersNode = v
      break
    end
  end
  
  if wipersNode == jbeamData.wipersNode then
    log("W", "controller.animatedWipers", "failed to find node: " .. wipersNode .. ". Using RefNode Instead.") 
    wipersNode = v.data.refNodes[0].ref
  end
end

local function reset()
  electrics.values.wiperVal = 0
  electrics.values.wiperVal2 = 0
  electrics.values.wiperValR = 0
  electrics.values.wipers = 0
  wiperMode = 0
  wiperModeR = 0
  spd = 0
  spdR = 0
end

local function updateGFX(dt)
  if wiperMode ~= 0 and electrics.values.wiperVal == 0 and timer >= wiperSleep and electrics.values.ignitionLevel ~= 0 then
    M.playSound()
    spd = 1
    timer = 0
  elseif electrics.values.wiperVal > 0.1 and electrics.values.wiperVal < 0.9 and spd == 1 then
    spd = 1.5
  elseif electrics.values.wiperVal > 1 then
    spd = -1
  elseif electrics.values.wiperVal > 0.9 and spd == 1.5 then
    spd = 1
  elseif electrics.values.wiperVal < 0.9 and electrics.values.wiperVal > 0.1 and spd == -1 then
    spd = -1.5
  elseif electrics.values.wiperVal < 0.1 and spd == -1.5 then
    spd = -1
  elseif electrics.values.wiperVal < 0 then
    electrics.values.wiperVal = 0
    spd = 0
    timer = 0
  end
  
  if hasRearWiper then
    if wiperModeR ~= 0 and electrics.values.wiperValR == 0 and timerR >= 1 and electrics.values.ignitionLevel ~= 0 then
      M.playSoundRear()
      spdR = 0.7
      timerR = 0
    elseif electrics.values.wiperValR > 0.1 and electrics.values.wiperValR < 0.9 and spdR == 0.7 then
      spdR = 1
    elseif electrics.values.wiperValR > 1 then
      spdR = -0.7
    elseif electrics.values.wiperValR > 0.9 and spdR == 1 then
      spdR = 0.7
    elseif electrics.values.wiperValR < 0.9 and electrics.values.wiperValR > 0.1 and spdR == -0.7 then
      spdR = -1
    elseif electrics.values.wiperValR < 0.1 and spdR == -1 then
      spdR = -0.7
    elseif electrics.values.wiperValR < 0 then
      electrics.values.wiperValR = 0
      spdR = 0
    end
  end

  if electrics.values.ignitionLevel ~= 0 or ignitionIndependent == true then
    electrics.values.wiperVal = electrics.values.wiperVal + (dt * spd)
    electrics.values.wiperValR = electrics.values.wiperValR + (dt * spdR)
    if wiperOffset then electrics.values.wiperVal2 = electrics.values.wiperVal + wiperOffset end
  end
  
  if wipersSound and M.isCamInside() then
    obj:setVolume(wipersSound, 1) 
  elseif wipersSound then
    obj:setVolume(wipersSound, 0)
  end
    
  electrics.values.wipers = stalkSmoother:get(wiperMode / 3)

  timer = timer + dt
  timerR = timerR + dt
end

local function toggleMode()
  if wiperMode == 0 then
    wiperMode = 1
    wiperSleep = 3
    timer = wiperSleep
    gui.message("Wipers: Slow", 2, "wiperMsg")
  elseif wiperMode == 1 then
	  wiperMode = 2
    wiperSleep = 1
    gui.message("Wipers: Medium", 2, "wiperMsg")
  elseif wiperMode == 2 then
	  wiperMode = 3
    wiperSleep = 0.02
    gui.message("Wipers: Fast", 2, "wiperMsg")
  else
	  wiperMode = 0
    gui.message("Wipers: Off", 2, "wiperMsg")
  end  
end

local function toggleModeR()
  if hasRearWiper then
    if wiperModeR == 0 then
      wiperModeR = 1
      gui.message("Rear Wiper: On", 2, "wiperMsgR")
    else
      wiperModeR = 0
      gui.message("Rear Wiper: Off", 2, "wiperMsgR")
    end
  end
end

local function playSound()
  wipersSound = wipersSound or obj:createSFXSource2("art/sound/wiper.mp3", "AudioClosest3D", "wiperSound", wipersNode, 0)
  if M.isCamInside() then 
    obj:setVolumePitch(wipersSound, 1, 1) 
  else
    obj:setVolumePitch(wipersSound, 0, 1)
  end
  obj:cutSFX(wipersSound)
  obj:playSFX(wipersSound)
end

local function playSoundRear()
  wipersSound = wipersSound or obj:createSFXSource2("art/sound/wiper.mp3", "AudioClosest3D", "wiperSound", wipersNode, 0)
  if M.isCamInside() then 
    obj:setVolumePitch(wipersSound, 1, 0.7) 
  else
    obj:setVolumePitch(wipersSound, 0, 0.7)
  end
  obj:cutSFX(wipersSound)
  obj:playSFX(wipersSound)
end
  

local function isCamInside()
  local camPos = obj:getCameraPosition()
  local combinedPos = obj:getPosition() + obj:getNodePosition(beamstate.nodeNameMap['driver'] or 0)

  if camPos and combinedPos then
      return camPos:distance(combinedPos) <= 0.6
  end
  return false
end

M.init = init
M.reset = reset
M.updateGFX = updateGFX
M.toggleMode = toggleMode
M.toggleModeR = toggleModeR
M.isCamInside = isCamInside
M.playSound = playSound
M.playSoundRear = playSoundRear
return M