-- RotationSiloCompacter
-- Specialization for RotationSiloCompacter
--
-- @author  Tobias F. (John Deere 6930)
-- @date 07/11/2013

RotationSiloCompacter = {};

function RotationSiloCompacter.prerequisitesPresent(specializations)
    return true;
end;

function RotationSiloCompacter:load(xmlFile)	
    self.setIsTurnedOn = SpecializationUtil.callSpecializationsFunction("setIsTurnedOn");
    self.raycastCallback = RotationSiloCompacter.raycastCallback;
	
	self.bunkerSiloCompactingScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.bunkerSiloCompacter#compactingScale"), 1);
	self.bunkerSiloCompactingScaleBackUp = self.bunkerSiloCompactingScale;
	self.bunkerSiloCompactingScaleOnContact = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.bunkerSiloCompacter#compactingScaleOnContact"), 3);
	self.bunkerSiloCompactingMinDistance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.bunkerSiloCompacter#compactingMinDistance"), 0.5);
	self.bunkerSiloCompactingRefNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.bunkerSiloCompacter#refNode"));

	self.raycastDistance = 0;
	self.raycastTransformId = nil;
	
	if self.isRealistic == nil or not self.isRealistic then
		self.setVehicleRpmUp = SpecializationUtil.callSpecializationsFunction("setVehicleRpmUp");
		self.saveMinRpm = 0;
	end;
	
	self.rotor = {};
	self.rotor.node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.rotor#index"));
    print(self.rotor.node);
	self.rotor.speed = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rotor#rotSpeed"), 1)*0.001);
    self.rotor.curSpeed = 0;
	self.rotor.speedInDecreasingTime = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rotor#speedInDecreasingTime"), 1)*1000;
	
	self.chaffParticleSystems = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.chaffParticleSystems.chaffParticleSystem(%d)", i);
	
		local particleSystem = {};
		particleSystem.ps = {};
		local ps = Utils.loadParticleSystem(xmlFile, particleSystem.ps, baseName, self.components, false, nil, self.baseDirectory)
		if ps == nil then
			break;
		end;
		particleSystem.disableTime = 0;
		particleSystem.isEnabled = false;
		table.insert(self.chaffParticleSystems, particleSystem);
		i = i+1;
	end;
	
	self.siloCompacterParticleSystemFlag = self:getNextDirtyFlag();
	
     local workSound = getXMLString(xmlFile, "vehicle.workSound#file");
	if workSound ~= nil and workSound ~= "" then
		workSound = Utils.getFilename(workSound, self.baseDirectory);
		self.workSound = createSample("workSound");
		self.workSoundEnabled = false;
		loadSample(self.workSound, workSound, false);
		self.workSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.workSound#pitchOffset"), 1);
		self.workSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.workSound#volume"), 1);
	end;
end;

function RotationSiloCompacter:delete()
	for k,v in pairs(self.chaffParticleSystems) do
		Utils.deleteParticleSystem(v.ps);
	end;
	if self.workSound ~= nil then
		delete(self.workSound);
		self.workSoundEnabled = false;
	end;
end;

function RotationSiloCompacter:readStream(streamId, connection)
	local isTurnedOn = streamReadBool(streamId);
	local bunkerSiloCompactingScale = streamReadFloat32(streamId);
	self:setIsTurnedOn(isTurnedOn, true);
	self.bunkerSiloCompactingScale = bunkerSiloCompactingScale;
end;
 
function RotationSiloCompacter:writeStream(streamId, connection)
	streamWriteBool(streamId, self.isTurnedOn);
	streamWriteFloat32(streamId, self.bunkerSiloCompactingScale);
end;
 
function RotationSiloCompacter:readUpdateStream(streamId, timestamp, connection)
	if connection:getIsServer() then
		local hasUpdate = streamReadBool(streamId);
		if hasUpdate then
			for k,v in ipairs(self.chaffParticleSystems) do
				local enabled = streamReadBool(streamId);
				Utils.setEmittingState(v.ps, enabled);
			end;
		end;
		local bunkerSiloCompactingScale = streamReadFloat32(streamId);
		self.bunkerSiloCompactingScale = bunkerSiloCompactingScale;
	end;
end;
 
function RotationSiloCompacter:writeUpdateStream(streamId, connection, dirtyMask)
	if not connection:getIsServer() then
		if bitAND(dirtyMask, self.siloCompacterParticleSystemFlag) ~= 0 then
			streamWriteBool(streamId, true);
			for k,v in ipairs(self.chaffParticleSystems) do
				streamWriteBool(streamId, v.isEnabled);
			end;
		else
			streamWriteBool(streamId, false);
		end;
		streamWriteFloat32(streamId, self.bunkerSiloCompactingScale);
	end;
end;
 
function RotationSiloCompacter:mouseEvent(posX, posY, isDown, isUp, button)
end;

function RotationSiloCompacter:keyEvent(unicode, sym, modifier, isDown)
end;

function RotationSiloCompacter:update(dt) 
	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) then
			self:setIsTurnedOn(not self.isTurnedOn);
		end;
	end;
end;

function RotationSiloCompacter:updateTick(dt)
	if self:getIsActive() then
        self.rotor.curSpeed = Utils.getMovedLimitedValue(self.rotor.curSpeed, self.rotor.speed, 0, self.rotor.speedInDecreasingTime, dt, not self.isTurnedOn);
        rotate(self.rotor.node, dt*self.rotor.curSpeed,0,0);
        
		if self.isTurnedOn then		
			if self.isServer then
				local x,y,z = getWorldTranslation(self.bunkerSiloCompactingRefNode);
				raycastClosest(x, y, z, 0, -1, 0, "raycastCallback", self.bunkerSiloCompactingMinDistance*10, self);				
			
				if self.raycastTransformId ~= nil then
					if self.raycastDistance <= self.bunkerSiloCompactingMinDistance then
						self.bunkerSiloCompactingScale = self.bunkerSiloCompactingScaleOnContact;
						for _,ps in pairs(self.chaffParticleSystems) do
							ps.disableTime = self.time + 300;
							if not ps.isEnabled then
								ps.isEnabled = true;
								self:raiseDirtyFlags(self.siloCompacterParticleSystemFlag);
								if self.isClient then
									Utils.setEmittingState(ps.ps, true);
								end;
							end;
						end;
					else
						self.bunkerSiloCompactingScale = self.bunkerSiloCompactingScaleBackUp;
					end;
				else
					self.bunkerSiloCompactingScale = self.bunkerSiloCompactingScaleBackUp;
				end;
			end;
			if self.isClient then
				if not self.workSoundEnabled and self:getIsActiveForSound() then
					setSamplePitch(self.workSound, self.workSoundPitchOffset);
					playSample(self.workSound, 0, self.workSoundVolume, 0);
					self.workSoundEnabled = true;
				end;
			end;
		end;
	end;
	
	if self.isRealistic ~= nil and self.isRealistic then
		if self.isTurnedOn then
			self.realToolNeedEngineRev = true;
		else
			self.realToolNeedEngineRev = false;
		end;
	else
		if self.isTurnedOn then 
			self:setVehicleRpmUp(dt, true);
		else
			self:setVehicleRpmUp(dt, false);
		end;	
	end;	
	
	if self.isClient then
		if not self.isTurnedOn and self.workSoundEnabled then
			stopSample(self.workSound);
			self.workSoundEnabled = false;
		end;
	end;
	
	if self.isServer then
		for k,v in pairs(self.chaffParticleSystems) do
			if self.time > v.disableTime then
				if v.isEnabled then
					v.isEnabled = false;
					self:raiseDirtyFlags(self.siloCompacterParticleSystemFlag);
					if self.isClient then
						Utils.setEmittingState(v.ps, false);
					end;
				end;
			end;
		end;
	end;	
end;

function RotationSiloCompacter:draw()
	if self.isClient then
		if self:getIsActiveForInput(true) then
			if self.isTurnedOn then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_off_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_on_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
			end;
		end;
	end;
end;

function RotationSiloCompacter:setIsTurnedOn(isTurnedOn, noEventSend)
	SetTurnedOnEvent.sendEvent(self, isTurnedOn, noEventSend)
	self.isTurnedOn = isTurnedOn;
end; 

function RotationSiloCompacter:onAttach(attacherVehicle)
	if self.isRealistic == nil or not self.isRealistic then
		self.saveMinRpm = self.attacherVehicle.motor.minRpm;
	end;
end;

function RotationSiloCompacter:onDetach()
	if self.deactivateOnDetach then
		RotationSiloCompacter.onDeactivate(self);
	end;
	if self.movingTools ~= nil then
		if self.movingTools[3] ~= nil then
			local tool = self.movingTools[3];
			tool.curRot[tool.rotationAxis] = 0;
			setRotation(tool.node, unpack(tool.curRot));
			Cylindered.setDirty(self, tool);
		end;
	end;
	
	if self.isRealistic == nil or not self.isRealistic then
		for k, steerable in pairs(g_currentMission.steerables) do
			if self.attacherVehicleCopy == steerable then
				steerable.motor.minRpm = self.saveMinRpm;
				self.attacherVehicleCopy = nil;
			end;
		end;
	end;
end;
 
function RotationSiloCompacter:onLeave()
	if self.deactivateOnLeave then
		RotationSiloCompacter.onDeactivate(self);
	end;
end;
 
function RotationSiloCompacter:onDeactivate()
	if self.isClient then
		for k,v in pairs(self.chaffParticleSystems) do
			v.isEnabled = false;
			Utils.setEmittingState(v.ps, false);
		end;
	end;
	self.isTurnedOn = false;
	RotationSiloCompacter.onDeactivateSounds(self)
end;

function RotationSiloCompacter:onDeactivateSounds()
	if self.workSoundEnabled then
		stopSample(self.workSound);
		self.workSoundEnabled = false;
	end;
end;

function RotationSiloCompacter:setVehicleRpmUp(dt, isActive)
	if self.attacherVehicle ~= nil and self.saveMinRpm ~= 0 then
		if dt ~= nil then
			if isActive == true then
				self.attacherVehicle.motor.minRpm = math.max(self.attacherVehicle.motor.minRpm-dt, -1000);
			else
				self.attacherVehicle.motor.minRpm = math.min(self.attacherVehicle.motor.minRpm+dt*2, self.saveMinRpm);
			end;
		else
			self.attacherVehicle.motor.minRpm = self.saveMinRpm;
		end;
		if self.attacherVehicle.isMotorStarted then
			local fuelUsed = 0.0000011*math.abs(self.attacherVehicle.motor.minRpm);
			self.attacherVehicle:setFuelFillLevel(self.attacherVehicle.fuelFillLevel-fuelUsed);
			g_currentMission.missionStats.fuelUsageTotal = g_currentMission.missionStats.fuelUsageTotal + fuelUsed;
			g_currentMission.missionStats.fuelUsageSession = g_currentMission.missionStats.fuelUsageSession + fuelUsed;
		end;
	end;
end;
	
function RotationSiloCompacter:raycastCallback(transformId, x, y, z, distance, nx, ny, nz)
	local overMovingPlane = false;
	if getUserAttribute(transformId, "movingPlanesIndex") ~= nil then
		overMovingPlane = true;
	elseif getParent(transformId) ~= nil then
		if getUserAttribute(getParent(transformId), "movingPlanesIndex") ~= nil then
			overMovingPlane = true;
		elseif getParent(getParent(transformId)) ~= nil then
			if getUserAttribute(getParent(getParent(transformId)), "movingPlanesIndex") ~= nil then
				overMovingPlane = true;
			elseif getParent(getParent(getParent(transformId))) ~= nil then
				if getUserAttribute(getParent(getParent(getParent(transformId))), "movingPlanesIndex") ~= nil then
					overMovingPlane = true;
				end;
			end;
		end;
	end;	
	
	if overMovingPlane then	
		for k,v in pairs(g_currentMission.onCreateLoadedObjects) do
			if v.className == "BunkerSilo" then			
				local nearestDistance = 1000;
				local locdistance = 0;
				local ax, ay, az = getWorldTranslation(self.bunkerSiloCompactingRefNode);
				for i=1, table.getn(v.movingPlanes) do
					local movingPlane = v.movingPlanes[i];					
					if movingPlane.shovelTrigger.nodeId == transformId then
						if movingPlane.fillLevel > 0 then
							local bx, by, bz = getWorldTranslation(movingPlane.nodeId);
							locdistance = Utils.vector3Length(ax-bx, ay-by, az-bz);
							if distance < nearestDistance then
								nearestDistance = locdistance;
								self.raycastDistance = distance;
								self.raycastTransformId = transformId;
							end;
						end;
					end;
				end;
			end;
		end;
	else
		self.raycastTransformId = nil;
	end;
end;