--
--
-- DynamicAttach
--
-- # Author:  Heady
-- # date: 29.10.2016
-- # last update: 30.10.2016
--
-- > Not for commercial use  < --
-- > Not allowed for edit - Copyright (C) Heady - www.planet-ls.de < --
--


DynamicAttach = {};

local modDir = g_currentModDirectory;

function DynamicAttach:prerequisitesPresent(specializations)
    return true;
end;

function DynamicAttach:preLoad(savegame)
	self.findDynamicObjectCallback = DynamicAttach.findDynamicObjectCallback;
end;

function DynamicAttach:load(savegame)

	self.dynamicAttach = {};
	
	self.dynamicAttach.attach = false;
	self.dynamicAttach.doAttach = false;
	self.dynamicAttach.doDetach = false;
	
	self.dynamicAttach.objectsInRange = {};
	self.dynamicAttach.objectsToJoint = {};
	
	self.dynamicAttach.raycastNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.dynamicAttach#raycastNodeIndex"));
	self.dynamicAttach.boxSizeX = getXMLFloat(self.xmlFile, "vehicle.dynamicAttach#boxSizeX");
	self.dynamicAttach.boxSizeY = getXMLFloat(self.xmlFile, "vehicle.dynamicAttach#boxSizeY");
	self.dynamicAttach.boxSizeZ = getXMLFloat(self.xmlFile, "vehicle.dynamicAttach#boxSizeZ");

end;

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

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

function DynamicAttach:readStream(streamId, connection)
    if connection:getIsServer() then
		self.dynamicAttach.attach = streamReadBool(streamId);
    end
end;

function DynamicAttach:writeStream(streamId, connection)
    if not connection:getIsServer() then
		streamWriteBool(streamId, self.dynamicAttach.attach);
    end;
end;

function DynamicAttach:update(dt)


	if self:getIsActiveForInput() then

	
		if InputBinding.hasEvent(InputBinding.DYNAMICATTACH_ATTACHWD) then
			self.dynamicAttach.attach = not self.dynamicAttach.attach;
			if self.dynamicAttach.attach then
				self.dynamicAttach.doAttach = true;
			else
				self.dynamicAttach.doDetach = true;
			end;
			DynamicAttachMPEvent:updateSendEvent(self);
		end;
		
	end;
		

end;

function DynamicAttach:updateTick(dt)

	if self.isServer then

		self.dynamicAttach.objectsInRange = {};
		local x,y,z = getWorldTranslation(self.dynamicAttach.raycastNode);
		local rx,ry,rz = getWorldRotation(self.dynamicAttach.raycastNode);
		--raycastAll(x, y, z, 0, 1, 0, "findDynamicObjectCallback", 10, self);
		local sizeX, sizeY, sizeZ = self.dynamicAttach.boxSizeX, self.dynamicAttach.boxSizeY, self.dynamicAttach.boxSizeZ;
		local numShapes = overlapBox(x, y, z, rx, ry, rz, sizeX, sizeY, sizeZ, "findDynamicObjectCallback", self, nil, true, false, true);
		
		--[[print("------")
		for k, v in pairs(self.dynamicAttach.objectsInRange) do
			print("k: "..tostring(k).." v: "..tostring(v))	
		end;
		print("------")]]

		if self.dynamicAttach.attach then

			if self.dynamicAttach.doAttach then
				if self.isServer then
					-- create Joints
					for key, value in pairs(self.dynamicAttach.objectsInRange) do
						if self.dynamicAttach.objectsToJoint[key] == nil then
							local constr = JointConstructor:new();
							constr:setActors(self.components[1].node, value.physics);
							-- create joint at center of mass to avoid jittering (e.g. tree trunks pivots are not at center of mass position)
							local x,y,z = localToWorld(value.physics, getCenterOfMass(value.physics));
							constr:setJointWorldPositions(x,y,z, x,y,z);
							constr:setRotationLimit(0, 0, 0);
							constr:setRotationLimit(1, 0, 0);
							constr:setRotationLimit(2, 0, 0);
							value.dynamicAttacherJoint = constr:finalize();
							self.dynamicAttach.objectsToJoint[key] = value;
						end;
					end;
					--[[for obj1, _ in pairs(self.dynamicAttach.objectsToJoint) do
						for obj2, _ in pairs(self.dynamicAttach.objectsToJoint) do
							if obj1 ~= obj2 then
								setPairCollision(obj1.nodeId, obj2.nodeId, true);
								setPairCollision(obj1.nodeId, obj2.nodeId, false);
							end
						end
					end]]
				end
				self.dynamicAttach.doAttach = false;
			end;
			
		else
		
			if self.dynamicAttach.doDetach then
				if self.isServer then
					-- remove joints
					for key, value in pairs(self.dynamicAttach.objectsToJoint) do
						if self.dynamicAttach.objectsToJoint[key] ~= nil then
							removeJoint(value.dynamicAttacherJoint);
							-- reset collision
							--[[for obj, _ in pairs(self.dynamicAttach.objectsToJoint) do
								setPairCollision(key.nodeId, obj.nodeId, true);
							end]]
							self.dynamicAttach.objectsToJoint[key] = nil;
						end
					end
				end
				self.dynamicAttach.doDetach = false;
			end;
			
		end;

	end;
		
end;

function DynamicAttach:draw()

	if self.dynamicAttach.attach then
        g_currentMission:addHelpButtonText(string.format(g_i18n:getText("DYNAMICATTACH_DETACH"), self.typeDesc), InputBinding.DYNAMICATTACH_ATTACHWD, nil, GS_PRIO_HIGH);
    else
        g_currentMission:addHelpButtonText(string.format(g_i18n:getText("DYNAMICATTACH_ATTACH"), self.typeDesc), InputBinding.DYNAMICATTACH_ATTACHWD, nil, GS_PRIO_HIGH);
	end;

end;

--function DynamicAttach:findDynamicObjectCallback(transformId, x, y, z, distance) --raycastAll
function DynamicAttach:findDynamicObjectCallback(transformId)

    if transformId ~= 0 and getHasClassId(transformId, ClassIds.SHAPE) then
        local object = g_currentMission:getNodeObject(transformId);
        if object ~= nil then
            if object.getMeshNodes ~= nil and object.dynamicMountObject == nil and self.dynamicAttach.objectsInRange[transformId] == nil then
                local nodes = object:getMeshNodes();
                if nodes ~= nil then
                    self.dynamicAttach.objectsInRange[transformId] = {physics=object.nodeId, visuals=nodes, object=object};
                end
            end
        elseif getSplitType(transformId) ~= 0 then
            local rigidBodyType = getRigidBodyType(transformId);
            if (rigidBodyType == "Dynamic" or rigidBodyType == "Kinematic") and self.dynamicAttach.objectsInRange[transformId] == nil then
                self.dynamicAttach.objectsInRange[transformId] = {physics=transformId, visuals={transformId}};
            end
        end
    end
    return true
end;

DynamicAttachMPEvent = {};
DynamicAttachMPEvent_mt = Class(DynamicAttachMPEvent, Event);

InitEventClass(DynamicAttachMPEvent, "DynamicAttachMPEvent");

function DynamicAttachMPEvent:emptyNew()
    local self = Event:new(DynamicAttachMPEvent_mt);
    self.className="DynamicAttachMPEvent";
    return self;
end;

function DynamicAttachMPEvent:new(object)
    local self = DynamicAttachMPEvent:emptyNew()
    self.object = object;
    return self;
end;

function DynamicAttachMPEvent:readStream(streamId, connection)
    self.object = networkGetObject(streamReadInt32(streamId));	
	
	self.object.dynamicAttach.attach = streamReadBool(streamId);
	
	if self.object.dynamicAttach.attach then
		self.object.dynamicAttach.doAttach = true;
	else
		self.object.dynamicAttach.doDetach = true;
	end;
	
	if not connection:getIsServer() then -- if server read then send to clients
		g_server:broadcastEvent(DynamicAttachMPEvent:new(self.object), nil, connection, self.object);
	end;

end;

function DynamicAttachMPEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));	
	
	streamWriteBool(streamId, self.object.dynamicAttach.attach);	
end;

function DynamicAttachMPEvent:updateSendEvent(runSelf)	

	if g_server ~= nil then
		g_server:broadcastEvent(DynamicAttachMPEvent:new(runSelf));
	else
		g_client:getServerConnection():sendEvent(DynamicAttachMPEvent:new(runSelf));
	end;

end;

