--
-- Transmission
-- Specialization that can simulate any delta powershift transmission
--
-- @author  Templaer
-- @date  19/11/09
--

Transmission = {};

function Transmission.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Acceleration, specializations);
end;

function Transmission:load(xmlFile)
	self.doPowershift = SpecializationUtil.callSpecializationsFunction("doPowershift");
	self.doRangeShift = SpecializationUtil.callSpecializationsFunction("doRangeShift");
	self.motorManagement = SpecializationUtil.callSpecializationsFunction("motorManagement");	
	self.transmission = SpecializationUtil.callSpecializationsFunction("transmission");
	self.updateTimer = SpecializationUtil.callSpecializationsFunction("updateTimer");
		
	self.hasAutoMode = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.hasAutoMode"), true);
	self.autoModeEnabled = false;
	
	self.numRanges = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.numRanges#count"), 4);
	self.numLevels = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.numLevels#count"), 6);
	self.currentLevel = 1;
    self.currentRange = math.min(Utils.getNoNil(getXMLInt(xmlFile, "vehicle.startingRange#number"), 3), self.numRanges) - 1;
	
	self.timer = 0;
	self.timerId = 0;
		
	self.backupMaxRpm = self.motor.maxRpm[3];
	self.backupMinRpm = self.motor.minRpm;
	
	local totalGears = self.numRanges * self.numLevels;
	local totalFieldGears = (self.numRanges - 1) * self.numLevels;
	local stepSize = self.motor.maxRpm[3] / totalGears;
	local correctionDown = (self.motor.maxRpm[3] / 2) / (totalFieldGears * stepSize);
	local correctionUp = 0.95 - correctionDown;
	
	self.rpmTable = {};
	for i = 0, self.numRanges-1 do
		self.rpmTable[i] = {}; 
		for j = 0, self.numLevels-1 do
			local currentRpm = (i * (self.motor.maxRpm[3] / self.numRanges) + (j+1) * self.motor.maxRpm[3] / self.numRanges / self.numLevels);
			if i < self.numRanges - 1 then	
				self.rpmTable[i][j] = currentRpm * correctionDown;
			else
				self.rpmTable[i][j] = currentRpm * (correctionUp + ((1 - correctionUp) / self.numLevels) * (j+1));
			end;
		end;
	end;
end;

function Transmission:delete()
end;

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

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

function Transmission:update(dt)
    if self.isMotorStarted and self.isEntered then			
		self:transmission(dt);
		self:motorManagement();
	end;
end;

function Transmission:draw()
	if self.isMotorStarted then
		if self.hasAutoMode then
			self:addTransmissionText(InputBinding.AUTOMATIC, g_i18n:getText("Automatic"));
		end;
		if self.autoModeEnabled then
			self:addTransmissionStats(string.format("%s/%s:", InputBinding.getKeyNamesOfDigitalAction(InputBinding.RANGEUP), InputBinding.getKeyNamesOfDigitalAction(InputBinding.RANGEDOWN)), string.format("Range %c auto", self.currentRange + 65));
			self:addTransmissionStats(string.format("%s/%s:", InputBinding.getKeyNamesOfDigitalAction(InputBinding.LEVELUP), InputBinding.getKeyNamesOfDigitalAction(InputBinding.LEVELDOWN)), string.format("Level %d auto", self.currentLevel));	
		else
			self:addTransmissionStats(string.format("%s/%s:", InputBinding.getKeyNamesOfDigitalAction(InputBinding.RANGEUP), InputBinding.getKeyNamesOfDigitalAction(InputBinding.RANGEDOWN)), string.format("Range %c", self.currentRange + 65));
			self:addTransmissionStats(string.format("%s/%s:", InputBinding.getKeyNamesOfDigitalAction(InputBinding.LEVELUP), InputBinding.getKeyNamesOfDigitalAction(InputBinding.LEVELDOWN)), string.format("Level %d", self.currentLevel));
		end;
	end;
end;

function Transmission:onLeave()
	self.motor.minRpm = self.backupMinRpm;
end;

function Transmission:stopMotor()
	self.motor.minRpm = self.backupMinRpm;
end;

-- Additional function(s)
function Transmission:doPowershift(direction)
	if direction == 1 and self.currentLevel < self.numLevels or direction == -1 and self.currentLevel > 1 then
		self.currentLevel = self.currentLevel + direction;
		self.motor.minRpm = direction * 200;
		self.timer = 0;
	end;
end;

function Transmission:doRangeShift(direction)
	if direction == 1 and self.currentRange < self.numRanges - 1 or direction == -1 and self.currentRange > 0 then
		self.currentRange = self.currentRange + direction;
		self.motor.minRpm = direction * 300;
		if self.autoModeEnabled then
			if direction == 1 then
				self.currentLevel = 1;
			else
				self.currentLevel = self.numLevels;
			end;
		end;
	end;
end;

function Transmission:motorManagement()
	if not self.playMotorSound and g_currentMission.allowSteerableMoving then
		if self.motor.lastMotorRpm < (self.motor.maxRpm[1] - 200) or self.motor.lastMotorRpm > self.motor.maxRpm[1] or self.currentLevel < self.numLevels and self.autoModeEnabled then
			if self.lastRoundPerMinute < math.abs(self.acceleration) * self.backupMaxRpm then
				self.motor.minRpm = self.motor.minRpm - 15;
			else
				self.motor.minRpm = math.min(self.motor.minRpm + 15, self.backupMinRpm);
			end;
		else
			if self.lastRoundPerMinute < (self.backupMaxRpm * 0.625) then
				self.motor.minRpm = self.motor.minRpm - 15;
			elseif self.lastRoundPerMinute > (self.backupMaxRpm * 0.65) then
				self.motor.minRpm = self.motor.minRpm + 15;
			end;
		end;
	end;
end;

function Transmission:transmission(dt)
	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.RANGEUP) then
			self:doRangeShift(1);
		end;
		
		if InputBinding.hasEvent(InputBinding.RANGEDOWN) then
			self:doRangeShift(-1);
		end;
			
		if InputBinding.hasEvent(InputBinding.LEVELUP) then
			self:doPowershift(1);
		end;
		
		if InputBinding.hasEvent(InputBinding.LEVELDOWN) then
			self:doPowershift(-1);
		end;
		
		if InputBinding.hasEvent(InputBinding.AUTOMATIC) then
			if self.hasAutoMode  then
				self.autoModeEnabled = not self.autoModeEnabled;
			end;
		end;
	end;

	self.motor.maxRpm[1] = self.rpmTable[self.currentRange][self.currentLevel-1];
						
	if self.autoModeEnabled and not self.playMotorSound and g_currentMission.allowSteerableMoving then
		if math.abs(self.acceleration) > 0.8 then	
			if self.lastRoundPerMinute > 1600 then
				self:updateTimer(1, dt);
			else
				self.timer = 0;
			end;
			
			if self.timer > 1.5 then
				self:doPowershift(1);
			end;
		elseif math.abs(self.acceleration) < 0.4 then
			if self.lastRoundPerMinute < 1000 then
				self:updateTimer(2, dt);
			else 
				self.timer = 0;
			end;
			
			if self.timer > 1.25 then
				self:doPowershift(-1);		
			end;	
		end;				
	end;
end;

function Transmission:updateTimer(timerId, dt)
	if self.timerId ~= timerId then
		self.timer = 0;
		self.timerId = timerId;
	else
		self.timer = self.timer + (dt / 1000);
	end;
end;
