AgrolinerITS26 = {};

function AgrolinerITS26.prerequisitesPresent(specializations)
    Vehicle.registerJointType("HookJoint");
	print("  register joint type: HookJoint");
	return true;
end;

function AgrolinerITS26:load(xmlFile)

	self.setVehicleRpmUp = SpecializationUtil.callSpecializationsFunction("setVehicleRpmUp");
	self.setTowballDirection = SpecializationUtil.callSpecializationsFunction("setTowballDirection");

	local hydraulicsCount = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.hydraulics#count"), 0);	
	self.hydraulics = {};	
	for i=1, hydraulicsCount do
		local hydraulicName = string.format("vehicle.hydraulics.hydraulic%d", i);		
		self.hydraulics[i] = {};		
		self.hydraulics[i].node = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#index"));
		self.hydraulics[i].punch = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#punch"));
		self.hydraulics[i].translationPunch = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#punchFixpoint"));
		self.hydraulics[i].fixPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#fixpoint"));
		if self.hydraulics[i].punch ~= nil and self.hydraulics[i].translationPunch ~= nil then
			local ax, ay, az = getWorldTranslation(self.hydraulics[i].punch);
			local bx, by, bz = getWorldTranslation(self.hydraulics[i].translationPunch);		
			self.hydraulics[i].punchDistance = Utils.vector3Length(ax-bx, ay-by, az-bz);
		end;
	end;
	
	self.attacherCylinder = {};
	self.attacherCylinder.leftCylinder = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.towBallZylinder#leftZylinder"));
	self.attacherCylinder.leftPunch = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.towBallZylinder#leftZylinderPunch"));
	self.attacherCylinder.leftFixPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.towBallZylinder#leftZylinderFixPoint"));
	if self.attacherCylinder.leftPunch ~= nil then
		local ax, ay, az = getWorldTranslation(self.attacherCylinder.leftPunch);
		local bx, by, bz = getWorldTranslation(self.attacherCylinder.leftFixPoint);
		self.attacherCylinder.leftDistance = Utils.vector3Length(ax-bx, ay-by, az-bz);
	end;
	self.attacherCylinder.rightCylinder = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.towBallZylinder#rightZylinder"));
	self.attacherCylinder.rightPunch = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.towBallZylinder#rightZylinderPunch"));
	self.attacherCylinder.rightFixPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.towBallZylinder#rightZylinderFixPoint"));
	if self.attacherCylinder.rightPunch ~= nil then
		local ax, ay, az = getWorldTranslation(self.attacherCylinder.rightPunch);
		local bx, by, bz = getWorldTranslation(self.attacherCylinder.rightFixPoint);
		self.attacherCylinder.rightDistance = Utils.vector3Length(ax-bx, ay-by, az-bz);
	end;
	
	local tipAnimRootNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipAnimation#rootNode"));
	self.tipAnimCharSet = 0;
	if tipAnimRootNode ~= nil and tipAnimRootNode ~= 0 then
		self.tipAnimCharSet = getAnimCharacterSet(tipAnimRootNode);
		if self.tipAnimCharSet ~= 0 then
			local clip = getAnimClipIndex(self.tipAnimCharSet, getXMLString(xmlFile, "vehicle.tipAnimation#clip"));
			assignAnimTrackClip(self.tipAnimCharSet, 0, clip);
			setAnimTrackLoopState(self.tipAnimCharSet, 0, false);
			self.tipAnimSpeedScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.tipAnimation#speedScale"), 1);
			self.tipAnimDuration = getAnimClipDuration(self.tipAnimCharSet, clip);
		end;
	end;
	self.tipReferencePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipReferencePoint#index"));
	self.towBallAngle = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.towBallAngle#index"));
	
	self.attacherJoints[1].jointType = Vehicle.JOINTTYPE_HOOKJOINT;
	self.firstAttachOnLoad = false;
	self.firstAttachTime = 4000;
	self.attachableObject = nil;
	self.isHakenliftTrailer = true;
	self.armIsLocked = true;
	self.liftAxisAutoDown = false;
	self.saveMinRpm = 0;
	
	self.objectTipAnimDuration = nil;
	self.objectTipAnimSpeedScale = nil;
	self.objectTipDischargeEndTime = nil;
	self.objectTipState = nil;
	self.objectTipReferencePoint = nil;
	self.tipState = 0;
	
end;

function AgrolinerITS26:delete()
end;

function AgrolinerITS26:readStream(streamId, connection)

end;

function AgrolinerITS26:writeStream(streamId, connection)

end;

function AgrolinerITS26:mouseEvent(posX, posY, isDown, isUp, button)

end;

function AgrolinerITS26:keyEvent(unicode, sym, modifier, isDown)

end;

function AgrolinerITS26:update(dt)
	
	if self.firstAttachTime > 0 then
		self.firstAttachTime = self.firstAttachTime-dt;
		if not self.firstAttachOnLoad then
			local attacherJoint = self.attacherJoints[1];
			if attacherJoint.jointIndex == 0 then
				for k, attachable in pairs(g_currentMission.attachables) do
					if attachable.attacherVehicle == nil and attachable.attacherJoint.jointType == attacherJoint.jointType then
						local px, py, pz = getWorldTranslation(attacherJoint.jointTransform);
                        local vx, vy, vz = getWorldTranslation(attachable.attacherJoint.node);
                        local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
                        if distance < 0.6 then
							self:attachImplement(attachable, 1);
							self.firstAttachOnLoad = true;
						end;
					end;
				end;
			end;
		end;
	end;
	
	self:setTowballDirection();
	
	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.AGROLINERITS26_AXIS) then
			if self.animationParts[1].clipEndTime then
				self:setAnimationTime(1, self.animationParts[1].startPosition);
			elseif not self.liftAxisAutoDown then
				self:setAnimationTime(1, self.animationParts[1].animDuration);
			end;
		end;
		if InputBinding.hasEvent(InputBinding.AGROLINERITS26_LOCK) then
			self.armIsLocked = not self.armIsLocked;
		end;
		local isKeyEvent = false;
		if self.tipState == 0 then
			if InputBinding.isPressed(InputBinding.AGROLINERITS26_DOWN) and self:getIsActiveForInput() then
				self:setAnimationTime(2, self.animationParts[2].currentPosition+(self.animationParts[2].offSet*(dt/5)));
				isKeyEvent = true;
			elseif InputBinding.isPressed(InputBinding.AGROLINERITS26_UP) and self:getIsActiveForInput() then
				self:setAnimationTime(2, self.animationParts[2].currentPosition-(self.animationParts[2].offSet*(dt/5)));
				isKeyEvent = true;
			end;
		end;
		self:setVehicleRpmUp(dt, isKeyEvent);
	end;
	
	if self.liftAxisAutoDown then
		self:setAnimationTime(1, self.animationParts[1].startPosition);
	end;
	
	setJointFrame(self.attacherJoints[1].jointIndex, 0, self.attacherJoints[1].jointTransform);
	local jointDesc = self.attacherJoints[1];
	local jointLimit1 = (50/2000)*math.max(self.animationParts[2].currentPosition-3000, 0);
	local jointLimit2 = (130/2000)*math.max(self.animationParts[2].currentPosition-3000, 0);
	setJointRotationLimit(jointDesc.jointIndex, 0, true, Utils.degToRad(-0), Utils.degToRad(0));
	setJointRotationLimit(jointDesc.jointIndex, 1, true, Utils.degToRad(-jointLimit1), Utils.degToRad(jointLimit1));
	setJointRotationLimit(jointDesc.jointIndex, 2, true, Utils.degToRad(-jointLimit2), Utils.degToRad(jointLimit2));
	
	if self.armIsLocked then
		self.selectedImplement = 0;
	else
		self.selectedImplement = table.getn(self.attachedImplements);
	end;
	local mustAxisDown = false;
	for k, implements in pairs(self.attachedImplements) do
		local implement = implements.object;
		if implement.isHakenliftObject then
			if self.animationParts[2].clipStartTime then
				implement.tipReferencePoint = self.tipReferencePoint;
			else
				implement.tipReferencePoint = nil;
			end;
			self.objectTipAnimDuration = implement.tipAnimDuration;
			self.objectTipAnimSpeedScale = implement.tipAnimSpeedScale;
			self.objectTipDischargeEndTime = implement.tipDischargeEndTime;
			self.objectTipState = implement.tipState;
			self.tipState = implement.tipState;
		else
			self.objectTipAnimDuration = nil;
			self.objectTipAnimSpeedScale = nil;
			self.objectTipDischargeEndTime = nil;
			self.objectTipState = nil;
		end;
		if implement.fillLevel > 2500 then
			mustAxisDown = true;
		end;
	end;
	self.liftAxisAutoDown = mustAxisDown;
	if self.objectTipAnimDuration ~= nil and self.objectTipAnimSpeedScale ~= nil and self.objectTipDischargeEndTime ~= nil and self.objectTipState ~= nil then
		local animDuration = self.objectTipAnimDuration;
		local speedScale = self.objectTipAnimSpeedScale;
		self.tipAnimSpeedScale = self.tipAnimDuration/(animDuration/speedScale);
		if self.objectTipState == Trailer.TIPSTATE_CLOSING then
			if self.tipAnimCharSet ~= 0 then
				if getAnimTrackTime(self.tipAnimCharSet, 0) > self.tipAnimDuration then
					setAnimTrackTime(self.tipAnimCharSet, 0, self.tipAnimDuration);
				end;
				setAnimTrackSpeedScale(self.tipAnimCharSet, 0, -self.tipAnimSpeedScale);
				enableAnimTrack(self.tipAnimCharSet, 0);
			end;
		elseif self.objectTipState == Trailer.TIPSTATE_OPENING then
			if self.tipAnimCharSet ~= 0 then
				if getAnimTrackTime(self.tipAnimCharSet, 0) < 0.0 then
					setAnimTrackTime(self.tipAnimCharSet, 0, 0.0);
				end;
				setAnimTrackSpeedScale(self.tipAnimCharSet, 0, self.tipAnimSpeedScale);
				enableAnimTrack(self.tipAnimCharSet, 0);
			end;
		elseif self.objectTipState == Trailer.TIPSTATE_CLOSED then
			disableAnimTrack(self.tipAnimCharSet, 0);
		end;
	else
		setAnimTrackTime(self.tipAnimCharSet, 0, getAnimTrackTime(self.tipAnimCharSet, 0));
		setAnimTrackSpeedScale(self.tipAnimCharSet, 0, -self.tipAnimSpeedScale);
		enableAnimTrack(self.tipAnimCharSet, 0);
		if getAnimTrackTime(self.tipAnimCharSet, 0) <= 0.0 then
			disableAnimTrack(self.tipAnimCharSet, 0);
		end;
	end;
	
	if self.updateSteeringAxleAngle then
		if self.attacherVehicle ~= nil and self.movingDirection < 0 then
			local x,y,z = worldDirectionToLocal(self.steeringAxleNode, localDirectionToWorld(self.attacherVehicle.steeringAxleNode, 0, 0, 1));
			local dot = z;
			dot = dot / Utils.vector2Length(x,z);
			local angle = math.acos(dot);
			if x < 0 then
				angle = -angle;
			end;
			local startSpeed = self.steeringAxleAngleScaleStart;
			local endSpeed = self.steeringAxleAngleScaleEnd;
			local scale = Utils.clamp(1 + (self.lastSpeed*-3600-startSpeed) * 1.0/(startSpeed-endSpeed), 0, 1);
			self.steeringAxleAngle = angle*scale;
		end;
	end;
end;

function AgrolinerITS26:updateTick(dt)

	for i=1, table.getn(self.hydraulics) do
		local ax, ay, az = getWorldTranslation(self.hydraulics[i].node);
		local bx, by, bz = getWorldTranslation(self.hydraulics[i].fixPoint);
		if bx ~= nil and by ~= nil and bz ~= nil then
			local x, y, z = worldDirectionToLocal(getParent(self.hydraulics[i].node), bx-ax, by-ay, bz-az);
			setDirection(self.hydraulics[i].node, x, y, z, 0, 0, 1);
			local distance = Utils.vector3Length(ax-bx, ay-by, az-bz);
			if self.hydraulics[i].punch ~= nil and self.hydraulics[i].punchDistance ~= nil and self.hydraulics[i].translationPunch then
				if self.hydraulics[i].doScale then
					local xScale, yScale, zScale = getScale(self.hydraulics[i].punch);
					local newScale = xScale * (distance / self.hydraulics[i].punchDistance);
					setScale(self.hydraulics[i].punch, 1, 1, newScale);
				else
					setTranslation(self.hydraulics[i].punch, 0, 0, distance-self.hydraulics[i].punchDistance);
				end;
			end;
		end;
	end;
	
	local steeringAxleAngle = 0;
	if self.attacherVehicle ~= nil then
		local x,y,z = worldDirectionToLocal(self.steeringAxleNode, localDirectionToWorld(self.attacherVehicle.steeringAxleNode, 0, 0, 1));
		local dot = z;
		dot = dot / Utils.vector2Length(x,z);
		local angle = math.acos(dot);
		if x > 0 then
			angle = -angle;
		end;
		steeringAxleAngle = -angle*0.6;
	end;
	setRotation(self.towBallAngle, 0, steeringAxleAngle, 0);
end;

function AgrolinerITS26: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 AgrolinerITS26:setTowballDirection()
	if self.leftFixPoint ~= nil then
		local ax, ay, az = getWorldTranslation(self.attacherCylinder.leftCylinder);
		local bx, by, bz = getWorldTranslation(self.leftFixPoint);
		local x, y, z = worldDirectionToLocal(getParent(self.attacherCylinder.leftCylinder), bx-ax, by-ay, bz-az);
		setDirection(self.attacherCylinder.leftCylinder, x, y, z, 0, 1, 0);
		local distance = Utils.vector3Length(ax-bx, ay-by, az-bz);
		if self.attacherCylinder.leftDistance ~= nil then
			setTranslation(self.attacherCylinder.leftPunch, 0, 0, distance-self.attacherCylinder.leftDistance);
		end;
	end;
	if self.rightFixPoint ~= nil then
		local ax, ay, az = getWorldTranslation(self.attacherCylinder.rightCylinder);
		local bx, by, bz = getWorldTranslation(self.rightFixPoint);
		local x, y, z = worldDirectionToLocal(getParent(self.attacherCylinder.rightCylinder), bx-ax, by-ay, bz-az);
		setDirection(self.attacherCylinder.rightCylinder, x, y, z, 0, 1, 0);
		local distance = Utils.vector3Length(ax-bx, ay-by, az-bz);
		if self.attacherCylinder.rightDistance ~= nil then
			setTranslation(self.attacherCylinder.rightPunch, 0, 0, distance-self.attacherCylinder.rightDistance);
		end;
	end;
end;

function AgrolinerITS26:onAttach(attacherVehicle)
	self.attacherVehicle = attacherVehicle;
	if self.attacherVehicleCopy == nil then
		self.attacherVehicleCopy = self.attacherVehicle;
	end;
	self.saveMinRpm = self.attacherVehicle.motor.minRpm;
end;

function AgrolinerITS26:onDetach()
	if self.deactivateOnDetach then
        self:onDeactivate(self);
    else
        self:onDeactivateSounds(self);
    end;
	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;

function AgrolinerITS26:draw()
	if table.getn(self.attachedImplements) > 0 then
		if self.armIsLocked then
			g_currentMission:addHelpButtonText(g_i18n:getText("AgrolinerITS26_1"), InputBinding.AGROLINERITS26_LOCK);
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("AgrolinerITS26_2"), InputBinding.AGROLINERITS26_LOCK);
		end;
	end;
	g_currentMission:addExtraPrintText(string.format(""..InputBinding.getKeyNamesOfDigitalAction(InputBinding.AGROLINERITS26_UP) .. " / " .. InputBinding.getKeyNamesOfDigitalAction(InputBinding.AGROLINERITS26_DOWN)..":            "..g_i18n:getText("AgrolinerITS26_3")..""));
	if self.animationParts[1].clipEndTime then
		g_currentMission:addHelpButtonText(g_i18n:getText("AgrolinerITS26_4"), InputBinding.AGROLINERITS26_AXIS);
	elseif not self.liftAxisAutoDown then
		g_currentMission:addHelpButtonText(g_i18n:getText("AgrolinerITS26_5"), InputBinding.AGROLINERITS26_AXIS);
	end;
end;