--
-- Cabsuspension
-- Specialization for Cabsuspension
--
-- @author	JoXXer
-- @date	17/09/11
--
-- @history	v1.0 - Initial implementation
--				v1.1 - 18/03/12 - Added springStiffness to reduce bouncyness
--				v1.2-  28/10/12 - Added maxMovement to reduce "twitching" in FS13
--

Cabsuspension = {};

function Cabsuspension.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Motorized, specializations);
end;

function Cabsuspension:load(xmlFile)
	-- Cabsuspension animation
	self.cab = {};
	self.cab.rotNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.cab#rotNode"));
	self.cab.springStiffness = getXMLFloat(xmlFile, "vehicle.cab#springStiffness");

	if self.cab.rotNode~=nil then
		local x,y,z = getTranslation(self.cab.rotNode);
		self.startCabXTranslation = x;
		self.startCabYTranslation = y;
		self.startCabZTranslation = z;

		local xRot,yRot,zRot = getRotation(self.cab.rotNode);
		self.startCabXRot = xRot;
		self.startCabYRot= yRot;
		self.startCabZRot= zRot;

		self.cabXRot = xRot;
		self.cabZrot = zRot;
	end;

	self.frontLeftWheelReal = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.frontLeftWheel#realWheel"));
	self.frontRightWheelReal = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.frontRightWheel#realWheel"));
	self.backLeftWheelReal = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.backLeftWheel#realWheel"));
	self.backRightWheelReal = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.backRightWheel#realWheel"));

	if self.frontLeftWheelReal == nil then
		if self.wheels[3].repr ~= nil and self.wheels[4].repr ~= nil and self.wheels[1].repr ~= nil and self.wheels[2].repr ~= nil then
			local x,y,z = getTranslation(self.wheels[3].repr);
			local x2,y2,z2 = getTranslation(self.wheels[4].repr);
			local x3,y3,z3 = getTranslation(self.wheels[1].repr);
			local x4,y4,z4 = getTranslation(self.wheels[2].repr);

			self.wheelYTranslationDifference = self.startCabYTranslation - ((y + y2)/2);
			self.frontAndRearWheelYTranslationDifference = y - y4;
			self.averageYTranslationCab = (y + y2)/2;
			self.averageYTranslationCabFront = (y3 + y4)/2;
		end;
	else
		local x,y,z = getTranslation(self.backLeftWheelReal);
		local x2,y2,z2 = getTranslation(self.backRightWheelReal);
		local x3,y3,z3 = getTranslation(self.frontLeftWheelReal);
		local x4,y4,z4 = getTranslation(self.frontRightWheelReal);

		self.wheelYTranslationDifference = self.startCabYTranslation - ((y + y2)/2);
		self.frontAndRearWheelYTranslationDifference = y - y4;
		self.averageYTranslationCab = (y + y2)/2;
		self.averageYTranslationCabFront = (y3 + y4)/2;
	end;

	self.cabTranslation = self.averageYTranslationCab;
	self.maxTranslationPrCycle = 0.00008;
	self.maxMovement = 0.01;
	self.oldTrans = 0;

	-- Seat animation
	self.seatNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.seatNode#index"));
	self.seatSuspensionNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.seatNode#seatBase"));

	if self.seatNode ~=nil then
		local x,y,z = getTranslation(self.seatNode);
		self.startSeatXTranslation = x;
		self.startSeatYTranslation = y;
		self.startSeatZTranslation = z;
	end;

	if self.wheels[3].repr ~= nil and self.wheels[4].repr ~= nil then
		if self.backLeftWheelReal == nil then
			local x,y,z = getTranslation(self.wheels[3].repr);
			local x2,y2,z2 = getTranslation(self.wheels[4].repr);

			self.averageYTranslation = (y + y2)/2;
		else
			local x,y,z = getTranslation(self.backLeftWheelReal);
			local x2,y2,z2 = getTranslation(self.backRightWheelReal);

			self.averageYTranslation = (y + y2)/2;
		end;
	end;

	self.maxSeatTranslationPrCycle = 0.00008;
	self.seatTranslation = self.averageYTranslation;
	self.defaultPosition = self.averageYTranslation;
end;

function Cabsuspension:delete()
end;

function Cabsuspension:readStream(streamId, connection)
end;

function Cabsuspension:writeStream(streamId, connection)
end;

function Cabsuspension:readUpdateStream(streamId, timestamp, connection)
end;

function Cabsuspension:writeUpdateStream(streamId, connection, dirtyMask)
end;

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

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

function Cabsuspension:update(dt)

	-- Cabsuspension animation
	if self.isClient then
		if self.cab.rotNode ~= nil and self.wheels[3].repr ~= nil and self.wheels[4].repr ~= nil then

			local ax, ay, az = 0;
			local bx, by, bz = 0;
			local cx, cy, cz =  0;
			local dx, dy, dz = 0;

			if self.frontLeftWheelReal == nil then
				ax, ay, az = getTranslation(self.wheels[3].repr);
				bx, by, bz = getTranslation(self.wheels[4].repr);
				cx, cy, cz = getTranslation(self.wheels[1].repr);
				dx, dy, dz = getTranslation(self.wheels[2].repr);
			else
				ax, ay, az = getTranslation(self.backLeftWheelReal);
				bx, by, bz = getTranslation(self.backRightWheelReal);
				cx, cy, cz =  getTranslation(self.frontLeftWheelReal);
				dx, dy, dz = getTranslation(self.frontRightWheelReal);
			end;

			local rotX, rotY, rotZ = getRotation(self.cab.rotNode);

			self.averageYTranslationCab = (ay + by)/2;
			self.averageYTranslationCabFront = (cy + dy)/2;

			self.averageYTranslationCabFront = self.averageYTranslationCabFront + self.frontAndRearWheelYTranslationDifference;

			local transDiff = self.averageYTranslationCab - self.oldTrans;
			local shouldMove = false;

			--[[
			if  transDiff > 0 and transDiff < self.maxMovement then
				shouldMove = true;
			elseif transDiff < 0 and transDiff > -self.maxMovement then
				shouldMove = true;
			else
				shouldMove = false;
			end;
			]]--
			shouldMove = true;

			if shouldMove then
				if self.cabTranslation > self.averageYTranslationCab then
					self.cabTranslation = self.cabTranslation - self.maxTranslationPrCycle * dt;
					--self.cabXRot = -(math.atan2(self.averageYTranslationCab, self.averageYTranslationCabFront) - math.rad(45)) - self.maxTranslationPrCycle * dt;
					--self.cabZrot = -(math.atan2(ay, by) - math.rad(45)) - self.maxTranslationPrCycle * dt;
					if self.cabTranslation < self.averageYTranslationCab then
						self.cabTranslation = self.averageYTranslationCab;
						--self.cabXRot = -(math.atan2(self.averageYTranslationCab, self.averageYTranslationCabFront) - math.rad(45));
						--self.cabZrot = -(math.atan2(ay, by) - math.rad(45));
					end;
				elseif self.cabTranslation < self.averageYTranslationCab then
					self.cabTranslation = self.cabTranslation + self.maxTranslationPrCycle * dt;
					--self.cabXRot = -(math.atan2(self.averageYTranslationCab, self.averageYTranslationCabFront) - math.rad(45)) + self.maxTranslationPrCycle * dt;
					--self.cabZrot = -(math.atan2(ay, by) - math.rad(45)) + self.maxTranslationPrCycle * dt;
					if self.cabTranslation > self.averageYTranslationCab then
						self.cabTranslation = self.averageYTranslationCab;
						--self.cabXRot = -(math.atan2(self.averageYTranslationCab, self.averageYTranslationCabFront) - math.rad(45));
						--self.cabZrot = -(math.atan2(ay, by) - math.rad(45));
					end;
				end;
				
				local maxRotDeg = math.deg(3);
				
				local t = -(math.atan2(self.averageYTranslationCab, self.averageYTranslationCabFront) - math.rad(45));
				t = math.min( math.max( -maxRotDeg, t ), maxRotDeg );
				if self.cabXRot > t + self.maxTranslationPrCycle * dt then
					self.cabXRot = self.cabXRot - self.maxTranslationPrCycle * dt;
					if self.cabXRot < t then
						self.cabXRot = t;
					end;
				elseif self.cabXRot < t + self.maxTranslationPrCycle * dt then
					self.cabXRot = self.cabXRot + self.maxTranslationPrCycle * dt;
					if self.cabXRot > t then
						self.cabXRot = t;
					end;
				end;

				maxRotDeg = math.deg(4);
				
				local t = -(math.atan2(ay, by) - math.rad(45));
				t = math.min( math.max( -maxRotDeg, t ), maxRotDeg );
				if self.cabZrot > t + self.maxTranslationPrCycle * dt then
					self.cabZrot = self.cabZrot - self.maxTranslationPrCycle * dt;
					if self.cabZrot < t then
						self.cabZrot = t;
					end;
				elseif self.cabZrot < t + self.maxTranslationPrCycle * dt then
					self.cabZrot = self.cabZrot + self.maxTranslationPrCycle * dt;
					if self.cabZrot > t then
						self.cabZrot = t;
					end;
				end;
				
				if self.cab.springStiffness ~= nil and self.cab.springStiffness ~= 0 then
					self.cabXRot = self.cabXRot / self.cab.springStiffness;
					self.cabZrot = self.cabZrot / self.cab.springStiffness;
				end;

				if self.cab.rotNode ~= nil then
					setTranslation(self.cab.rotNode, self.startCabXTranslation, self.cabTranslation + self.wheelYTranslationDifference, self.startCabZTranslation);
					setRotation(self.cab.rotNode, self.cabXRot, rotY, self.cabZrot);
				end;
			end;

			self.oldTrans = self.averageYTranslationCab;
		end;
	end;

	-- Seat animation
	if self.wheels[3].repr ~= nil and self.wheels[4].repr ~= nil then
		local x,y,z = 0;
		local x2,y2,z2 = 0;

		if self.frontLeftWheelReal == nil then
			x,y,z = getTranslation(self.wheels[3].repr);
			x2,y2,z2 = getTranslation(self.wheels[4].repr);
		else
			x,y,z = getTranslation(self.backLeftWheelReal);
			x2,y2,z2 = getTranslation(self.backRightWheelReal);
		end;
		self.averageYTranslation = (y + y2)/2;
	end;

	if self.seatTranslation > self.averageYTranslation + 2*self.maxSeatTranslationPrCycle * dt then
		self.seatTranslation = self.seatTranslation - self.maxSeatTranslationPrCycle * dt;
		if self.seatTranslation < self.averageYTranslation then
			self.seatTranslation = self.averageYTranslation;
		end;
	elseif self.seatTranslation < self.averageYTranslation - 2*self.maxSeatTranslationPrCycle * dt then
		self.seatTranslation = self.seatTranslation + self.maxSeatTranslationPrCycle * dt;
		if self.seatTranslation > self.averageYTranslation then
			self.seatTranslation = self.averageYTranslation;
		end;
	end;

	local transDiff = 0;
	local defaultHeight = 0.255;
	local newHeight = 0;

	transDiff = self.seatTranslation - self.defaultPosition;
	newHeight = defaultHeight + transDiff;
	local newScale = newHeight / defaultHeight;

	if self.seatNode ~= nil and self.seatSuspensionNode ~= nil then
		setTranslation(self.seatNode, self.startSeatXTranslation, self.seatTranslation, self.startSeatZTranslation);
		setScale(self.seatSuspensionNode, 1, newScale, 1);
	end;
end;

function Cabsuspension:updateTick(dt)

end;

function Cabsuspension:draw()
end;

function Cabsuspension:onLeave()

end;

function Cabsuspension:onEnter()

end;
