--
-- manualIgnition
-- Specialization for manual motor ignition
--
-- @v1: Templaer - 01 May   2009
-- @v2: Henly20  - 24 April 2012
-- 
-- @author:    	Xentro (www.fs-uk.com)(Marcus@Xentro.se)
-- @version:    v3.063 none global edition
-- @date:       2014-02-06
-- 
--
--[[
xml for dash lights, add as many as you want. (add <dashLight index="" /> after comment. (line 21))
<dashLights>
	<dashLight index="" />
	<!-- add more after this line if you want more dash lights -->
	
</dashLights>

Replace x y z with you rotation value.
off = engine off
on = engine on
start = this is the stage where key is on "start motor"
<key index="" off="x y z" on="x y z" start="x y z" />

-- other options --

preHeatStart - This will stop user from starting while preHeatHud is displayed.
preHeat - How long the pre heat mode should be.

<manualIgnition preHeatStart="false" preHeat="1400" />

idleFuelUsage - Fuel usage when not moving and motor is on, in percentage.
realIdlePercentFuelUsage = MR variable

<fuelUsage idleFuelUsage="10" realIdlePercentFuelUsage="0.03" />
]]--

manualIgnition = {};

manualIgnition.NORMAL = 0;

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

function manualIgnition:load(xmlFile)
	self.setManualIgnitionMode = SpecializationUtil.callSpecializationsFunction("setManualIgnitionMode");
	self.overrideIgnitionInput = false;
	
	if self.motorStopSound ~= nil then
		self.motorStopSoundNew = self.motorStopSound;
		self.motorStopSoundVolumeNew = self.motorStopSoundVolume;
	end;
	
	self.ignitionType = manualIgnition.NORMAL;
	
	self.playedMotorStopSoundNew = true;
	self.ignitionKey = false;
	self.allowedIgnition = false;
	self.isMotorStarted = false;
	self.overrideHud = false;
	
	self.motorStopSoundVolume = 0;
	self.ignitionMode = 0;

	self.dashLights = {};
	self.dashLights.activated = false;
	self.dashLights.table = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.dashLights.dashLight(%d)", i);
		if not hasXMLProperty(xmlFile, key) then break; end;
		
		local index = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#index"));
		if index ~= nil then
			table.insert(self.dashLights.table, {node = index});
			i = i + 1;
		end;		
	end;
	
	local keyPath = "vehicle.key";
	self.key = {};
	self.key.mode = 0;
	self.key.lastMode = 0;
	if hasXMLProperty(xmlFile, keyPath) then
		local index = getXMLString(xmlFile, keyPath .. "#index")
		if index ~= nil then
			self.key.node = Utils.indexToObject(self.components, index);
			
			local off = Utils.getRadiansFromString(getXMLString(xmlFile, keyPath .. "#off"), 3);
			local on = Utils.getRadiansFromString(getXMLString(xmlFile, keyPath .. "#on"), 3);
			local start = Utils.getRadiansFromString(getXMLString(xmlFile, keyPath .. "#start"), 3);
			
			if off == nil then
				local x, y, z = getRotation(self.key.node);
				off = {x, y, z};
			end;
			
			if on ~= nil and start ~= nil then
				self.key.rot = {};
				self.key.rot['off'] = off;
				self.key.rot['on'] = on;
				self.key.rot['start'] = start;
			else
				print('Error: <key> is missing a value for on="x y z" or starting="x y z" in ' .. self.configFileName);
			end;
		end;
	end;
	
	self.heater = {};
	self.heater["fastStart"] = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.manualIgnition#preHeatStart"), false);
	self.heater["maxTime"] = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.manualIgnition#preHeat"), 1200);
	self.heater["currentTime"] = 0;
	self.heater["maxHeatMin"] = 10;
	self.heater["CurrentHeatMin"] = 0; 
		
	self.idleFuelUsage = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fuelUsage#idleFuelUsage"), 10) / 100;
	
	self.activeErrorTime = 0;
	self.activeError = "";
	
	if self.isRealistic ~= nil and self.isRealistic then
		self.realIdlePercentFuelUsage = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fuelUsage#realIdlePercentFuelUsage"), 0.03);
	end;
		
	self:addConflictCheckedInput(InputBinding.MANUAL_IGNITION_1);
end;

function manualIgnition:delete()
end;

function manualIgnition:readStream(streamId, connection)
	self:setManualIgnitionMode(streamReadInt8(streamId), true);
end;

function manualIgnition:writeStream(streamId, connection)
	streamWriteInt8(streamId, self.ignitionMode);
end;

function manualIgnition:mouseEvent(posX, posY, isDown, isUp, button)
end;

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

function manualIgnition:update(dt)
	if self:getIsActive() and self:getIsActiveForInput(false) and self.isClient and not self.overrideIgnitionInput and not self:hasInputConflictWithSelection() then
		if self.fuelFillLevel > 0 then			
			if InputBinding.hasEvent(InputBinding.MANUAL_IGNITION_1) then
				if self.ignitionMode > 2 then
					self.ignitionMode = 0;
				end;
				local allow = false;
				local errorId = 0;
				local steps = 1;
				
				if self.ignitionType == manualIgnition.NORMAL then
					if self.ignitionMode ~= 1 or (self.ignitionMode == 1 and (self.heater["currentTime"] == 0 and not self.heater["fastStart"]) or (self.heater["fastStart"] and self.heater["currentTime"] >= 0)) then
						allow = true;
					else
						errorId = 1;
					end;
				end;
				
				if allow then
					self:setManualIgnitionMode(self.ignitionMode + steps);
				else
					self.activeErrorTime = self.time + 1000;
					
					if errorId == 1 then
						self.activeError = g_i18n:getText("MANUAL_IGNITION_5");
					end;
				end;
			end;
			
			if InputBinding.isPressed(InputBinding.MANUAL_IGNITION_1) and self.ignitionMode == 2 then
				self.key.mode = 2;
			else		
				if self.isMotorStarted then
					self.key.mode = 1;
				end;
			end;
			
			if (self.axisForward < -0.5 or self.axisForward > 0.5) and self.ignitionMode == 0 then
				self.activeErrorTime = self.time + 800;
				self.activeError = g_i18n:getText("MANUAL_IGNITION_4");
			end;
		end;
	end;
 end;

function manualIgnition:updateTick(dt)
	local speed = dt / 60000 * g_currentMission.environment.timeScale;
	
	if self.isMotorStarted then
		if self.heater["CurrentHeatMin"] < self.heater["maxHeatMin"] then
			self.heater["CurrentHeatMin"] = self.heater["CurrentHeatMin"] + speed;
		end;
	else
		if self.heater["CurrentHeatMin"] > 0 then
			local rainAffect = 4;
			if g_currentMission.environment.currentRain ~= nil and g_currentMission.environment.currentRain.rainTypeId == "rain" then
				if g_currentMission.environment.lastRainScale > 0.01 then
					rainAffect = 2;
				end;
			end;
			
			self.heater["CurrentHeatMin"] = self.heater["CurrentHeatMin"] - (speed / rainAffect);
			speed = speed / rainAffect;
		end;
	end;
	
	if self.ignitionMode == 1 then
		if self.heater["currentTime"] > 0 then
			self.heater["currentTime"] = math.max(self.heater["currentTime"] - dt, 0);
		end;
	end;
	
	if self:getIsActive() then
		local key = self.key;
		if key.mode ~= key.lastMode then
			if key.rot ~= nil then
				if key.mode == 1 then
					setRotation(key.node, unpack(key.rot['on']));
				elseif key.mode == 2 then
					setRotation(key.node, unpack(key.rot['start']));
				else
					setRotation(key.node, unpack(key.rot['off']));
				end;
			end;
			key.lastMode = key.mode;
		end;
		
		if self.ignitionMode ~= 1 then
			local updateTime = self.heater["maxTime"];
			local updateHeat = updateTime * (self.heater["CurrentHeatMin"] / self.heater["maxHeatMin"]);
			updateTime = updateTime - updateHeat
			
			if self.heater["currentTime"] ~= updateTime then
				self.heater["currentTime"] = updateTime;
			end;
		end;
	end;
	
	local stopAI = false;
	if not self:getIsHired() then
		if self.ignitionKey and self.allowedIgnition then
			self:startMotor(true);
			self.deactivateOnLeave = false;
			Utils.setEmittingState(self.exhaustParticleSystems, true)
			self.allowedIgnition = false;
		elseif not self.ignitionKey and self.allowedIgnition then
			self:stopMotor(true);
			self.deactivateOnLeave = true;
			self.allowedIgnition = false;
		elseif self.ignitionKey and not self.allowedIgnition and self.deactivateOnLeave then
			self.deactivateOnLeave = false;
		end;

		if not self.playedMotorStopSoundNew and self.motorStopSoundNew ~= nil then
			playSample(self.motorStopSoundNew, 1, self.motorStopSoundVolumeNew, 0);
			self.playedMotorStopSoundNew = true;
		end;
	elseif not self.ignitionKey and not self.deactivateOnLeave then
		stopAI = true;
	end;
	
	if self.ignitionMode ~= 2 or self.motorStartTime > self.time and self.ignitionMode == 2 then
		local stop = false;
		
		for _, implement in pairs(self.attachedImplements) do
			local tool = implement.object;
			if (tool.getIsPowerTakeoffActive ~= nil and tool:getIsPowerTakeoffActive()) 
			or (tool.isTurnedOn ~= nil and tool.isTurnedOn)
			or (tool.isThreshing ~= nil and tool.isThreshing) 
			or (tool.isInWorkPosition ~= nil and tool.isInWorkPosition) 
			or (tool.foldMoveDirection ~= nil and tool.foldMoveDirection ~= 0) then
				stop = true;
				break;
			end;
		end;
		
		if (self.getIsTurnedOn ~= nil and self:getIsTurnedOn()) -- custom function that returns bool value of your custom "isTurnedOn" variable
		or (self.isTurnedOn ~= nil and self.isTurnedOn)
		or (self.isThreshing ~= nil and self.isThreshing)
		or (self.isInWorkPosition ~= nil and self.isInWorkPosition)
		or (self.foldMoveDirection ~= nil and self.foldMoveDirection ~= 0) then
			stop = true;
		end;
		
		if stop then
			self:onDeactivate(true);
			self:onDeactivateSounds(true);
			stopAI = true;
		end;
	end;
	
	if self.isBroken or (not self.ignitionKey and self.ignitionMode == 2) then
		stopAI = true;
		if self.ignitionMode ~= 0 then
			self:setManualIgnitionMode(0, true);
		end;
	elseif self.fuelFillLevel == 0 then
		stopAI = true;
		if self.ignitionMode ~= 0 then
			self:setManualIgnitionMode(0, true);
		end;
	end;
	
	if stopAI then
		if self:getIsHired() then
			if SpecializationUtil.hasSpecialization(AICombine, self.specializations) then
				AICombine.stopAIThreshing(self, true);
			end;
			if SpecializationUtil.hasSpecialization(AITractor, self.specializations) then
				AITractor.stopAITractor(self, true);
			end;
		end;
	end;
	
	for _, v in ipairs(self.dashLights.table) do
		if getVisibility(v.node) ~= self.dashLights.activated then
			setVisibility(v.node, self.dashLights.activated);
		end;
	end;
	
	if self.isMotorStarted and not self:getIsHired() and self.isServer and not self.isFuelFilling then
		local fuelUsed = self.fuelUsage * self.idleFuelUsage;
		
		if self.isRealistic ~= nil and self.isRealistic then
			if self.isActive then
				fuelUsed = 0;
			else
				fuelUsed = self.realIdlePercentFuelUsage * self.realMaxFuelUsage * dt / (1000 * 3600); -- 3% of max fuel usage in Liter per hour
			end;
		end;
		
		if fuelUsed > 0 then
			self:setFuelFillLevel(self.fuelFillLevel - fuelUsed);
			g_currentMission.missionStats.fuelUsageTotal = g_currentMission.missionStats.fuelUsageTotal + fuelUsed;
			g_currentMission.missionStats.fuelUsageSession = g_currentMission.missionStats.fuelUsageSession + fuelUsed;
		end;
	end;
end;

function manualIgnition:onLeave()
	if not self.deactivateOnLeave then
		Utils.setEmittingState(self.exhaustParticleSystems, true)
		self.allowedIgnition = false;
		self.isMotorStarted = true;
		self.ignitionKey = true;

		self.lastAcceleration = 0;
		self.lastRoundPerMinute = 0;
		self.motor.lastMotorRpm = self.motor.minRpm;
	
		if self.isServer and (self.isRealistic == nil or (self.isRealistic ~= nil and not self.isRealistic)) then
			for k,wheel in pairs(self.wheels) do
				setWheelShapeProps(wheel.node, wheel.wheelShape, 0, self.motor.brakeForce, 0);
			end;
		end;
	else
		self.allowedIgnition = false;
		self.ignitionKey = false;
		self.key.mode = 0;
	end;
end;

function manualIgnition:onEnter()
	if not self.ignitionKey then
		self.isMotorStarted = false;
		Motorized.stopSounds(self);
		Utils.setEmittingState(self.exhaustParticleSystems, false)
	else
		if self.ignitionMode == 2 then
			self.allowedIgnition = true;
			self.ignitionKey = true;
			self.key.mode = 1;
		end;	
	end;
end;

function manualIgnition:draw()
	if g_currentMission.showHelpText and self.isClient then
		if self.fuelFillLevel <= 0 then
			g_currentMission:addExtraPrintText(g_i18n:getText("MANUAL_IGNITION_7"));
		else
			if self.ignitionType == manualIgnition.NORMAL then
				if self.ignitionMode == 0 then
					g_currentMission:addHelpButtonText(g_i18n:getText("MANUAL_IGNITION_6"), InputBinding.MANUAL_IGNITION_1);
				elseif self.ignitionMode == 1 then
					if self.heater["currentTime"] > 0 then
						g_currentMission:addExtraPrintText(g_i18n:getText("MANUAL_IGNITION_3"));
					else
						g_currentMission:addHelpButtonText(g_i18n:getText("MANUAL_IGNITION_2"), InputBinding.MANUAL_IGNITION_1);
					end;
				end;
			end;
		end;
	end;
	
	if g_currentMission.ignitionOverlay ~= nil and not self.overrideHud and self.fuelFillLevel > 0 then
		if ((self.ignitionMode <= 1) or ((self.motorStartTime + 3000) > self.time)) then
			g_currentMission.ignitionOverlay[1]:render();
			if self.key.mode >= 1 and self.ignitionMode <= 1 then
				g_currentMission.ignitionOverlay[2]:render();
			end;
			if self.heater["currentTime"] > 0 and self.ignitionMode == 1 then
				g_currentMission.ignitionOverlay[3]:render();
			end;
			if self.ignitionMode == 2 then
				g_currentMission.ignitionOverlay[4]:render();
			end;
		end;
	end;
	
	if self.activeErrorTime > self.time then
		g_currentMission:addWarning(self.activeError, 0.018, 0.033);
	end;
end;

function manualIgnition:setManualIgnitionMode(ignition, noEventSend)
	manualIgnitionEvent.sendEvent(self, ignition, noEventSend);

	self.ignitionMode = ignition;
	self.key.mode = 0;
    self.lastAcceleration = 0;
	
    self.ignitionKey = false;
	self:stopMotor(true);
	self.allowedIgnition = false;
	self.deactivateOnLeave = true;
	self.dashLights.activated = false;
	
	if self.ignitionMode == 1 then
		self.key.mode = 1;
		self.dashLights.activated = true;
	elseif self.ignitionMode == 2 then
		self.ignitionKey = true;
		self.key.mode = 1;
		self.allowedIgnition = true;
	elseif self.ignitionMode > 2 then
		self.ignitionMode = 0;
		self.playedMotorStopSoundNew = false;
	end;
	
	if self.isServer and (self.isRealistic == nil or (self.isRealistic ~= nil and not self.isRealistic)) and self.ignitionMode ~= 2 then
		for k, wheel in ipairs(self.wheels) do
			setWheelShapeProps(wheel.node, wheel.wheelShape, 0, self.motor.brakeForce, 0);
		end;
    end;
end;


manualIgnitionEvent = {};
manualIgnitionEvent_mt = Class(manualIgnitionEvent, Event);

InitEventClass(manualIgnitionEvent, "manualIgnitionEvent");

function manualIgnitionEvent:emptyNew()
    local self = Event:new(manualIgnitionEvent_mt);
    self.className = "manualIgnitionEvent";
    return self;
end;

function manualIgnitionEvent:new(vehicle, ignition)
    local self = manualIgnitionEvent:emptyNew()
    self.vehicle = vehicle;
	self.ignition = ignition;
    return self;
end;

function manualIgnitionEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.ignition = streamReadInt8(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function manualIgnitionEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteInt8(streamId, self.ignition);
end;

function manualIgnitionEvent:run(connection)
	self.vehicle:setManualIgnitionMode(self.ignition, true);
	if not connection:getIsServer() then
		g_server:broadcastEvent(manualIgnitionEvent:new(self.vehicle, self.ignition), nil, connection, self.object);
	end;
end;

function manualIgnitionEvent.sendEvent(vehicle, ignition, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(manualIgnitionEvent:new(vehicle, ignition), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(manualIgnitionEvent:new(vehicle, ignition));
		end;
	end;
end;