--[[
CruiseControlExtension

Author: 	Ifko[nator]
Date:		24.12.2020
Version: 	1.1

History:	v1.0 @06.12.2020 - initial implemation in FS 19
			v1.1 @24.12.2020 - added support for vca mod
]]

CruiseControlExtension = {};
CruiseControlExtension.currentModName = g_currentModName;

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

function CruiseControlExtension.registerEventListeners(vehicleType)
	local functionNames = {
		"onLoad",
		"onUpdate",
		"onRegisterActionEvents"
	};

	for _, functionName in ipairs(functionNames) do
		SpecializationUtil.registerEventListener(vehicleType, functionName, CruiseControlExtension);
	end;
end;

function CruiseControlExtension:onLoad(savegame)
	if JohnDeerePackUtil == nil then
        return;
    end;
	
	local specCruiseControlExtension = JohnDeerePackUtil.getSpecByName(self, "cruiseControlExtension");
	
	specCruiseControlExtension.changeDelay = 250;
	specCruiseControlExtension.changeCurrentDelay = 0;
	specCruiseControlExtension.changeMultiplier = 1;
	specCruiseControlExtension.inputValue = 0;

	local modName = "";

	for _, mod in pairs(g_modManager:getActiveMods()) do
		if _G[mod.modName].vehicleControlAddon ~= nil then		
			if g_modIsLoaded[mod.modName] then	
				modName = _G[mod.modName];
			end;
        end; 
	end;

    if modName ~= "" then
		modName.vehicleControlAddon.newUpdateSpeedGauge = Utils.prependedFunction(modName.vehicleControlAddon.newUpdateSpeedGauge, CruiseControlExtension.updateSpeedGauge);
	else
		SpeedMeterDisplay.updateSpeedGauge = Utils.overwrittenFunction(SpeedMeterDisplay.updateSpeedGauge, CruiseControlExtension.updateSpeedGauge);
	end;

	SpeedMeterDisplay.drawSpeedText = Utils.overwrittenFunction(SpeedMeterDisplay.drawSpeedText, CruiseControlExtension.drawSpeedText);
	SpeedMeterDisplay.drawCruiseControlText = Utils.overwrittenFunction(SpeedMeterDisplay.drawCruiseControlText, CruiseControlExtension.drawCruiseControlText);
end;

function CruiseControlExtension:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
	local specCruiseControlExtension = JohnDeerePackUtil.getSpecByName(self, "cruiseControlExtension");
	local specDrivable = JohnDeerePackUtil.getSpecByName(self, "drivable");
	
	if self:getIsActive() then
		for _, input in pairs({"CRUISE_CONTROL_EXTENSION_DOWN_BUTTON", "CRUISE_CONTROL_EXTENSION_UP_BUTTON"}) do
			local inputButton = specCruiseControlExtension.actionEvents[InputAction[input]];
			local inputValueCahngeAllowed = false;
			local cruiseControllSpeed = math.floor(self:getCruiseControlSpeed());
			
			if input == "CRUISE_CONTROL_EXTENSION_DOWN_BUTTON" then
				inputValueCahngeAllowed = cruiseControllSpeed > (specDrivable.cruiseControl.minSpeed / 10);
			else
				inputValueCahngeAllowed = cruiseControllSpeed < specDrivable.cruiseControl.maxSpeed;
			end;

			if inputButton ~= nil then
				g_inputBinding:setActionEventTextVisibility(inputButton.actionEventId, inputValueCahngeAllowed);
			end;
		end;

		local lastInputValue = specCruiseControlExtension.inputValue;
		specCruiseControlExtension.inputValue = 0;

		if lastInputValue ~= 0 then
			specCruiseControlExtension.changeCurrentDelay = specCruiseControlExtension.changeCurrentDelay - dt * specCruiseControlExtension.changeMultiplier;
			specCruiseControlExtension.changeMultiplier = math.min(specCruiseControlExtension.changeMultiplier + dt * 0.003, 5);

			if specCruiseControlExtension.changeCurrentDelay < 0 then
				specCruiseControlExtension.changeCurrentDelay = specCruiseControlExtension.changeDelay;
				local dir = MathUtil.sign(lastInputValue);
				local speed = specDrivable.cruiseControl.speed + (dir/10);

				self:setCruiseControlMaxSpeed(speed);

				if specDrivable.cruiseControl.speed ~= specDrivable.cruiseControl.speedSent then
					if g_server ~= nil then
						g_server:broadcastEvent(SetCruiseControlSpeedEvent:new(self, specDrivable.cruiseControl.speed), nil, nil, self);
					else
						g_client:getServerConnection():sendEvent(SetCruiseControlSpeedEvent:new(self, specDrivable.cruiseControl.speed));
					end;

					specDrivable.cruiseControl.speedSent = specDrivable.cruiseControl.speed;
				end;
			end;
		else
			specCruiseControlExtension.changeCurrentDelay = 0;
			specCruiseControlExtension.changeMultiplier = 1;
		end;
	end;
end;

function CruiseControlExtension:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
	if self.isClient then
		local specCruiseControlExtension = JohnDeerePackUtil.getSpecByName(self, "cruiseControlExtension");

		self:clearActionEventsTable(specCruiseControlExtension.actionEvents);
		
		if isActiveForInputIgnoreSelection then
			for _, input in pairs({"CRUISE_CONTROL_EXTENSION_DOWN_BUTTON", "CRUISE_CONTROL_EXTENSION_UP_BUTTON"}) do
				local _, actionEventId = self:addActionEvent(specCruiseControlExtension.actionEvents, InputAction[input], self, CruiseControlExtension.actionEventCruiseControlLevelExtension, false, true, true, true, nil);
			
				g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_HIGH);
			end;
		end;
	end;
end;

function CruiseControlExtension.actionEventCruiseControlLevelExtension(self, actionName, inputValue, callbackState, isAnalog)
	local specCruiseControlExtension = JohnDeerePackUtil.getSpecByName(self, "cruiseControlExtension");
	
	if actionName == "CRUISE_CONTROL_EXTENSION_DOWN_BUTTON" then
		inputValue = -1;
	end;
	
	specCruiseControlExtension.inputValue = inputValue;
end;

function CruiseControlExtension:updateSpeedGauge(superFunc, dt)
	local kmh = math.max(0, self.vehicle:getLastSpeed() * self.vehicle.spec_motorized.speedDisplayScale);

	local specCruiseControlExtension = JohnDeerePackUtil.getSpecByName(self.vehicle, "cruiseControlExtension");
	local specDrivable = JohnDeerePackUtil.getSpecByName(self.vehicle, "drivable");
	
	local cruiseControlIsActive = specDrivable.cruiseControl.state ~= Drivable.CRUISECONTROL_STATE_OFF;
	local minSpeedBeforeZero = 0.1;

	if specCruiseControlExtension == nil or not cruiseControlIsActive then
		minSpeedBeforeZero = 0.5;
	end;

	if kmh < minSpeedBeforeZero then
		kmh = 0;
	end;

	self.speedKmh = kmh;

	local gaugeValue = MathUtil.clamp(kmh / (self.vehicle.spec_drivable.cruiseControl.maxSpeed * 1.1), 0, 1);
	local indicatorRotation = MathUtil.lerp(SpeedMeterDisplay.ANGLE.SPEED_GAUGE_MIN, SpeedMeterDisplay.ANGLE.SPEED_GAUGE_MAX, gaugeValue);

	self:updateGaugeIndicator(self.speedIndicatorElement, self.speedIndicatorRadiusX, self.speedIndicatorRadiusY, indicatorRotation);
	self:updateGaugeFillSegments(self.speedGaugeSegmentElements, gaugeValue);
	self:updateGaugePartialSegments(self.speedGaugeSegmentPartElements, indicatorRotation, 1, self.speedGaugeRadiusX, self.speedGaugeRadiusY, SpeedMeterDisplay.ANGLE.SPEED_GAUGE_MIN, SpeedMeterDisplay.ANGLE.SPEED_GAUGE_SEGMENT_FULL, SpeedMeterDisplay.ANGLE.SPEED_GAUGE_SEGMENT_SMALLEST);
end;

function CruiseControlExtension:drawSpeedText(superFunc)
	if self.vehicle == nil then
		return;
	end;

	local specCruiseControlExtension = JohnDeerePackUtil.getSpecByName(self.vehicle, "cruiseControlExtension");
	local specDrivable = JohnDeerePackUtil.getSpecByName(self.vehicle, "drivable");
	
	local cruiseControlIsActive = specDrivable ~= nil and specDrivable.cruiseControl.state ~= Drivable.CRUISECONTROL_STATE_OFF;
	local speed = self.speedKmh;
	local roundValue = 1;
	
	if specCruiseControlExtension == nil or not cruiseControlIsActive then
		speed = math.floor(self.speedKmh);
		roundValue = 0;

		if math.abs(self.speedKmh - speed) > 0.5 then
			speed = speed + 1;
		end;
	end;

	local speedI18N = MathUtil.round(g_i18n:getSpeed(speed), roundValue);
	local speedUnit = utf8ToUpper(g_i18n:getSpeedMeasuringUnit());
	local posX, posY = self.gaugeBackgroundElement:getPosition();

	posX = posX + self.gaugeBackgroundElement:getWidth() * 0.5;

	setTextColor(unpack(SpeedMeterDisplay.COLOR.SPEED_TEXT));
	setTextBold(false);
	setTextAlignment(RenderText.ALIGN_CENTER);
	renderText(posX, posY + self.speedTextOffsetY, self.speedTextSize, tostring(speedI18N));
	setTextColor(unpack(SpeedMeterDisplay.COLOR.SPEED_UNIT));
	renderText(posX, posY + self.speedUnitTextOffsetY, self.speedUnitTextSize, speedUnit);
end;

function CruiseControlExtension:drawCruiseControlText(supeRFunc)
	if self.vehicle == nil then
		return;
	end;
	
	if self.cruiseControlElement:getVisible() then
		setTextAlignment(RenderText.ALIGN_LEFT);
		setTextColor(unpack(self.cruiseControlColor));
		setTextBold(true);

		local specCruiseControlExtension = JohnDeerePackUtil.getSpecByName(self.vehicle, "cruiseControlExtension");
		local roundValue = 1;
		local textSizeMultiplikator = 0.8;

		if specCruiseControlExtension == nil then
			roundValue = 0;
			textSizeMultiplikator = 1;
		end;

		local speedText = MathUtil.round(g_i18n:getSpeed(self.cruiseControlSpeed), roundValue);
		local baseX, baseY = self.cruiseControlElement:getPosition();
		local posX = baseX + self.cruiseControlElement:getWidth() + self.cruiseControlTextOffsetX;
		local posY = baseY + self.cruiseControlTextOffsetY;

		renderText(posX, posY, self.cruiseControlTextSize * textSizeMultiplikator, tostring(speedText));
	end;
end;