--
-- objectAttacherJBT
-- Specialization for attaching objects on a trailer
--
-- @author Geri-G
--
-- edited by PeterJ FS-UK modteam
-- 16/11/2012
-- 07/02/2013 - made FillablePallet compatible
--
--

objectAttacherJBT = {};

function objectAttacherJBT.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Attachable, specializations);
end;

function objectAttacherJBT:load(xmlFile)

	self.setIsBaleAttached = SpecializationUtil.callSpecializationsFunction("setIsBaleAttached");
	self.searchObjects = objectAttacherJBT.searchObjects;
	self.attachobjects = objectAttacherJBT.attachobjects;
	self.detachobjects = objectAttacherJBT.detachobjects;
	self.OrientJoint = objectAttacherJBT.OrientJoint;
	self.isObjectInRange = objectAttacherJBT.isObjectInRange;
	self.place = {};
	local i=0;
	while true do
		local basename = string.format("vehicle.baleCastPoints.baleCastPoint(%d)",i);
		local place = {};
		place.node1 = Utils.indexToObject(self.components, getXMLString(xmlFile,basename.."#frontRight"));

		if place.node1 == nil then
			break;
		end;
		place.node2 = Utils.indexToObject(self.components, getXMLString(xmlFile,basename.."#backLeft"));
		place.attacherNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(xmlFile,basename.."#attacherNode"),"0>"));
		place.highOffset = Utils.getNoNil(getXMLFloat(xmlFile,basename.."#highOffset"),4);
		table.insert(self.place,place);
		i=i+1;
	end;
	self.allowVehicleAttachment = getXMLBool(xmlFile,"vehicle.baleCastPoints#allowVehicleAttachment");
	self.Attachedobjects = {};
	self.objectsAttached = false;
	self.isBaleAttach = false;	
end;

function objectAttacherJBT:delete()
end;

function objectAttacherJBT:readStream(streamId, connection)
	local baleAttach = streamReadBool(streamId);
	self:setIsBaleAttached(baleAttach, true);			
end;

function objectAttacherJBT:writeStream(streamId, connection)
    streamWriteBool(streamId, self.isBaleAttach);
end;

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

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

function objectAttacherJBT:update(dt)
	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
			self:setIsBaleAttached(not self.isBaleAttach);
		end;
	end;
end;

function objectAttacherJBT:updateTick(dt)
end;

function objectAttacherJBT:draw()
	if self:getIsActive() then
		if not self.isBaleAttach then
			g_currentMission:addHelpButtonText(g_i18n:getText("Unlock"), InputBinding.IMPLEMENT_EXTRA3);
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("Lock"), InputBinding.IMPLEMENT_EXTRA3);
		end;
	end;
end;

function objectAttacherJBT:isObjectInRange(place,object)
	local Xmax, Ymax, Zmax = getWorldTranslation(place.node1);
		  Xmax, Ymax, Zmax = worldToLocal(place.attacherNode,Xmax, Ymax, Zmax);
		  
	local Xmin, Ymin, Zmin = getWorldTranslation(place.node2);	
		  Xmin, Ymin, Zmin = worldToLocal(place.attacherNode,Xmin, Ymin, Zmin);
	
	local Xt, Yt, Zt = getWorldTranslation(object);
		  Xt, Yt, Zt = worldToLocal(place.attacherNode,Xt, Yt, Zt);
		
	if (Xt < math.max(Xmax,Xmin) and Xt > math.min(Xmax,Xmin)) and (Zt < math.max(Zmax,Zmin) and Zt > math.min(Zmax,Zmin)) and (Yt<= ((Ymax+Ymin)/2)+place.highOffset and Yt>= (Ymax+Ymin)/2) then
		return true;
	else
		return false;
	end;
end;

function objectAttacherJBT:searchObjects()
	for index,item in pairs(g_currentMission.itemsToSave) do
		if item.item:isa(Bale) or item.item:isa(FillablePallet) then 
			if item.item.isAttached == nil then--and (getUserAttribute(item.item.nodeId, "isHaybale") == true or getUserAttribute(item.item.nodeId, "isStrawbale") == true or getUserAttribute(item.item.nodeId, "isRoundbale") == true) then
				for k,v in pairs(self.place) do
					local isInRange = self:isObjectInRange(v,item.item.nodeId);			
					local is1stAttached = false;
					if isInRange then
						is1stAttached = self:attachobjects(v,item.item.nodeId,item.item);
					end;
					if is1stAttached then
						self.objectsAttached = true;
					end;
				end;
			end;
		end;
	end;
	if self.allowVehicleAttachment == true then
		for k,v in pairs(g_currentMission.vehicles) do
			if v ~= self and v ~= self.attacherVehicle then
				local is1stAttached = false;
				for index,components in pairs(v.components) do		
					for k1,v1 in pairs(self.place) do
						local isInRange = self:isObjectInRange(v1,components.node);	
						if isInRange then	
							is1stAttached = self:attachobjects(v1,components.node);
						end;
					end;
				end;
				if is1stAttached then
					self.objectsAttached = true;
				end;
			end;
		end;
	end;
end;

function objectAttacherJBT:setIsBaleAttached(baleAttach, noEventSend)
	SetBaleAttachEvent.sendEvent(self, baleAttach, noEventSend) 
	self.isBaleAttach = baleAttach;
	
	if baleAttach then
		self:detachobjects();	
	else
		self:searchObjects();
	end;
end;

function objectAttacherJBT:OrientJoint(Source, Target)	
	local xw, yw, zw = getWorldTranslation(Source);		
	local x,y,z = worldToLocal(getParent(Target), xw, yw, zw);	
	setTranslation(Target, x,y,z);			
	
	local zX, zY, zZ = localDirectionToWorld(Source, 0,0,1);
	local zX, zY, zZ = worldDirectionToLocal(getParent(Target), zX, zY, zZ);
	local yX, yY, yZ = localDirectionToWorld(Source, 0,1,0);
	local yX, yY, yZ = worldDirectionToLocal(getParent(Target), yX, yY, yZ);
	setDirection(Target, zX, zY, zZ, yX, yY, yZ);
	return false;
end;

function objectAttacherJBT:attachobjects(place,object,baleT)
	local attachedobject = {};
	attachedobject.object = object;
	if self.isServer then
		attachedobject.AT = createTransformGroup("AT");
		link(place.attacherNode,attachedobject.AT);
		
		self:OrientJoint(object,attachedobject.AT);

		local constr = JointConstructor:new();					
		constr:setActors(place.attacherNode, object);
		constr:setJointTransforms(attachedobject.AT,  object);
		for i=1, 3 do
			constr:setTranslationLimit(i-1, true, 0, 0);
			constr:setRotationLimit(i-1,0,0);
		end;
		attachedobject.JointIndex = constr:finalize();
		
		if baleT ~= nil then
			attachedobject.baleT = baleT;
			baleT.isAttached = true;
		end;
	end;

	table.insert(self.Attachedobjects, attachedobject);
	return true;
end;

function objectAttacherJBT:detachobjects()
	if self.isServer then
		for k,v in pairs(self.Attachedobjects) do
			removeJoint(v.JointIndex);
			delete(v.AT);
			v.JointIndex = nil;
			if v.baleT ~= nil then
				v.baleT.isAttached = nil;
			end;
		end;
	end;
	
	self.Attachedobjects = nil;
	self.Attachedobjects = {};
	self.objectsAttached = false;
end;

function objectAttacherJBT:onAttach(attacherVehicle)
	if self.isServer then
		self:setIsBaleAttached(false);
	end;
end;

function objectAttacherJBT:onDetach()
	if self.isServer then
		self:setIsBaleAttached(true);
	end;
end;

function objectAttacherJBT:onLeave()
	if self.isServer then
		self:setIsBaleAttached(true);
	end;
end;
