--
-- AutoLoadWood for FS19
-- @author:    	Marhu, kenny456 - FS19 conversion (kenny456@seznam.cz)
-- @history:	v1.0 - 2018-12-25 - converted to FS19
--								  - added function to move loading position FWD/BWD depending on logs length
--
AutoLoadWood = {};

function AutoLoadWood.prerequisitesPresent(specializations)
    return true
end

function AutoLoadWood.initSpecialization()
end

function AutoLoadWood.registerOverwrittenFunctions(vehicleType)
end

function AutoLoadWood.registerFunctions(vehicleType)
end

function AutoLoadWood.registerEvents(vehicleType)
end

function AutoLoadWood:registerActionEventsPlayer()
end

function AutoLoadWood:registerActionEventsMenu()
end
function AutoLoadWood:onRegisterActionEvents(isSelected, isOnActiveVehicle)
	if isOnActiveVehicle then
		if self.AutoLoadWood == nil then 
			self.AutoLoadWood = {}
		else	
			self:clearActionEventsTable( self.AutoLoadWood )
		end 
		for _,actionName in pairs({ "AUTOLOADWOOD_TOGGLE_AUTO",  
                                "AUTOLOADWOOD_TOGGLE_UNLOAD",        
                                "AUTOLOADWOOD_TOGGLE_SIDE",        
                                "AUTOLOADWOOD_TOGGLE_SHOW_POSITION"}) do
			local _, eventName = self:addActionEvent(self.AutoLoadWood, InputAction[actionName], self, AutoLoadWood.actionCallback, true, true, false, true, nil);
			--local __, eventName = InputBinding.registerActionEvent(g_inputBinding, actionName, self, AutoLoadWood.actionCallback ,false ,true ,false ,true)
			if isSelected then
				g_inputBinding.events[eventName].displayPriority = 1
			elseif  isOnActiveVehicle then
				g_inputBinding.events[eventName].displayPriority = 3
			end
		end
	end
end

function AutoLoadWood.registerEventListeners(vehicleType)
    EL = vehicleType.eventListeners
    table.insert(EL.onLoad, AutoLoadWood)
    table.insert(EL.onUpdate, AutoLoadWood)
    table.insert(EL.onDraw, AutoLoadWood)
    table.insert(EL.onRegisterActionEvents, AutoLoadWood)
    --table.insert(EL.toggleState, AutoLoadWood)
    --table.insert(EL.actionCallback, AutoLoadWood)
    --table.insert(EL.dynamicMountTriggerCallback, AutoLoadWood)
end

function AutoLoadWood:onLoad(vehicle)
	local xmlFile = self.xmlFile
	--self.doCheckSpeedLimit = Utils.overwrittenFunction(self.doCheckSpeedLimit, AutoLoadWood.doCheckSpeedLimit)
	self.dynamicMountTriggerCallback =  Utils.overwrittenFunction(self.dynamicMountTriggerCallback, AutoLoadWood.dynamicMountTriggerCallback)
    self.toggleState = AutoLoadWood.toggleState
	
	self.woodLoad = {};
	self.autoload = false;
	self.rightSide = false;
	self.unload = false;
	self.showPosition = false;
	
	self.searchSizeY = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.AutoLoadWood#SizeY"),5);
	self.searchSizeZ = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.AutoLoadWood#SizeX"),10);
	self.autoLoadSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.AutoLoadWood#Speed"),500);
	self.autoLoadElaps = 0;
	
	if self.isServer then
		
		local key = "vehicle.AutoLoadWood.woodTrigger";
		local woodTriggerXOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#xOff"),1.2);
		local woodTriggerYOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#yOff"),-3);
		local woodTriggerZOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#zOff"),1.5);
		
		local key = "vehicle.AutoLoadWood.fillPose";
		local fillPoseXOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#xOff"),0);
		local fillPoseYOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#yOff"),2);
		local fillPoseZOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#zOff"),0);
		
		local key = "vehicle.AutoLoadWood.unloadPose";
		local unloadPoseXOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#xOff"),3);
		local unloadPoseYOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#yOff"),0);
		local unloadPoseZOff = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#zOff"),0);

		local key = "vehicle.AutoLoadWood.limitToLen";
		self.loadMinLen = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#minLen"),2.5);
		self.loadMaxLen = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#maxLen"),20);
		self.loadMaxAtt = Utils.getNoNil(getXMLInt(xmlFile, key .. "#delimbOk"),0);
		
		self.dynamicMountTrigger = I3DUtil.indexToObject(self.components, self.i3dMappings.dynamicMountTrigger);
		self.autoLoadWood = I3DUtil.indexToObject(self.components, self.i3dMappings.autoLoadWood);
		self.autoLoadWoodBegin = I3DUtil.indexToObject(self.components, self.i3dMappings.autoLoadWoodBegin);
		local linkNode = getParent(self.dynamicMountTrigger)
		local x,y,z = getTranslation(self.dynamicMountTrigger)
		
		self.woodTrigger = {createTransformGroup("woodTrigger1"),
							createTransformGroup("woodTrigger2"),
							createTransformGroup("woodTrigger3"),
							createTransformGroup("woodTrigger4")};
		
		local rot = math.rad(90)
		for i = 1, 4 do					
			link(linkNode, self.woodTrigger[i]);
			setTranslation(self.woodTrigger[i], x + woodTriggerXOff, y + woodTriggerYOff, z + woodTriggerZOff)
			setRotation(self.woodTrigger[i], 0, rot, 0);
			woodTriggerZOff = woodTriggerZOff * -1;
			if i == 2 then 
				woodTriggerXOff = woodTriggerXOff * -1;
				rot = math.rad(-90)
			end
		end
			
		self.fillPoseNode = createTransformGroup("fillPoseNode");
		link(self.autoLoadWood,self.fillPoseNode);
		setTranslation(self.fillPoseNode, x + fillPoseXOff, y + fillPoseYOff, z + fillPoseZOff)
		setRotation(self.fillPoseNode,math.rad(-90),0,0)
		
		self.unloadPoseNode = {	createTransformGroup("unloadPoseNode1"),
								createTransformGroup("unloadPoseNode2")};
		
		for i = 1, 2 do					
			link(linkNode, self.unloadPoseNode[i]);
			setTranslation(self.unloadPoseNode[i], x + unloadPoseXOff, y + unloadPoseYOff, z + unloadPoseZOff)
			setRotation(self.unloadPoseNode[i],math.rad(-90),0,0)
			unloadPoseXOff = unloadPoseXOff * -1;
		end
	end;
end


function AutoLoadWood:onUpdate(dt, vehicle)
	if false then
		for i = 1, 4 do
			local x,y,z = getWorldTranslation(self.woodTrigger[i])
			local nx, ny, nz = localDirectionToWorld(self.woodTrigger[i], 1, 0, 0)
			local yx, yy, yz = localDirectionToWorld(self.woodTrigger[i], 0, 1, 0)
			local zx, zy, zz = localDirectionToWorld(self.woodTrigger[i], 0, 0, 1)
			drawDebugLine(x,y,z, 1, 0, 0, x + nx, y + ny, z + nz, 1, 0, 0);
			drawDebugLine(x,y,z, 0, 1, 0, x + yx, y + yy, z + yz, 0, 1, 0);
			drawDebugLine(x,y,z, 0, 0, 1, x + zx, y + zy, z + zz, 0, 0, 1);
		end
		
		local x,y,z = getWorldTranslation(self.fillPoseNode)
		local nx, ny, nz = localDirectionToWorld(self.fillPoseNode, 1, 0, 0)
		local yx, yy, yz = localDirectionToWorld(self.fillPoseNode, 0, 1, 0)
		local zx, zy, zz = localDirectionToWorld(self.fillPoseNode, 0, 0, 1)
		drawDebugLine(x,y,z, 1, 0, 0, x + nx, y + ny, z + nz, 1, 0, 0);
		drawDebugLine(x,y,z, 0, 1, 0, x + yx, y + yy, z + yz, 0, 1, 0);
		drawDebugLine(x,y,z, 0, 0, 1, x + zx, y + zy, z + zz, 0, 0, 1);
		
		for i = 1, 2 do
			local x,y,z = getWorldTranslation(self.unloadPoseNode[i])
			local nx, ny, nz = localDirectionToWorld(self.unloadPoseNode[i], 1, 0, 0)
			local yx, yy, yz = localDirectionToWorld(self.unloadPoseNode[i], 0, 1, 0)
			local zx, zy, zz = localDirectionToWorld(self.unloadPoseNode[i], 0, 0, 1)
			drawDebugLine(x,y,z, 1, 0, 0, x + nx, y + ny, z + nz, 1, 0, 0);
			drawDebugLine(x,y,z, 0, 1, 0, x + yx, y + yy, z + yz, 0, 1, 0);
			drawDebugLine(x,y,z, 0, 0, 1, x + zx, y + zy, z + zz, 0, 0, 1);
		end
		
		if self.lastWoodShapes ~= nil and entityExists(self.lastWoodShapes) then
			local x,y,z = getWorldTranslation(self.lastWoodShapes)
			local nx, ny, nz = localDirectionToWorld(self.lastWoodShapes, 10, 0, 0)
			local yx, yy, yz = localDirectionToWorld(self.lastWoodShapes, 0, 10, 0)
			local zx, zy, zz = localDirectionToWorld(self.lastWoodShapes, 0, 0, 10)
			drawDebugLine(x,y,z, 1, 0, 0, x + nx, y + ny, z + nz, 1, 0, 0);
			drawDebugLine(x,y,z, 0, 1, 0, x + yx, y + yy, z + yz, 0, 1, 0);
			drawDebugLine(x,y,z, 0, 0, 1, x + zx, y + zy, z + zz, 0, 0, 1);
		end
		if self.autoLoadWood ~= nil then
			target = self.autoLoadWood
			local x,y,z = getWorldTranslation(target)
			local nx, ny, nz = localDirectionToWorld(target, 10, 0, 0)
			local yx, yy, yz = localDirectionToWorld(target, 0, 10, 0)
			local zx, zy, zz = localDirectionToWorld(target, 0, 0, 10)
			drawDebugLine(x,y,z, 1, 0, 0, x + nx, y + ny, z + nz, 1, 0, 0);
			drawDebugLine(x,y,z, 0, 1, 0, x + yx, y + yy, z + yz, 0, 1, 0);
			drawDebugLine(x,y,z, 0, 0, 1, x + zx, y + zy, z + zz, 0, 0, 1);
		end
	end
	
	if self.autoload then
		self.autoLoadElaps = self.autoLoadElaps + dt;
		if self.autoLoadElaps >= self.autoLoadSpeed then
			self.autoLoadElaps = 0;
			
			if self.isServer then
				if entityExists(self.lastWoodShapes) and self.woodLoad[self.lastWoodShapes] == nil then
					self:toggleState(false, self.rightSide, self.unload, self.showPosition)
					return;
				end;
				
				local triggerNum = (self.rightSide and 2 or 0) + 1;
				
				local x,y,z = getWorldTranslation(self.woodTrigger[triggerNum])
				local nx, ny, nz = localDirectionToWorld(self.woodTrigger[triggerNum], 1, 0, 0)
				local yx, yy, yz = localDirectionToWorld(self.woodTrigger[triggerNum], 0, 1, 0)
				local shape, minY, maxY, minZ, maxZ = findSplitShape(x, y, z, nx, ny, nz, yx, yy, yz, self.searchSizeY, self.searchSizeZ)
				
				if shape == nil or not entityExists(shape) or getRigidBodyType(shape) ~= "Dynamic" then
					triggerNum = triggerNum + 1;
					x,y,z = getWorldTranslation(self.woodTrigger[triggerNum])
					nx, ny, nz = localDirectionToWorld(self.woodTrigger[triggerNum], 1, 0, 0)
					yx, yy, yz = localDirectionToWorld(self.woodTrigger[triggerNum], 0, 1, 0)
					shape, minY, maxY, minZ, maxZ = findSplitShape(x, y, z, nx, ny, nz, yx, yy, yz, self.searchSizeY, self.searchSizeZ)
				end	
				
				if shape ~= nil and entityExists(shape) and getRigidBodyType(shape) == "Dynamic" then
					local sizeX, sizeY, sizeZ, numConvexes, numAttachments = getSplitShapeStats(shape)
					local maxSize = math.max(sizeX, math.max(sizeY, sizeZ)) --fcelsa
					local a, b, c = localToWorld(self.woodTrigger[triggerNum], 0, (minY + maxY)*0.5, (minZ + maxZ)*0.5)
					local sx,sy,sz = getWorldTranslation(shape)
					local dist = MathUtil.vector3Length(a - sx, b - sy, c - sz)
					local nx, ny, nz = localDirectionToWorld(shape, 0, 1, 0)
					local lenBelow, lenAbove = getSplitShapePlaneExtents(shape, a, b, c, nx, ny, nz);
					dist = dist - lenBelow
					local wx,wy,wz = localToWorld(self.fillPoseNode,0,-dist - (sizeX/2),0)
					local dx,dy,dz = worldToLocal(getParent(shape),wx,wy,wz)
					local nx, ny, nz = localDirectionToWorld(self.fillPoseNode, 1, 0, 0)
					local yx, yy, yz = localDirectionToWorld(self.fillPoseNode, 0, 1, 0)
					local x, y, z = worldDirectionToLocal(getParent(shape), nx, ny, nz)
					local xdir, ydir, zdir = worldDirectionToLocal(getParent(shape), yx, yy, yz)
					if numAttachments == nil then numAttachments = 0; end;
					if maxSize <= self.loadMaxLen and maxSize >= self.loadMinLen and numAttachments <= self.loadMaxAtt then
						removeFromPhysics(shape)
						setTranslation(shape,dx,dy,dz)
						setDirection(shape, x, y, z, xdir, ydir, zdir)
						addToPhysics(shape)
						self.lastWoodShapes = shape
					end;
				end
			end
		end
	elseif self.unload then
		self.autoLoadElaps = self.autoLoadElaps + dt;
		if self.autoLoadElaps >= self.autoLoadSpeed then
			self.autoLoadElaps = 0;
			
			if self.isServer then
				local x,y,z = getWorldTranslation(self.fillPoseNode)
				local findWood = false;
				for k, shape in pairs(self.woodLoad) do
					if entityExists(shape) then
						local side = self.rightSide and 2 or 1;
						local sx,sy,sz = getWorldTranslation(shape)
						local dist = MathUtil.vector2Length(x - sx, z - sz)
						if dist < 100 then
							local wx,wy,wz = localToWorld(self.unloadPoseNode[side],0,-dist,0)
							local dx,dy,dz = worldToLocal(getParent(shape),wx,wy,wz)
							local nx, ny, nz = localDirectionToWorld(self.unloadPoseNode[side], 1, 0, 0)
							local yx, yy, yz = localDirectionToWorld(self.unloadPoseNode[side], 0, 1, 0)
							local x, y, z = worldDirectionToLocal(getParent(shape), nx, ny, nz)
							local xdir, ydir, zdir = worldDirectionToLocal(getParent(shape), yx, yy, yz)
							removeFromPhysics(shape)
							setTranslation(shape,dx,dy,dz)
							setDirection(shape, x, y, z, xdir, ydir, zdir)
							addToPhysics(shape)
							self:dynamicMountTriggerCallback(self.dynamicMountTrigger, shape, false, true, false, shape)
							findWood = true;
							break;
						else
							self.woodLoad[k] = nil
						end
					else
						self.woodLoad[k] = nil
					end
				end
				if findWood == false then self:toggleState(self.autoload, self.rightSide, false, self.showPosition) end;
			end;
		end;
	end
end

function AutoLoadWood:onDraw()
	if self:getIsActive() and self.showPosition == true then
		local x,y,z = getWorldTranslation(self.fillPoseNode)
		local a,b,c = getWorldTranslation(self.autoLoadWoodBegin)
		local dist = MathUtil.vector2Length(x - a, z - c)
		self.fillInfoText = '|<-- '..string.format("%.1f",dist)..' m\n |'
		Utils.renderTextAtWorldPosition(x, y, z, self.fillInfoText, getCorrectTextSize(0.016), 0);
	end
	if self.autoload then
		g_inputBinding:setActionEventText(self.AutoLoadWood.AUTOLOADWOOD_TOGGLE_AUTO.actionEventId, 'Остановить автозагрузку')
	else
		g_inputBinding:setActionEventText(self.AutoLoadWood.AUTOLOADWOOD_TOGGLE_AUTO.actionEventId, 'Начать автозагрузку')
	end
	if self.unload then
		g_inputBinding:setActionEventText(self.AutoLoadWood.AUTOLOADWOOD_TOGGLE_UNLOAD.actionEventId, 'Остановить выгрузку')
	else
		g_inputBinding:setActionEventText(self.AutoLoadWood.AUTOLOADWOOD_TOGGLE_UNLOAD.actionEventId, 'Авторазгрузка брёвен')
	end
	if self.rightSide then
		g_inputBinding:setActionEventText(self.AutoLoadWood.AUTOLOADWOOD_TOGGLE_SIDE.actionEventId, 'Правая сторона')
	else
		g_inputBinding:setActionEventText(self.AutoLoadWood.AUTOLOADWOOD_TOGGLE_SIDE.actionEventId, 'Левая сторона')
	end
	if self.showPosition then
		g_inputBinding:setActionEventText(self.AutoLoadWood.AUTOLOADWOOD_TOGGLE_SHOW_POSITION.actionEventId, 'Скрыть позицию загрузки')
	else
		g_inputBinding:setActionEventText(self.AutoLoadWood.AUTOLOADWOOD_TOGGLE_SHOW_POSITION.actionEventId, 'Показать позицию загрузки')
	end
end
function AutoLoadWood:toggleState(autoload, rightSide, unload, showPosition, noEventSend)

	AutoLoadWoodToggleEvent.sendEvent(self, autoload, rightSide, unload, showPosition, noEventSend)
	
	self.lastWoodShapes = 0;
	self.autoload = autoload;
	self.rightSide = rightSide;
	self.unload = unload;
	self.showPosition = showPosition;
end;
function AutoLoadWood:actionCallback(actionName, keyStatus, arg4, arg5, arg6)
	if keyStatus > 0 then
		if actionName == 'AUTOLOADWOOD_TOGGLE_AUTO' then
			self:toggleState(not self.autoload, self.rightSide, false, self.showPosition)
		elseif actionName == 'AUTOLOADWOOD_TOGGLE_UNLOAD' then
			self:toggleState(false, self.rightSide, not self.unload, self.showPosition)
		elseif actionName == 'AUTOLOADWOOD_TOGGLE_SIDE' then
			self:toggleState(false, not self.rightSide, false, self.showPosition)
		elseif actionName == 'AUTOLOADWOOD_TOGGLE_SHOW_POSITION' then
			self:toggleState(self.autoload, self.rightSide, self.unload, not self.showPosition)
		end
	end
end
function AutoLoadWood:dynamicMountTriggerCallback(superFunc,triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId)
	local splitType = g_splitTypeManager:getSplitTypeByIndex(getSplitType(otherActorId))
	if splitType ~= nil then
		if onEnter then
			self.woodLoad[otherActorId] = otherActorId
		elseif onLeave then
			self.woodLoad[otherActorId] = nil;
		end
	end
	superFunc(self, triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId)
end

--- Event ---

AutoLoadWoodToggleEvent = {};
AutoLoadWoodToggleEvent_mt = Class(AutoLoadWoodToggleEvent, Event);

InitEventClass(AutoLoadWoodToggleEvent, "AutoLoadWoodToggleEvent");

function AutoLoadWoodToggleEvent:emptyNew()
    local self = Event:new(AutoLoadWoodToggleEvent_mt);
    return self;
end;
    
function AutoLoadWoodToggleEvent:new(object, autoload, rightSide, unload, showPosition)
	local self = AutoLoadWoodToggleEvent:emptyNew()
	self.object = object;
	self.autoload = autoload;
	self.rightSide = rightSide;
	self.unload = unload;
	self.showPosition = showPosition;
	return self;
end;

function AutoLoadWoodToggleEvent:readStream(streamId, connection)
	local id = streamReadInt32(streamId);
	self.autoload = streamReadBool(streamId);
	self.rightSide = streamReadBool(streamId);
	self.unload = streamReadBool(streamId);
	self.showPosition = streamReadBool(streamId);
	self.object = networkGetObject(id);
	self:run(connection);
end;

function AutoLoadWoodToggleEvent:writeStream(streamId, connection)
	streamWriteInt32(streamId, networkGetObjectId(self.object));
	streamWriteBool(streamId, self.autoload);
	streamWriteBool(streamId, self.rightSide);
	streamWriteBool(streamId, self.unload);
	streamWriteBool(streamId, self.showPosition);
end;

function AutoLoadWoodToggleEvent:run(connection)
	if not connection:getIsServer() then
		g_server:broadcastEvent(self, false, connection, self.object);
	end;
	if self.object ~= nil then
		self.object:toggleState(self.autoload, self.rightSide, self.unload, self.showPosition, true);
	end;
end;

function AutoLoadWoodToggleEvent.sendEvent(vehicle, autoload, rightSide, unload, showPosition, noEventSend)
	if autoload ~= vehicle.autoload or rightSide ~= vehicle.rightSide or unload ~= vehicle.unload or showPosition ~= vehicle.showPosition then
		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then
				g_server:broadcastEvent(AutoLoadWoodToggleEvent:new(vehicle, autoload, rightSide, unload, showPosition), nil, nil, vehicle);
			else
				g_client:getServerConnection():sendEvent(AutoLoadWoodToggleEvent:new(vehicle, autoload, rightSide, unload, showPosition));
			end;
		end;
	end;
end;