-- 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 = {}
M.type = "auxilliary"
M.relevantDevice = nil
local min = math.min
local max = math.max
local abs = math.abs

local bulletBeams = {}
local bulletNodes = {}
local activeBullets = {}
local activeBulletCount = 0
local recoilCounter = 0
local rofTimer = 0
local numberOfRounds = nil
local roundIndex = nil
local fireRateTime = nil
local bulletTargetSpeed = 0
local realBulletSpeed = 340
local realBulletSpeedSquared = realBulletSpeed * realBulletSpeed
local quarterBulletTargetSpeed = 0
local additionalExplosiveEnergy = 0 --J


local function updateBulletFiring(bullet, dt)
	local nodeVelocity = obj:getNodeVelocityVector(bullet.nodeCid):length() - bullet.velocityOffset
	if nodeVelocity >= bulletTargetSpeed then
		electrics.values[bullet.thrusterSource] = nil
		recoilCounter = recoilCounter - 1
		local nodeMass = obj:getNodeMass(bullet.nodeCid)
		local targetEnergy = 0.5 * nodeMass * realBulletSpeedSquared + additionalExplosiveEnergy
		local equivalentWeight = min(max(targetEnergy * 2 / (nodeVelocity * nodeVelocity), nodeMass), 100)
		obj:setNodeMass(bullet.nodeCid, equivalentWeight)
		bullet.roundState = "fired"
		bullet.update = nop
	end
end


local function update(dt)
	for i = 1, activeBulletCount, 1 do
		activeBullets[i]:update(dt)
	end
	electrics.values.recoil = recoilCounter > 0 and 1 or nil --activates the recoil thruster
end


local function updateGFX(dt)
	
	local activeBullets2 = {}
	for _,v in ipairs(activeBullets) do
		if v.roundState == "fired" then
			local bulletVelocity = abs(obj:getNodeVelocityVector(v.nodeCid):length())
			if bulletVelocity <= quarterBulletTargetSpeed then
				obj:breakBeam(v.beamCid or 0)
				obj:addParticleByNodes(v.nodeCid, 0.1, 0, 27, 0, 1)
				v.roundState = "dead"
			end
		end
		if v.roundState ~= "dead" then
			table.insert(activeBullets2, v)
		end
	end

	activeBullets = activeBullets2
	rofTimer = max(rofTimer - dt, 0)
	
	local brokengun = obj:beamIsBroken(deadgun)
	
	if electrics.values.supertact_gau >= 0.5 and electrics.values.open_gau >= 0.5 then 
		electrics.values.barrelspin = electrics.values.barrelspin + (2600 * dt)
		if electrics.values.barrelspin >= 360 then electrics.values.barrelspin = 0 end
		if rofTimer <= 0 and roundIndex < numberOfRounds and brokengun == false then --only go in here if we are STILL firing or want to fire
			sounds.playSoundOnceAtNode("minigun", barrelNodemid, 5)	--Play the firing sound
			local barrelvel = -obj:getNodeVelocity(barrelNodemid, barrelNodeback)
			obj:addParticleByNodesRelative(barrelNodemid, barrelNodeback, 10, 6, 0, 1)
			obj:addParticleByNodesRelative(barrelNodemid, barrelNodeback, barrelvel, 64, 0, 1)
			gui.message(string.format("Minigun rounds: %d", (numberOfRounds - roundIndex - 1) * 1), 3, "cannonrounds")
			local thrusterSource = "50cal_"..(roundIndex + 1)
			electrics.values[thrusterSource] = 1 --roundIndex starts at 1, and determines which bullet is to be fired. it is added to "shell_", so if roundIndex is 1 then the thruster with "bllt_1" as the control is activated
			table.insert(activeBullets,
				{
				beamCid = bulletBeams[roundIndex + 1],
				nodeCid = bulletNodes[roundIndex + 1],
				thrusterSource = thrusterSource,
				velocityOffset = electrics.values.airspeed,
				muzzleFlashTimer = 0.05,
				hasMuzzleFlash = true,
				roundState = "firing",
				update = updateBulletFiring})
			rofTimer = fireRateTime
			roundIndex = roundIndex + 1
			recoilCounter = recoilCounter + 1
		end
	end
	activeBulletCount = #activeBullets
	
end

local function init(jbeamData)
	
	electrics.values.superThrustLevel = jbeamData.superThrust or 0
	electrics.values.barrelspin = 0
	electrics.values.supertact_gau = 0    --trigger
	electrics.values.open_gau = 0         --hood
	electrics.values.recoil = nil         --gun recoil
	recoilCounter = 0
	roundIndex = 0
	numberOfRounds = jbeamData.numberOfRounds or 0
	fireRateTime = 0.06
	bulletTargetSpeed = jbeamData.bulletSpeed or 200
	quarterBulletTargetSpeed = bulletTargetSpeed * 0.25
	additionalExplosiveEnergy = jbeamData.bulletAdditionalExplosiveEnergy or 43600
	deadgun = 0
	
	for k, node in pairs (v.data.nodes) do
		if node.name == "gau0" then barrelNodefront = k end
		if node.name == "gau1" then barrelNodemid = k end
		if node.name == "gau16" then barrelNodeback = k end
		if node.bullet then bulletNodes[node.bullet] = node.cid  end
	end
	
	activeBullets = {}
	activeBulletCount = 0
	bulletBeams = {}
	
	for _, beam in pairs(v.data.beams) do
		if beam.tracer then bulletBeams[beam.tracer] = beam.cid  end
	end
	
	for s,b in pairs(v.data.beams) do
		if b.name == "deadgun"    then deadgun = b.cid end
	end
	
end

M.init = init
M.update = update
M.updateGFX = updateGFX

return M