--
-- Wrapper
-- Specialization for Wrapper mod
--
-- @author  JoXXer
-- @date  2011/01/09

Wrapper = {};

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

function Wrapper:load(xmlFile)

	self.setArmMiddleUp = SpecializationUtil.callSpecializationsFunction("setArmMiddleUp");
	self.setArmMiddleDown = SpecializationUtil.callSpecializationsFunction("setArmMiddleDown");
	self.setWrapping = SpecializationUtil.callSpecializationsFunction("setWrapping");
	self.setUnloading = SpecializationUtil.callSpecializationsFunction("setUnloading");
	self.setTurnToLoad = SpecializationUtil.callSpecializationsFunction("setTurnToLoad");
	self.setBalesVisibility = SpecializationUtil.callSpecializationsFunction("setBalesVisibility");
	self.setResetActiveBale = SpecializationUtil.callSpecializationsFunction("setResetActiveBale");
	self.createBale = SpecializationUtil.callSpecializationsFunction("createBale");
	self.dropBale = SpecializationUtil.callSpecializationsFunction("dropBale");
	self.updateActivateText = SpecializationUtil.callSpecializationsFunction("updateActivateText");
	
	-- Static Bales --
	self.numStaticBales = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.staticBales#count"), 0);	
	self.staticBales = {};
	for i=1, self.numStaticBales do
        local baleNamei = string.format("vehicle.staticBales.staticBale" .. "%d", i);
        self.staticBales[i] = Utils.indexToObject(self.components, getXMLString(xmlFile, baleNamei .. "#index"));
    end;
	
	-- Bale arm attacher --
	self.searchArmBales = Wrapper.searchArmBales;
	self.attachArmObjects = Wrapper.attachArmObjects;
	self.detachArmObjects = Wrapper.detachArmObjects;
	self.armOrientJoint = Wrapper.armOrientJoint;
	self.setArmWorkState = Wrapper.setArmWorkState;
	self.isBaleInArmRange = Wrapper.isBaleInArmRange;
	self.armPlace = {};
	self.armPlace.node1 = Utils.indexToObject(self.components, getXMLString(xmlFile,"vehicle.Loadingarm#castPoint1"));		
	self.armPlace.node2 = Utils.indexToObject(self.components, getXMLString(xmlFile,"vehicle.Loadingarm#castPoint2"));
	self.armPlace.attacherNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(xmlFile,"vehicle.Loadingarm#attacherNode"),"1>"));
	self.armPlace.highOffset = Utils.getNoNil(getXMLFloat(xmlFile,"vehicle.Loadingarm#highOffset"),4);	
	self.AttachedArmObjects = {};
	self.attacherArmMod = 0;
	self.attacherArmModOld = 0;
	self.allowArmAttachment = true;
	self.balesOnArmAttached = false;
	
	-- Bale wrappingTable attacher --
	self.searchTableBales = Wrapper.searchTableBales;
	self.attachTableObjects = Wrapper.attachTableObjects;
	self.detachTableObjects = Wrapper.detachTableObjects;
	self.tableOrientJoint = Wrapper.tableOrientJoint;
	self.setTableWorkState = Wrapper.setTableWorkState;
	self.isBaleInTableRange = Wrapper.isBaleInTableRange;
	self.tablePlace = {};
	self.tablePlace.node1 = Utils.indexToObject(self.components, getXMLString(xmlFile,"vehicle.Wrappingtable#castPoint1"));		
	self.tablePlace.node2 = Utils.indexToObject(self.components, getXMLString(xmlFile,"vehicle.Wrappingtable#castPoint2"));
	self.tablePlace.attacherNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(xmlFile,"vehicle.Wrappingtable#attacherNode"),"0>0|0|0|0|0|0"));
	self.tablePlace.highOffset = Utils.getNoNil(getXMLFloat(xmlFile,"vehicle.Wrappingtable#highOffset"),4);	
	self.AttachedTableObjects = {};
	self.attacherTableMod = 0;
	self.attacherTableModOld = 0;
	self.allowTableAttachment = true;
	self.balesOnTableAttached = false;
	self.baleCanBeWrapped = false;
	
	-- Animations --
	self.ArmAnimationMiddleUp = getXMLString(xmlFile, "vehicle.LoadingArmMiddleUp#animationName");
	self.ArmAnimationMiddleDown = getXMLString(xmlFile, "vehicle.LoadingArmMiddleDown#animationName");
	self.WrappingAnimation = getXMLString(xmlFile, "vehicle.WrappingTableWrapping#animationName");
	self.WrappingUnloadAnimation = getXMLString(xmlFile, "vehicle.WrappingTableUnload#animationName");
	self.TurnToLoadAnimation = getXMLString(xmlFile, "vehicle.TurnToLoadAnimation#animationName");
	
	self.isReadyToUnload = false;
	self.turnToLoad = false;
	self.isUnloading = false;
	self.isWrapping = false;
	self.armMiddleUp = false;
	self.armMiddleDown = false;
	self.isArmInMiddleAndCanGoDown = false;
	self.isReadyToLoad = true;
	self.isBaleVisible = false;
	self.resetActiveBale = false;
	self.baleActive = 1;
	self.usedFruitType = 0;

	self.baleInRange = {};
	
	--create bale-stuff--
   self.baleTypes = {};
   local i = 0;
   while true do
       local key = string.format("vehicle.baleTypes.baleType(%d)", i);
       local t = getXMLString(xmlFile, key.."#fruitType");
       local filename = getXMLString(xmlFile, key.."#filename");
       if t==nil or filename==nil then
           break;
       end;

       local entry = {};
       entry.filename = filename;
       local desc = FruitUtil.fruitTypes[t];
       if desc ~= nil then
           self.baleTypes[desc.index] = entry;

           if self.defaultBaleType == nil then
               self.defaultBaleType = entry;
           end;
       end;
       i = i +1;
   end;
   if self.defaultBaleType == nil then
       self.baleTypes = nil;
   end;

   self.bales = {};
   
   self.baleAnimRoot = Utils.getNoNil(Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.baleAnimation#node")), "0>0|0|0|0|0|0");

end;
function Wrapper:delete()
end;

function Wrapper:readUpdateStream(streamId, timestamp, connection)
end;

function Wrapper:writeUpdateStream(streamId, connection, dirtyMask)
end;

function Wrapper:draw()
	if self.isReadyToLoad and self.armMiddleDown and not self.armMiddleUp and not self.isArmInMiddleAndCanGoDown and not self.balesOnArmAttached then
		g_currentMission:addHelpButtonText(g_i18n:getText("ARM_IN_MIDDLE_CAN_GO_UP"), InputBinding.LOWER_IMPLEMENT);
	elseif self.isReadyToLoad and self.armMiddleDown and not self.armMiddleUp and not self.isArmInMiddleAndCanGoDown and self.balesOnArmAttached then
		g_currentMission:addHelpButtonText(g_i18n:getText("ARM_IN_MIDDLE_CAN_GO_UP_ATTACHED"), InputBinding.LOWER_IMPLEMENT);
	elseif self.isReadyToLoad and self.armMiddleDown and self.armMiddleUp then
		g_currentMission:addHelpButtonText(g_i18n:getText("ARM_UP"), InputBinding.LOWER_IMPLEMENT);
	elseif not self.armMiddleDown and not self.armMiddleUp then
		g_currentMission:addHelpButtonText(g_i18n:getText("ARM_DOWN"), InputBinding.LOWER_IMPLEMENT);
	elseif self.armMiddleDown and not self.armMiddleUp and self.isArmInMiddleAndCanGoDown and not self.balesOnArmAttached then
		g_currentMission:addHelpButtonText(g_i18n:getText("ARM_IN_MIDDLE_CAN_GO_DOWN"), InputBinding.LOWER_IMPLEMENT);
	elseif self.armMiddleDown and not self.armMiddleUp and self.isArmInMiddleAndCanGoDown and self.balesOnArmAttached then
		g_currentMission:addHelpButtonText(g_i18n:getText("ARM_IN_MIDDLE_CAN_GO_DOWN_ATTACHED"), InputBinding.LOWER_IMPLEMENT);
	elseif not self.isReadyToLoad and self.armMiddleDown and not self.armMiddleUp then
		g_currentMission:addHelpButtonText(g_i18n:getText("ARM_IN_MIDDLE_CAN_GO_DOWN_ATTACHED"), InputBinding.LOWER_IMPLEMENT);
	end;
	
	--if self:getAnimationTime(self.ArmAnimationMiddleUp) >= 1 then
		--if self.baleCanBeWrapped then
			--g_currentMission:addExtraPrintText(g_i18n:getText("START_WRAPPING_ARM_UP"));
		--end;
	--end;
	
	if self.isReadyToUnload and not self.isUnloading then
		g_currentMission:addHelpButtonText(g_i18n:getText("LIFT_WRAPPINGTABLE"), InputBinding.IMPLEMENT_EXTRA2);
	elseif self.isUnloading then
		g_currentMission:addHelpButtonText(g_i18n:getText("LOWER_WRAPPINGTABLE"), InputBinding.IMPLEMENT_EXTRA2);
	end;
	
	if self.baleCanBeWrapped and not self.armMiddleUp then
		g_currentMission:addHelpButtonText(g_i18n:getText("START_WRAPPING"), InputBinding.IMPLEMENT_EXTRA);
	end;
end;

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

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

function Wrapper:readStream(streamId, connection)
    self:setArmMiddleUp(streamReadBool(streamId), true);
	self:setArmMiddleDown(streamReadBool(streamId), true);
	self:setWrapping(streamReadBool(streamId), true);
	self:setUnloading(streamReadBool(streamId), true);
	self:setTurnToLoad(streamReadBool(streamId), true);
	self:setBalesVisibility(streamReadBool(streamId), true);
	self:setResetActiveBale(streamReadBool(streamId), true);
	self:setArmWorkState(streamReadBool(streamId), true);
	local numBales = streamReadInt16(streamId);
	for i=1, numBales do
		local fruitType = streamReadInt8(streamId);
		self:createBale(fruitType);
	end;

end;

function Wrapper:writeStream(streamId, connection)
    streamWriteBool(streamId, self.armMiddleUp);
	streamWriteBool(streamId, self.armMiddleDown);
	streamWriteBool(streamId, self.isWrapping);
	streamWriteBool(streamId, self.turnToLoad);
	streamWriteBool(streamId, self.isUnloading);
	streamWriteBool(streamId, self.isBaleVisible);
	streamWriteBool(streamId, self.resetActiveBale);
	streamWriteBool(streamId, self.balesOnArmAttached);
	streamWriteInt16(streamId, table.getn(self.bales));
	for i=1, table.getn(self.bales) do
		local bale = self.bales[i];
		streamWriteInt8(streamId, bale.fruitType);
	end;

end;

function Wrapper:update(dt)
	if self:getIsActiveForInput() then
		if self.isReadyToLoad and self.armMiddleDown and not self.armMiddleUp and not self.isArmInMiddleAndCanGoDown then
			if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) and self:getAnimationTime(self.ArmAnimationMiddleDown) == 1 then
				self:setArmMiddleUp(not self.armMiddleUp);
				self.isArmInMiddleAndCanGoDown = true;
			end;
		elseif self.isReadyToLoad and self.armMiddleDown and self.armMiddleUp then
			if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) and self:getAnimationTime(self.ArmAnimationMiddleUp) == 1 then
				self:setArmMiddleUp(not self.armMiddleUp);
				self:searchTableBales();
			end;
		elseif not self.armMiddleDown and not self.armMiddleUp then
			if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) and self:getAnimationTime(self.ArmAnimationMiddleDown) == 0 then
				self:setArmMiddleDown(not self.armMiddleDown);
				if self.balesOnArmAttached == false then
					self:setArmWorkState(self.balesOnArmAttached);
				end;
			end;
		elseif self.armMiddleDown and not self.armMiddleUp and self.isArmInMiddleAndCanGoDown then
			if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) and self:getAnimationTime(self.ArmAnimationMiddleUp) == 0 then
				self:setArmMiddleDown(not self.armMiddleDown);
				self.isArmInMiddleAndCanGoDown = false;
				if self.balesOnArmAttached == true then
					self:setArmWorkState(self.balesOnArmAttached);
				end;
			end;
		elseif not self.isReadyToLoad and self.armMiddleDown and not self.armMiddleUp then
			if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) and self:getAnimationTime(self.ArmAnimationMiddleDown) == 1 then
				self:setArmMiddleDown(not self.armMiddleDown);
			end;
		end;
		
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) and not self.armMiddleUp then
			self:searchTableBales();
			if self.baleCanBeWrapped then
				self.isWrapping = true;
				self:searchTableBales();
				self:setWrapping(self.isWrapping);
			end;
		end;
		
		if self:getAnimationTime(self.WrappingUnloadAnimation) == 0 or self:getAnimationTime(self.WrappingUnloadAnimation) == 1 then
			if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) and self.isReadyToUnload then
				self:setUnloading(not self.isUnloading);
			end;
		end;
    end;
end;

function Wrapper:updateTick(dt)	

	if not self.isReadyToLoad and not self.armMiddleDown and not self.armMiddleUp and self:getAnimationTime(self.ArmAnimationMiddleDown) == 0 then
		if self.balesOnArmAttached == true then
			self:setArmWorkState(self.balesOnArmAttached);
		end;
	end;
	if self.isReadyToLoad and self.armMiddleDown and self.armMiddleUp and self:getAnimationTime(self.ArmAnimationMiddleUp) == 1 then
		if self.balesOnArmAttached == true then
			self:setArmWorkState(self.balesOnArmAttached);
		end;
	end;

	if self:getAnimationTime(self.WrappingAnimation) >=1 and self.isWrapping then
		self.isWrapping = false;
		self.isReadyToUnload = true;
		self:setBalesVisibility(not self.isBaleVisible);
		self:setResetActiveBale(not self.resetActiveBale);
		if self.baleTypes ~= nil then
			-- create bale
			self:createBale(self.usedFruitType);
			if g_server ~= nil then
				g_server:broadcastEvent(CreateBaleEvent:new(self, self.usedFruitType, 0), nil, nil, self);
			else
				g_client:getServerConnection():sendEvent(CreateBaleEvent:new(self, self.usedFruitType, 0));
			end;
		end;
	end;
	
	if self.isUnloading then
		if table.getn(self.bales) > 0 then
			self:dropBale(1);
			if g_client ~= nil then
				g_client:getServerConnection():sendEvent(DropBaleEvent:new(self, 1, 0));
			end;
		end;
	end;
	
	if self.isWrapping then
		if self:getRealAnimationTime(self.WrappingAnimation) >= 0 and getVisibility(self.staticBales[1]) == false and self.baleActive == 1 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 2500 and getVisibility(self.staticBales[2]) == false and self.baleActive == 2 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 5000 and getVisibility(self.staticBales[3]) == false and self.baleActive == 3 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 7500 and getVisibility(self.staticBales[4]) == false and  self.baleActive == 4 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 10000 and getVisibility(self.staticBales[5]) == false and  self.baleActive == 5 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 12500 and getVisibility(self.staticBales[6]) == false and self.baleActive == 6 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 15000 and getVisibility(self.staticBales[7]) == false and  self.baleActive == 7 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 17500 and getVisibility(self.staticBales[8]) == false and self.baleActive == 8 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 20000 and getVisibility(self.staticBales[9]) == false and self.baleActive == 9 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 22500 and getVisibility(self.staticBales[10]) == false and self.baleActive == 10 then
			self:setBalesVisibility(not self.isBaleVisible);
		elseif self:getRealAnimationTime(self.WrappingAnimation) >= 25000 and getVisibility(self.staticBales[11]) == false and self.baleActive == 11 then
			self:setBalesVisibility(not self.isBaleVisible);
		end;
	end;
	
	
	if self.turnToLoad and self:getAnimationTime(self.WrappingUnloadAnimation) == 0 then
		--print("turntoloadif");
		self:setTurnToLoad(self.turnToLoad);
	end;
end;
--tableattachings--
function Wrapper:isBaleInTableRange(node1,node2,Yoffset,Bale)
	local Xmax, Ymax, Zmax = getWorldTranslation(node1);
		  Xmax, Ymax, Zmax = worldToLocal(self.tablePlace.attacherNode,Xmax, Ymax, Zmax);
		  
	local Xmin, Ymin, Zmin = getWorldTranslation(node2);	
		  Xmin, Ymin, Zmin = worldToLocal(self.tablePlace.attacherNode,Xmin, Ymin, Zmin);
	
	local Xt, Yt, Zt = getWorldTranslation(Bale);
		  Xt, Yt, Zt = worldToLocal(self.tablePlace.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)+Yoffset and Yt>= (Ymax+Ymin)/2) then
		return true;
	else
		return false;
	end;
end;

function Wrapper:searchTableBales()
	for index,item in pairs(g_currentMission.itemsToSave) do
		if item.item:isa(Bale) then 
			if item.item.isAttached == nil then
				local isInRange = self:isBaleInTableRange(self.tablePlace.node1,self.tablePlace.node2,self.tablePlace.highOffset,item.item.nodeId);
				if isInRange and self.isWrapping then
					local baleObject = item.item;
					if baleObject ~= nil and baleObject:isa(Bale) then
						self.usedFruitType = baleObject.fruitType;
						baleObject:delete();
					end;
					self.baleCanBeWrapped = false;
				elseif isInRange then
					self.baleCanBeWrapped = isInRange;
					self.baleInRange = item.item;
				elseif not isInRange and self.baleInRange == item.item then
					self.baleCanBeWrapped = isInRange;
					self.baleInRange = nil;
				end;
			end;
		end;
	end;
end;


function Wrapper:setTableWorkState(isCoupling,noEventSend)
	--setWorkState.sendEvent(self, isCoupling, noEventSend);
	if isCoupling then
		self:detachTableObjects();	
	else
		self:searchTableBales();
	end;
end;

function Wrapper:tableOrientJoint(Source, Target)	
	local xw, yw, zw = getWorldTranslation(Source);		
	local x,y,z = worldToLocal(getParent(Target), xw, yw, zw);	
	setTranslation(Target, x,y,z);			
	--JointRotation Anpassung an das Objekt
	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);
	--print("Print in tableOrientJoint");
	return false;
end;

function Wrapper:attachTableObjects(object,baleT)
	local attachedobject = {};
	attachedobject.object = object;
	if self.isServer then
		attachedobject.AT = createTransformGroup("AT");
		link(self.tablePlace.attacherNode,attachedobject.AT);
		
		attachedobject.objectMass = getMass(object);
		setMass(object,attachedobject.objectMass*0.01);
		
		self:tableOrientJoint(object,attachedobject.AT);

		local constr = JointConstructor:new();					
		constr:setActors(self.tablePlace.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.AttachedTableObjects, attachedobject);
	return true;
end;

function Wrapper:detachTableObjects()
	if self.isServer then
		for k,v in pairs(self.AttachedTableObjects) do
			removeJoint(v.JointIndex);
			delete(v.AT);
			v.JointIndex = nil;
			setMass(v.object,v.objectMass);
			if v.baleT ~= nil then
				v.baleT.isAttached = nil;
			end;
		end;
	end;
	
	self.AttachedTableObjects = nil;
	self.AttachedTableObjects = {};
	self.balesOnTableAttached = false;
end;

--armattachers--
function Wrapper:isBaleInArmRange(node1,node2,Yoffset,Bale)
	local Xmax, Ymax, Zmax = getWorldTranslation(node1);
		  Xmax, Ymax, Zmax = worldToLocal(self.armPlace.attacherNode,Xmax, Ymax, Zmax);
		  
	local Xmin, Ymin, Zmin = getWorldTranslation(node2);	
		  Xmin, Ymin, Zmin = worldToLocal(self.armPlace.attacherNode,Xmin, Ymin, Zmin);
	
	local Xt, Yt, Zt = getWorldTranslation(Bale);
		  Xt, Yt, Zt = worldToLocal(self.armPlace.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)+Yoffset and Yt>= (Ymax+Ymin)/2) then
		return true;
	else
		return false;
	end;
end;

function Wrapper:searchArmBales()
	for index,item in pairs(g_currentMission.itemsToSave) do
		if item.item:isa(Bale) then 
			if item.item.isAttached == nil then

				local isInRange = self:isBaleInArmRange(self.armPlace.node1,self.armPlace.node2,self.armPlace.highOffset,item.item.nodeId);
				
				local is1stAttached = false;
				if isInRange then
					is1stAttached = self:attachArmObjects(item.item.nodeId,item.item);
				end;
				if is1stAttached then
					self.balesOnArmAttached = true;
				end;
			end;
		end;
	end;
	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		
				local isInRange = self:isBaleInArmRange(self.armPlace.node1,self.armPlace.node2,self.armPlace.highOffset,components.node);	
				if isInRange then	
					is1stAttached = self:attachArmObjects(components.node);
				end;
			end;
			if is1stAttached then
				self.balesOnArmAttached = true;
			end;
		end;
	end;
end;


function Wrapper:setArmWorkState(isCoupling,noEventSend)
	ArmWorkStateEvent.sendEvent(self, isCoupling, noEventSend);
	if isCoupling then
		self:detachArmObjects();	
	else
		self:searchArmBales();
	end;
end;

function Wrapper:armOrientJoint(Source, Target)	
	local xw, yw, zw = getWorldTranslation(Source);		
	local x,y,z = worldToLocal(getParent(Target), xw, yw, zw);	
	setTranslation(Target, x,y,z);			
	--JointRotation Anpassung an das Objekt
	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 Wrapper:attachArmObjects(object,baleT)
	local attachedobject = {};
	attachedobject.object = object;
	if self.isServer then
		attachedobject.AT = createTransformGroup("AT");
		link(self.armPlace.attacherNode,attachedobject.AT);
		
		attachedobject.objectMass = getMass(object);
		setMass(object,attachedobject.objectMass*0.1);
		
		self:armOrientJoint(object,attachedobject.AT);

		local constr = JointConstructor:new();					
		constr:setActors(self.armPlace.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.AttachedArmObjects, attachedobject);
	return true;
end;

function Wrapper:detachArmObjects()
	if self.isServer then
		for k,v in pairs(self.AttachedArmObjects) do
			removeJoint(v.JointIndex);
			delete(v.AT);
			v.JointIndex = nil;
			setMass(v.object,v.objectMass);
			if v.baleT ~= nil then
				v.baleT.isAttached = nil;
			end;
		end;
	end;
	
	self.AttachedArmObjects = nil;
	self.AttachedArmObjects = {};
	self.balesOnArmAttached = false;
end;

function Wrapper:setBalesVisibility(baleVisibility, noEventSend)
	if baleVisibility ~= self.isBaleVisible then
		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then
				g_server:broadcastEvent(SetBalesEvent:new(self, baleVisibility), nil, nil, self);
			else
				g_client:getServerConnection():sendEvent(SetBalesEvent:new(self, baleVisibility));
			end;
		end;
		self.isBaleVisibile = baleVisibility;
		if self.baleActive ~= 12 then
			setVisibility(self.staticBales[self.baleActive], baleVisibility);
		end;
		if self.baleActive ~= 1 then
			setVisibility(self.staticBales[self.baleActive-1], not baleVisibility);
		end;
		--print(string.format("Should set bale" .. "%d" .. " visible in setBalesVisibility", self.baleActive));
		self.baleActive = self.baleActive+1;
	end;
end;

function Wrapper:setTurnToLoad(isLoading,noEventSend)
	SetTurnToLoadEvent.sendEvent(self, isLoading, noEventSend);
	-- Play turntoload animation --
	if self.TurnToLoadAnimation ~= nil and self.playAnimation ~= nil then
		self:playAnimation(self.TurnToLoadAnimation, 1, nil, true);
		self.turnToLoad = false;
		self.isReadyToLoad = true;
	end;
end;

function Wrapper:setUnloading(isUnloadingState,noEventSend)
	SetUnloadingEvent.sendEvent(self, isUnloadingState, noEventSend);
	-- Play unloading animation --
	self.isWrappingTableDown = isUnloadingState;
	
	if self.isWrappingTableDown then
		if self.WrappingUnloadAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.WrappingUnloadAnimation, 1, nil, true);
			self.isUnloading = true;
		end;
	else
		if self.WrappingUnloadAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.WrappingUnloadAnimation, -1, nil, true);
			self.isUnloading = false;
			self.isReadyToUnload = false;
			self.turnToLoad = true;
		end;
	end;
end;

function Wrapper:setArmMiddleUp(isArmMiddleUp,noEventSend)
	SetArmMiddleUpEvent.sendEvent(self, isArmMiddleUp, noEventSend);
	-- Play arm animation --
	if isArmMiddleUp then
		if self.ArmAnimationMiddleUp ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.ArmAnimationMiddleUp, 1, nil, true);
			self.armMiddleUp = true;
		end;
	else
		if self.ArmAnimationMiddleUp ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.ArmAnimationMiddleUp, -1, nil, true);
			self.armMiddleUp = false;
		end;
	end;
end;
function Wrapper:setArmMiddleDown(isArmMiddleDown,noEventSend)
	SetArmMiddleDownEvent.sendEvent(self, isArmMiddleDown, noEventSend);
	-- Play arm animation --
	if isArmMiddleDown then
		if self.ArmAnimationMiddleDown ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.ArmAnimationMiddleDown, 1, nil, true);
			self.armMiddleDown = true;
		end;
	else
		if self.ArmAnimationMiddleDown ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.ArmAnimationMiddleDown, -1, nil, true);
			self.armMiddleDown = false;
		end;
	end;
end;

function Wrapper:setWrapping(isWrapping,noEventSend)
	SetWrappingEvent.sendEvent(self, isWrapping, noEventSend);
	-- Play wrapping animation --
	if self.WrappingAnimation ~= nil and self.playAnimation ~= nil then
		self:playAnimation(self.WrappingAnimation, 1, nil, true);
		self.isReadyToLoad = false;
	end;
end;

function Wrapper:createBale(usedFruitType)
    local baleType = self.baleTypes[usedFruitType];
    if baleType == nil then
        baleType = self.defaultBaleType;
    end;
    local baleRoot = Utils.loadSharedI3DFile(baleType.filename, self.baseDirectory);

    local baleId = getChildAt(baleRoot, 0);
    setRigidBodyType(baleId, "None");
	link(self.baleAnimRoot, baleId);
    delete(baleRoot);

    local bale = {};
    bale.id = baleId;
    bale.time = 0;
    bale.fruitType = usedFruitType;
    bale.filename = Utils.getFilename(baleType.filename, self.baseDirectory);
    bale.lastX, bale.lastY, bale.lastZ = getWorldTranslation(bale.id);
    table.insert(self.bales, bale);
    local i = table.getn(self.bales);
	--print("Bale should be created");
end;

function Wrapper:dropBale(baleIndex)
    local bale = self.bales[baleIndex];
		if bale ~= nil then
		--local deltaRealTime = (self.time - self.baleLastPositionTime)/1000;
		local x,y,z = getWorldTranslation(bale.id);
		local rx,ry,rz = getWorldRotation(bale.id);
		link(getRootNode(), bale.id);

		if self.isServer then
			local baleObject = Bale:new(self.isServer, self.isClient);
			baleObject:load(bale.filename, x,y,z,rx,ry,rz);
			baleObject:register();

			local lx, ly, lz = bale.lastX, bale.lastY, bale.lastZ;
			--setLinearVelocity(baleObject.nodeId, (x-lx)/deltaRealTime, (y-ly)/deltaRealTime, (z-lz)/deltaRealTime);
		end;
		delete(bale.id);
		table.remove(self.bales, baleIndex);
	end;
end;

function Wrapper:setResetActiveBale(activeBaleReset, noEventSend)
	SetActiveBaleEvent.sendEvent(self, activeBaleReset, noEventSend);
	if activeBaleReset then
		self.baleActive = 1;
	end;
end;

function Wrapper:onDetach()
end;

function Wrapper:onAttach()
end;

function Wrapper:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then

	end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

function Wrapper:getSaveAttributesAndNodes(nodeIdent)
    local attributes = nil;
    local node = nil;
    return attributes, node;
end;


