----------------------------------------------------------------------------
-- @Author: ViperGTS96©-----------------------------------------------------
----------------------------------------------------------------------------
--------------------"The simplest design is the best design." --------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------

bigfootNitro = {};

function bigfootNitro.prerequisitesPresent(specializations)
	return SpecializationUtil.hasSpecialization(Washable, specializations)
		and SpecializationUtil.hasSpecialization(Motorized, specializations)
		and SpecializationUtil.hasSpecialization(AnimatedVehicle, specializations);
end;

--if GS_IS_CONSOLE_VERSION then return; end;

function bigfootNitro:intialize()
	bigfootNitro.nitroActivated = 0;
	bigfootNitro.nitroInterval = 70; --nitro Duration [35]
	bigfootNitro.nitroFillRate = 0.25; --litres per tic
	bigfootNitro.nitroCapacity = 100; --tank size (no affect on duration)
	bigfootNitro.maxSpeed = 350; --speed limit for nitro use (kmph)
	bigfootNitro.dir = g_currentModDirectory;

	bigfootAirControl:intialize();
end;

function bigfootNitro.registerEventListeners(vehicleType)
	SpecializationUtil.registerEventListener(vehicleType, "onLoad", bigfootNitro);
	SpecializationUtil.registerEventListener(vehicleType, "onUpdate", bigfootNitro);
	SpecializationUtil.registerEventListener(vehicleType, "onLeave", bigfootNitro);
	SpecializationUtil.registerEventListener(vehicleType, "onDraw", bigfootNitro);
	SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", bigfootNitro);
end;

function bigfootNitro.registerOverwrittenFunctions(vehicleType)
	SpecializationUtil.registerOverwrittenFunction(vehicleType, "getBrakeForce", bigfootNitro.getBrakeForce);
end;

function bigfootNitro:onLoad()
	self.bigfootNitroEvents = {};
	self.bigfootNitroEventIds = {};
	local baseString = "vehicle.motorized.sounds";
	local xmlFile = loadXMLFile("bigfoot_sound", bigfootNitro.dir.."sounds/sound.xml");
	self.nitroSound = g_soundManager:loadSampleFromXML(xmlFile, "sounds", "motorNitro", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self);
	self.nitroActivated = bigfootNitro.nitroActivated;
	bigfootNitro.nitroCapacity = self:getFillUnitCapacity(3);
	self:addFillUnitFillLevel(self:getOwnerFarmId(), 3, bigfootNitro.nitroCapacity, FillType.NOS, ToolType.UNDEFINED);
	self.areAllTiresOnGround = bigfootNitro.areAllTiresOnGround;
	self.setBoostEventState = bigfootNitro.setBoostEventState;

	bigfootAirControl:onLoad(self);
end;

function bigfootNitro:onDraw()
	bigfootAirControl:onDraw(self);
end;

function bigfootNitro:getBrakeForce(superFunc)
	local brakeForce = superFunc(self);
	if self.nitroActivated > 0 or self.spec_drivable:getAccelerationAxis() > 0 then
		brakeForce = 0;
	end;
	return brakeForce;
end;

function bigfootNitro:areAllTiresOnGround()
	local i = 1;
	for _, wheel in pairs(self.spec_wheels.wheels) do
		if wheel.hasGroundContact ~= nil and not wheel.hasGroundContact then
			i = i + 1
		end;
	end;
	if i >= #self.spec_wheels.wheels then 
		return false; 
	end;
	return true;
end;

function bigfootNitro:updateNitroSound(self, spec)
	if self.isClient then
		if not g_soundManager:getIsSamplePlaying(self.nitroSound) then
			if self.nitroActivated > (bigfootNitro.nitroInterval-2) then
				g_soundManager:playSample(self.nitroSound);
			end;
		else
			for i=1, #spec.motorSamples do
				if g_soundManager:getIsSamplePlaying(spec.motorSamples[i]) then
					setSampleVolume(spec.motorSamples[i].soundSample, 0.5);
				end;
			end;
		end;
	end;
end;

function bigfootNitro:resetNitro(self)
	if self.isClient then
		if g_soundManager:getIsSamplePlaying(self.nitroSound) then
			g_soundManager:stopSample(self.nitroSound);
		end;
	end;
    useBFNitroEvent.sendEvent(self, 0, noEventSend);
	self.nitroActivated = 0;
end;

function bigfootNitro:onLeave()
	bigfootNitro:resetNitro(self);
end;

function bigfootNitro:onUpdate(dt)
	if self.nitroActivated <= 0 then
		if self:getFillUnitFillLevel(3) < self:getFillUnitCapacity(3) then
			self:addFillUnitFillLevel(self:getOwnerFarmId(), 3, bigfootNitro.nitroFillRate, FillType.NOS, ToolType.UNDEFINED);
		end;
	else
		if self:getIsMotorStarted() then
			if self.isServer and self:areAllTiresOnGround() then
				local force = 20*self:getTotalMass(true);
				local _,cmY,cmZ = getCenterOfMass(self.rootNode);
				local dirX,_,dirZ = localDirectionToWorld(self.components[1].node,0,0,1);
				addForce(self.components[1].node,dirX*force,0,dirZ*force,0,cmY,cmZ,true);
			end;
			bigfootNitro:updateNitroSound(self, self.spec_motorized);
			self.nitroActivated = self.nitroActivated - 1;
			local delta = bigfootNitro.nitroCapacity/bigfootNitro.nitroInterval;
			self:addFillUnitFillLevel(self:getOwnerFarmId(), 3, -delta, FillType.NOS, ToolType.UNDEFINED);
		else
			bigfootNitro:resetNitro(self);
		end;
	end;

	bigfootAirControl:onUpdate(self, dt);
end;

function bigfootNitro:setBoostEventState(interval, noEventSend)
    useBFNitroEvent.sendEvent(self, interval, noEventSend);
	self.nitroActivated = interval;
end;

function bigfootNitro:boostEvent(actionName, inputValue, callbackState, isAnalog)
	if self:getIsMotorStarted() then
		if self:getFillUnitFillLevel(3) >= self:getFillUnitCapacity(3) then
			local speed = self:getLastSpeed(true);
			if self:areAllTiresOnGround() and speed < bigfootNitro.maxSpeed then
				local interval = bigfootNitro.nitroInterval;
				if speed > 96 then interval = interval/2; end;
				--self.nitroActivated = bigfootNitro.nitroInterval;
				self:setBoostEventState(bigfootNitro.nitroInterval);
			end;
		end;
	end;
end;

function bigfootNitro:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
	if self.isClient then
		self:clearActionEventsTable(self.bigfootNitroEvents);
		self.bigfootNitroEventIds = {};
		if isActiveForInputIgnoreSelection--[[self:getIsActiveForInput(true, true)]] then
			local _, actionEventId = self:addActionEvent(self.bigfootNitroEvents, 'nitroBoost', self, bigfootNitro.boostEvent, false, true, false, true, nil);
			g_inputBinding:setActionEventTextVisibility(actionEventId, true);
			g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL);
			table.insert(self.bigfootNitroEventIds, actionEventId);
		end;
	end;
end;

bigfootNOS = {};
function bigfootNOS:loadMap()
	if FillType.NOS == nil then
		local key = bigfootNitro.dir.."icon/";
		local refFrame = g_currentMission.worldYReferenceFrame;
		local nosDesc = g_fillTypeManager:addFillType("nos", g_i18n:getText("fillType_nitro"), false, 0, 0, 0, key.."hud_nos.dds", key.."hud_nos.dds", "", refFrame, {0,0,0,0}, nil);
	end;
	g_currentMission.hud.fillLevelsDisplay:refreshFillTypes(g_fillTypeManager);
	removeModEventListener(bigfootNOS);
end;

useBFNitroEvent = {};
useBFNitroEvent_mt = Class(useBFNitroEvent, Event);
InitEventClass(useBFNitroEvent,"useBFNitroEvent");

function useBFNitroEvent:emptyNew()
    local self = Event:new(useBFNitroEvent_mt);
    self.className = "useBFNitroEvent";
    return self;
end;
function useBFNitroEvent:new(vehicle,interval)
    self.vehicle = vehicle;
    self.interval = interval;
    return self;
end;
function useBFNitroEvent:readStream(streamId,connection)
    self.vehicle = NetworkUtil.readNodeObject(streamId);
    self.interval = streamReadInt16(streamId);
    self:run(connection);
end;
function useBFNitroEvent:writeStream(streamId,connection)
    NetworkUtil.writeNodeObject(streamId,self.vehicle);
    streamWriteInt16(streamId,self.interval);
end;
function useBFNitroEvent:run(connection)
    self.vehicle:setBoostEventState(self.interval, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(useBFNitroEvent:new(self.vehicle,self.interval),nil,connection,self.vehicle);
    end;
end;
function useBFNitroEvent.sendEvent(vehicle,interval,noEventSend)
    if noEventSend == nil or noEventSend == false then
        if g_server ~= nil then
            g_server:broadcastEvent(useBFNitroEvent:new(vehicle,interval),nil,nil,vehicle);
        else
            g_client:getServerConnection():sendEvent(useBFNitroEvent:new(vehicle,interval));
        end;
    end;
end;

source(g_currentModDirectory.."scripts/bigfootAirControl.lua");
bigfootNitro:intialize();
addModEventListener(bigfootNOS);