--
-- CustomTrackSystem
--
-- @author:    	Xentro (Marcus@Xentro.se)
-- @website:	www.Xentro.se
-- @history:	v1.0 - 2015-03-01 - Initial implementation
--				v1.1 - 2015-09-15 - Update
--				v1.2 - 2015-10-02 - Remove tracks on "ground prepared surface" 
-- 				v1.3 - 2015-11-04 - Can be used along with HP 
-- 				v1.31 - 2016-03-27 - MP updates for HP side
-- 				v1.32 - 2016-05-03 - Update for HP
-- 

CustomTrackSystem = {};

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

function CustomTrackSystem:load(xmlFile)
	local file = getXMLString(xmlFile, "vehicle.CustomTrackSystem#file");
	if file ~= nil and file ~= "" and g_currentMission.tyreTrackSystem ~= nil then
		file = Utils.getFilename(file, self.baseDirectory);
		
		if fileExists(file) then
			local system = TyreTrackSystem:new();
			system:load(file);
			self.customTrackSystem = system;
			
			if g_currentMission.customTrackSystem == nil then
				g_currentMission.customTrackSystem = {};
			end;
			
			table.insert(g_currentMission.customTrackSystem, self.customTrackSystem);
		else
			print("CustomTrackSystem - Error: We can't load " .. tostring(file));
		end;
	end;
	
	if self.weAreHardPointObject then
		self.ourWheelParent = self.vehicle;
	else
		self.ourWheelParent = self;
	end;
	
	if self.customTrackSystem ~= nil then
		self.hasWheelContactUpdate = {};
		self.trackSystemData = {};
		
		local i = 0;
		while true do
			local key = string.format("vehicle.wheels.wheel(%d)", i);
			if not hasXMLProperty(xmlFile, key) then break; end;
			
			local customTrackAtlasIndex = getXMLInt(xmlFile, key .. "#customTrackAtlasIndex");
			if customTrackAtlasIndex ~= nil then
				self.ourWheelParent.wheels[i + 1].customTrackAtlasIndex = customTrackAtlasIndex;
				self.ourWheelParent.wheels[i + 1].width = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#width"), self.ourWheelParent.wheels[i + 1].width);
				self.ourWheelParent.wheels[i + 1].xoffset = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#xoffset"), self.ourWheelParent.wheels[i + 1].xoffset);
				
				local entry = {};
				entry.id = i + 1;
				entry.trackIndex = self.customTrackSystem:createTrack(self.ourWheelParent.wheels[i + 1].width, customTrackAtlasIndex);
				
				table.insert(self.trackSystemData, entry);
				self.hasWheelContactUpdate[i + 1] = self.ourWheelParent.wheels[i + 1].tyreTrackIndex == nil;
				
				if not self.hasWheelContactUpdate[i + 1] then
					print("CustomTrackSystem - Warning: You can't use the default track system along with CustomTrackSystem on wheel " .. i + 1 .. ", CustomTrackSystem have been deactivated for this wheel.");
				end;
			end;
			
			i = i + 1;
		end;
	end;
	
	self.lastTrackPosition = {0, 0, 0};
	self.synchTracksMP = #self.trackSystemData > 0;
	self.customTrackDirtyFlag = self:getNextDirtyFlag();
end;

function CustomTrackSystem:delete()
	if self.customTrackSystem ~= nil then
		for _, v in ipairs(self.trackSystemData) do
			self.customTrackSystem:destroyTrack(v.trackIndex);
		end;
		
		for i = 1, #g_currentMission.customTrackSystem do
			if g_currentMission.customTrackSystem[i] == self.customTrackSystem then
				table.remove(g_currentMission.customTrackSystem, i);
				break;
			end;
		end;
		
		if #g_currentMission.customTrackSystem == 0 then
			g_currentMission.customTrackSystem = nil;
		end;
		
		self.customTrackSystem:delete();
	end;
end;

function CustomTrackSystem:readStream(streamId, connection)
	if self.customTrackSystem ~= nil and connection:getIsServer() then
		for _, v in ipairs(self.trackSystemData) do
			if self.hasWheelContactUpdate[v.id] then
				self.ourWheelParent.wheels[v.id].contact = streamReadInt8(streamId);
			end;
		end;
	end;
end;

function CustomTrackSystem:writeStream(streamId, connection)
	if self.customTrackSystem ~= nil and not connection:getIsServer() then
		for _, v in ipairs(self.trackSystemData) do
			if self.hasWheelContactUpdate[v.id] then
				streamWriteInt8(streamId, self.ourWheelParent.wheels[v.id].contact);
			end;
		end;
	end;
end;

function CustomTrackSystem:readUpdateStream(streamId, timestamp, connection)
	CustomTrackSystem.readStream(self, streamId, connection);
end;

function CustomTrackSystem:writeUpdateStream(streamId, connection, dirtyMask)
	CustomTrackSystem.writeStream(self, streamId, connection);
end;

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

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

function CustomTrackSystem:update(dt)
	if self.customTrackSystem ~= nil then
		if self:getIsActive() and self.firstTimeRun then
			if self.isServer then
				-- mp updates are activated once vehicle starts moving normally but not for HP objects
				if self.weAreHardPointObject and self.synchTracksMP then
					local position = {getWorldTranslation(self.components[1].node)};
					local distance = Utils.vector3Length(self.lastTrackPosition[1] - position[1], self.lastTrackPosition[2] - position[2], self.lastTrackPosition[3] - position[3]);
					
					if distance > 0.01 then
						self.lastTrackPosition = position;
						self:raiseDirtyFlags(self.customTrackDirtyFlag);
					else
						self:clearDirtyFlags(self.customTrackDirtyFlag);
					end;
				end;
			end;
			
			for p, v in ipairs(self.trackSystemData) do
				if self.hasWheelContactUpdate[v.id] then
					local wheel = self.ourWheelParent.wheels[v.id];
					local wheelSpeed = 0;
					local color;
					
					if self.isServer then
						wheelSpeed = getWheelShapeAxleSpeed(wheel.node, wheel.wheelShape);
					else
						wheelSpeed = 1;
					end;
					
					if wheel.contact == Vehicle.WHEEL_GROUND_CONTACT then
						color = wheel.lastColor;
					elseif wheel.contact == Vehicle.WHEEL_OBJ_CONTACT then
						if wheel.dirtAmount > 0 then
							color = wheel.lastColor;
							color[4] = 0; -- no depth to tyre tracks on road etc.
						end;
					end;
					
					if color ~= nil then
						local ux, uy, uz = localDirectionToWorld(self.ourWheelParent.rootNode, 0, 1, 0);
						local wx, wy, wz = worldToLocal(wheel.node, getWorldTranslation(wheel.driveNode));
						wy = wy - wheel.radius;
						wx = wx + wheel.xoffset;
						wx, wy, wz = localToWorld(wheel.node, wx, wy, wz);
						
						self.customTrackSystem:addTrackPoint(v.trackIndex, wx, wy, wz, ux, uy, uz, color[1], color[2], color[3], wheel.dirtAmount, color[4], wheelSpeed);
					else
						self.customTrackSystem:cutTrack(v.trackIndex);
					end;
				end;
			end;
		end;
	end;
end;

function CustomTrackSystem:updateTick(dt)
end;

function CustomTrackSystem:draw()
end;


-- remove tracks from surface if cultivated etc
if not Utils.CustomTrackSystemTrackFix20151002 then
	Utils.CustomTrackSystemTrackFix20151002 = true;
	
	local udc = Utils.updateDestroyCommonArea;
	Utils.updateDestroyCommonArea = function(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, limitToField)
		if g_currentMission.customTrackSystem ~= nil then
			for i, v in ipairs(g_currentMission.customTrackSystem) do
				v:eraseParallelogram(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ);
			end;
		end;
		
		udc(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, limitToField);
	end;
	
	local usa = Utils.updateSowingArea;
	Utils.updateSowingArea = function(fruitId, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, angle, useDirectPlanting)
		local ids = g_currentMission.fruits[fruitId]

		if ids == nil or ids.id == 0 then
			return 0;
		end;
	
		if g_currentMission.customTrackSystem ~= nil then
			for i, v in ipairs(g_currentMission.customTrackSystem) do
				v:eraseParallelogram(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ);
			end;
		end;
		
		return usa(fruitId, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, angle, useDirectPlanting);
	end;
end;