--
-- baleLockByMovement2
-- Specialization for attaching bales on a trailer
--
-- @author Geri-G
--
-- edited by PeterJ - euroDZN 
-- 16/11/2012
-- 05/06/2013 - made controllable by movement 
--

baleLockByMovement2 = {};

function baleLockByMovement2.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Attachable, specializations) and SpecializationUtil.hasSpecialization(baleLockByMovement, specializations);
end;

function baleLockByMovement2:load(xmlFile)

	self.setIsBaleAttached2 = SpecializationUtil.callSpecializationsFunction("setIsBaleAttached2");
	self.searchBales2 = baleLockByMovement2.searchBales2;
	self.attachbales2 = baleLockByMovement2.attachbales2;
	self.detachbales2 = baleLockByMovement2.detachbales2;
	self.OrientJoint2 = baleLockByMovement2.OrientJoint2;
	self.isBaleInRange2 = baleLockByMovement2.isBaleInRange2;
	
	self.place2 = {};
	local i=0;
	while true do
		local basename = string.format("vehicle.baleCastPoints.baleCastPoint2(%d)",i);
		local place2 = {};
		place2.node1 = Utils.indexToObject(self.components, getXMLString(xmlFile,basename.."#frontRight"));

		if place2.node1 == nil then
			break;
		end;
		place2.node2 = Utils.indexToObject(self.components, getXMLString(xmlFile,basename.."#backLeft"));
		place2.attacherNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(xmlFile,basename.."#attacherNode"),"0>"));
		local highOffsetNode = Utils.indexToObject(self.components, getXMLString(xmlFile,basename.."#highOffsetNode"));
		if highOffsetNode ~= nil then
			place2.highOffsetNode = highOffsetNode;
			place2.highOffset = nil;
		else
			place2.highOffset = Utils.getNoNil(getXMLFloat(xmlFile,basename.."#highOffset"),4);
		end;
		table.insert(self.place2,place2);
		i=i+1;
	end;
	self.Attachedbales2 = {};
	self.isBaleAttach2 = false;
	
	if not self.controlledByKey then
		local controlledAnims = table.getn(self.animationParts);
		if controlledAnims > 1 then
			self.animLockTime2 = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.baleCastPoints#animLockTime2"), (self.animationParts[2].animDuration/2));
			self.operateSecondArm = true;
		end;
	end;
	if self.foldingParts ~= nil then
		if table.getn(self.foldingParts) > 0 then
		--if self.foldingParts[1].animationName ~= nil then
			self.hasFoldingParts = true;
		end;
	end;
end;

function baleLockByMovement2:delete()
end;

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

function baleLockByMovement2:writeStream(streamId, connection)
    streamWriteBool(streamId, self.isBaleAttach2);
end;
  
function baleLockByMovement2:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if resetVehicles then
		if self.hasFoldingParts then
			self:setFoldDirection(1, false);
		end;
	end;
	return BaseMission.VEHICLE_LOAD_OK;
end;

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

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

function baleLockByMovement2:update(dt)
	if self:getIsActive() then
		if self.controlledByKey then
			if self:getIsActiveForInput() then
				if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) then
					self:setIsBaleAttached2(not self.isBaleAttach2);
				end;
			end;
		end;
	end;
end;

function baleLockByMovement2:updateTick(dt)

	if self:getIsActive() then
		if not self.controlledByKey and self.operateSecondArm then
			local animTime = self.animationParts[2].inputTime;
			if animTime ~= nil then
				if self.isBaleAttach2 then
					if self.animLockTime2 > animTime then
						self:setIsBaleAttached2(false);				
					end;
				else
					if self.animLockTime2 < animTime then
						self:setIsBaleAttached2(true);				
					end;
				end;
			end;
		end;
	end;
end;

function baleLockByMovement2:draw()
	if self:getIsActive() then
		if self.controlledByKey then
			if self.isBaleAttach2 then
				g_currentMission:addHelpButtonText(g_i18n:getText("Unlock2"), InputBinding.IMPLEMENT_EXTRA);
			else
				g_currentMission:addHelpButtonText(g_i18n:getText("Lock2"), InputBinding.IMPLEMENT_EXTRA);
			end;
		else
			if self.isBaleAttach2 then
				g_currentMission:addExtraPrintText(g_i18n:getText("Locked2"));
			end;
		end;
	end;
end;

function baleLockByMovement2:isBaleInRange2(place2,bale)
	local Xmax, Ymax, Zmax = getWorldTranslation(place2.node1);
		  Xmax, Ymax, Zmax = worldToLocal(place2.attacherNode,Xmax, Ymax, Zmax);
		  
	local Xmin, Ymin, Zmin = getWorldTranslation(place2.node2);	
		  Xmin, Ymin, Zmin = worldToLocal(place2.attacherNode,Xmin, Ymin, Zmin);
	
	local Xt, Yt, Zt = getWorldTranslation(bale);
		  Xt, Yt, Zt = worldToLocal(place2.attacherNode,Xt, Yt, Zt);

	local highOffset = nil;
	if place2.highOffsetNode ~= nil then
		local x, y, z = getTranslation(place2.node1)
		local x1, y2, z3 = getTranslation(place2.node2)
		local _, yOffset, _ = getTranslation(place2.highOffsetNode);
		highOffset = ((y-y2)/2) + yOffset;
		place2.highOffset = highOffset;
	end;
		
	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)+place2.highOffset and Yt>= (Ymax+Ymin)/2) then
		return true;
	else
		return false;
	end;
end;

function baleLockByMovement2:searchBales2()
	for index,item in pairs(g_currentMission.itemsToSave) do
		if item.item:isa(Bale) 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.place2) do
					local isInRange = self:isBaleInRange2(v,item.item.nodeId);			
					local is1stAttached = false;
					if isInRange then
						is1stAttached = self:attachbales2(v,item.item.nodeId,item.item);
					end;
				end;
			end;
		end;
	end;
end;

function baleLockByMovement2:setIsBaleAttached2(baleAttach, noEventSend)
	SetBaleAttach2Event.sendEvent(self, baleAttach, noEventSend)
	self.isBaleAttach2 = baleAttach;
	
	if baleAttach then
		self:searchBales2();	
	else
		self:detachbales2();
	end;
end;

function baleLockByMovement2:OrientJoint2(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 baleLockByMovement2:attachbales2(place2,bale,baleT)
	local attachedbale = {};
	attachedbale.bale = bale;
	if self.isServer then
		attachedbale.AT = createTransformGroup("AT");
		link(place2.attacherNode,attachedbale.AT);
		
		self:OrientJoint2(bale,attachedbale.AT);

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

	table.insert(self.Attachedbales2, attachedbale);
	return true;
end;

function baleLockByMovement2:detachbales2()
	if self.isServer then
		for k,v in pairs(self.Attachedbales2) do
			removeJoint(v.JointIndex);
			delete(v.AT);
			v.JointIndex = nil;
			if v.baleT ~= nil then
				v.baleT.isAttached = nil;
			end;
		end;
	end;
	
	self.Attachedbales2 = nil;
	self.Attachedbales2 = {};
end;

function baleLockByMovement2:onAttach(attacherVehicle)
	if self.isServer then
		--self:setIsBaleAttached2(true);
	end;
end;

function baleLockByMovement2:onDetach()
	if self.isServer then
		self:setIsBaleAttached2(false);
	end;
	if self.hasFoldingParts then
		self:setFoldDirection(1, false);
	end;
end;



SetBaleAttach2Event = {};
SetBaleAttach2Event_mt = Class(SetBaleAttach2Event, Event);
  
InitEventClass(SetBaleAttach2Event, "SetBaleAttach2Event");
  
function SetBaleAttach2Event:emptyNew()
	local self = Event:new(SetBaleAttach2Event_mt);
	self.className="SetBaleAttach2Event";
	return self;
end;
  
function SetBaleAttach2Event:new(bale, baleAttach)
      local self = SetBaleAttach2Event:emptyNew()
      self.bale = bale;
      self.baleAttach = baleAttach;
      return self;
end;
  
function SetBaleAttach2Event:readStream(streamId, connection)
	local id = streamReadInt32(streamId);
	self.baleAttach = streamReadBool(streamId);
	self.bale = networkGetObject(id);
	self:run(connection);
end;
  
function SetBaleAttach2Event:writeStream(streamId, connection)
	streamWriteInt32(streamId, networkGetObjectId(self.bale));
	streamWriteBool(streamId, self.baleAttach);
end;
  
function SetBaleAttach2Event:run(connection)
	if not connection:getIsServer() then
		g_server:broadcastEvent(self, false, connection, self.bale);
	end;
	self.bale:setIsBaleAttached2(self.baleAttach, true);
end;
  
function SetBaleAttach2Event.sendEvent(vehicle, baleAttach, noEventSend)
	if baleAttach ~= vehicle.isBaleAttach2 then
		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then
				g_server:broadcastEvent(SetBaleAttach2Event:new(vehicle, baleAttach), nil, nil, vehicle);
			else
				g_client:getServerConnection():sendEvent(SetBaleAttach2Event:new(vehicle, baleAttach));
			end;
		end;
	end;
end;

