--
-- henly 20 (Ls_uk Modteam)
-- 28.11.2010
--
-- > www.LS-UK.info

dropbed = {};

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


function dropbed:load(xmlFile)

	self.setHydraulicDirection = SpecializationUtil.callSpecializationsFunction("setHydraulicDirection");
	self.setRotationMax1 = SpecializationUtil.callSpecializationsFunction("setRotationMax1");
	
	self.setIsTurnedOn = SpecializationUtil.callSpecializationsFunction("setIsTurnedOn");
	self.setmoveSupport = SpecializationUtil.callSpecializationsFunction("setmoveSupport");
	self.MoveSupportAnimation = getXMLString(xmlFile, "vehicle.moveSupportDB#animationName");
	self.moveSupport = false;
	self.setRotateBody = SpecializationUtil.callSpecializationsFunction("setRotateBody");
	self.RotateBodyAnimation = getXMLString(xmlFile, "vehicle.RotateBody#animationName");
	self.RotateBody = false;
	
	self.GetVehiclesInRange = dropbed.GetVehiclesInRange;
	self.attachVehicles = dropbed.attachVehicles;
	self.detachVehicles = dropbed.detachVehicles;
	self.Attachers={};
	self.PF={};
	local Parent = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.Attacher#ParentIndex"));
	local Parent2 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.Attacher#PlaceFinderParent"));
	local numAttachers = getNumOfChildren(Parent);
	local numPlaceFinders = getNumOfChildren(Parent2);
	for i=1, numAttachers do
		self.Attachers[i] = {};
		self.Attachers[i].node = getChildAt(Parent, i-1);
		self.Attachers[i].attachedObject = nil;
	end;	
	for j=1, numPlaceFinders do
		self.PF[j] = {};
		self.PF[j].Transform = getChildAt(Parent2, j-1);
	end;
	self.once = true;
	self.onceActive = true;	

	local hydraulicsCount = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.hydraulics#count"), 0);	
	self.hydraulics = {};	
	for i=1, hydraulicsCount do
		local hydraulicName = string.format("vehicle.hydraulics.hydraulic%d", i);		
		self.hydraulics[i] = {};		
		self.hydraulics[i].node = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#index"));
		self.hydraulics[i].punch = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#punch"));
		self.hydraulics[i].translationPunch = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#punchFixpoint"));
		self.hydraulics[i].fixPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#fixpoint"));	
		local xUp, yUp, zUp = Utils.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, hydraulicName .. "#upVectors"),"0 1 0"));
		self.hydraulics[i].upVectors = {xUp, yUp, zUp};
		
		local ax, ay, az;		
		if self.hydraulics[i].punch ~= nil then
			ax, ay, az = getWorldTranslation(self.hydraulics[i].punch);
		else
			ax, ay, az = getWorldTranslation(self.hydraulics[i].node);
		end;
		if self.hydraulics[i].translationPunch ~= nil then
			local bx, by, bz = getWorldTranslation(self.hydraulics[i].translationPunch);		
			self.hydraulics[i].punchDistance = Utils.vector3Length(ax-bx, ay-by, az-bz);
		end;
	end;
	self.setHydraulicTime = 30;
	
	self.rotationMax1 = false;		
    self.isTurnedOn = false;
end;

function dropbed:delete()
end;

function dropbed:readStream(streamId, connection)
    local turnedOn = streamReadBool(streamId);
    self:setIsTurnedOn(turnedOn, true);
	self:setmoveSupport(streamReadBool(streamId), true);
	self:setRotateBody(streamReadBool(streamId), true);		
end;

function dropbed:writeStream(streamId, connection)
	streamWriteBool(streamId, self.isTurnedOn);
	streamWriteBool(streamId, self.rotateMax1);
	streamWriteBool(streamId, self.moveSupport);	
	streamWriteBool(streamId, self.RotateBody);	
end;

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

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

function dropbed:update(dt)

	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
			self:setIsTurnedOn(not self.isTurnedOn);
		end;
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
			self:setRotateBody(not self.isRotateBodyOn);				
		end;
	end;
end;

function dropbed:updateTick(dt)
	if self:getIsActive() then
		if self.isTurnedOn then
			local nearestVehicles = {};
			if self.once then
				self.nearestVehicles = {self:GetVehiclesInRange()};
				self.once = false;
			end;
			for i = 1, table.getn(self.nearestVehicles) do
				self:attachVehicles(self.nearestVehicles[i], i);
			end;
		else
			self.once = true;
			for i = 1, table.getn(self.nearestVehicles) do
				self:detachVehicles(self.nearestVehicles[i], i);
			end;	
		end;
	end;

	if self:getIsActive() and self.isClient then
		for i, jointDesc in pairs(self.componentJoints) do
		   setJointFrame(self.componentJoints[i].jointIndex, 0, self.componentJoints[i].jointNode);
		end;
	end;
	
	if self:getIsActive() then			
		self.setHydraulicTime = 30;	
	end;

	if self.setHydraulicTime > 0 then
		for k,v in pairs(self.hydraulics) do 
			self:setHydraulicDirection(k);
		end;
		self.setHydraulicTime = self.setHydraulicTime - 1;
	end;

	if self.attacherVehicle then
		for k, implement in pairs(self.attacherVehicle.attachedImplements) do
			if implement.object == self then
				local index = implement.jointDescIndex;
				self.attacherVehicleJoint = self.attacherVehicle.attacherJoints[index];
				setJointRotationLimit(self.attacherVehicleJoint.jointIndex, 2, true, Utils.degToRad(-20), Utils.degToRad(20));
			end;
		end;
	end;	
end;

function dropbed:draw()
	if self:getIsActive() then
		if self.isTurnedOn then
			g_currentMission:addHelpButtonText(g_i18n:getText("Unlock"), InputBinding.IMPLEMENT_EXTRA3);
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("Lock"), InputBinding.IMPLEMENT_EXTRA3);
		end;
		
		if self.RotateBody == true then
			g_currentMission:addHelpButtonText(g_i18n:getText("Up"), InputBinding.IMPLEMENT_EXTRA2);
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("Down"), InputBinding.IMPLEMENT_EXTRA2);
		end;
	end;
end;

function dropbed:onDetach()
	self.onceActive = false;
	self.isTurnedOn = false;

	if not self.isRotateBodyOn then
		self:setmoveSupport(false);
	else
		self:setmoveSupport(true);		
	end;
end;

function dropbed:onAttach(attacherVehicle)
	self.isTurnedOn = true;
	self:setmoveSupport(true);
end;

function dropbed:validateAttacherJoint(implement, jointDesc, dt)
	return true;
end;

function dropbed:setHydraulicDirection(index)
	local hydraulic = self.hydraulics[index];

	if hydraulic.fixPoint ~= nil then
		local ax, ay, az = getWorldTranslation(hydraulic.node);
		local bx, by, bz = getWorldTranslation(hydraulic.fixPoint);
		local x, y, z = worldDirectionToLocal(getParent(hydraulic.node), bx-ax, by-ay, bz-az);
		local xUp, yUp, zUp = unpack(hydraulic.upVectors);
		setDirection(hydraulic.node, x, y, z, xUp, yUp, zUp);
		if hydraulic.punch ~= nil then
			local distance = Utils.vector3Length(ax-bx, ay-by, az-bz);
			setTranslation(hydraulic.punch, 0, 0, distance-hydraulic.punchDistance);
		end;
	end;
end;

function dropbed:setIsTurnedOn(turnedOn, noEventSend)
	SetTurnedOnEvent.sendEvent(self, turnedOn, noEventSend)
	self.isTurnedOn = turnedOn;
end;

function dropbed:attachVehicles(node, k)
	if self.Attachers[k].node ~= nil and self.Attachers[k].attachedObject == nil then 			
		--JointTranslation Anpassung an das Objekt
		local xw, yw, zw = getWorldTranslation(node.components[1].node);		
		local x,y,z = worldToLocal(getParent(self.Attachers[k].node), xw, yw, zw);	
		setTranslation(self.Attachers[k].node, x,y,z);			
		--JointRotation Anpassung an das Objekt
		local zX, zY, zZ = localDirectionToWorld(node.components[1].node, 0,0,1);
		local zX, zY, zZ = worldDirectionToLocal(getParent(self.Attachers[k].node), zX, zY, zZ);
		local yX, yY, yZ = localDirectionToWorld(node.components[1].node, 0,1,0);
		local yX, yY, yZ = worldDirectionToLocal(getParent(self.Attachers[k].node), yX, yY, yZ);
		setDirection(self.Attachers[k].node, zX, zY, zZ, yX, yY, yZ);
		
		if node.enterReferenceNode == nil then
			node:onAttach(self);
		end;
		--anhaengen
		local constr = JointConstructor:new();					
		constr:setActors(self.components[1].node, node.components[1].node);
		constr:setJointTransforms(self.Attachers[k].node,  node.components[1].node);
		for i=1, 3 do		                    
			constr:setTranslationLimit(i-1, true, 0, 0);
			constr:setRotationLimit(i-1, 0, 0);
		end;		
		self.Attachers[k].attachedObject = constr:finalize();
	end;
end;

function dropbed:detachVehicles(node, k)
	if self.Attachers[k].attachedObject ~= nil then	
		node.attacherVehicle = nil;
		
		if node.enterReferenceNode == nil then
			node:onDetach(self);
		end;		
		removeJoint(self.Attachers[k].attachedObject);
		self.Attachers[k].attachedObject = nil;
		
		setTranslation(self.Attachers[k].node,0,0,0);
		setRotation(self.Attachers[k].node,0,0,0);
	end;
end;

function dropbed:GetVehiclesInRange()
	local nearestNode = {};
	local nearestDistance = 2;
	for u,obj in pairs(self.PF) do
		local px, py, pz = getWorldTranslation(obj.Transform);
		
		for k,v in pairs(g_currentMission.vehicles) do
			if v ~= self and v ~= self.attacherVehicle then
				local x,y,z = getWorldTranslation(v.components[1].node);
				local distance = Utils.vector3Length(px-x, py-y, pz-z);
				if distance < nearestDistance then
					if table.getn(nearestNode)+1 <= table.getn(self.Attachers) then
						nearestNode[table.getn(nearestNode)+1] = v;
						print("eingetragen");
					end;
				end;
			end;
		end;
	end;
	return unpack(nearestNode)
end;

function dropbed:setmoveSupport(ismoveSupport,noEventSend)
	setmoveSupportEvent.sendEvent(self, ismoveSupport, noEventSend);
	-- Play moveSupport animation --
	self.ismoveSupportOn = ismoveSupport;
	if self.ismoveSupportOn then
		if self.MoveSupportAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.MoveSupportAnimation, -1, nil, true);
			self.moveSupport = true;
		end;
	else
		if self.MoveSupportAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.MoveSupportAnimation, 1, nil, true);
			self.moveSupport = false;
		end;
	end;	
end;

function dropbed:setRotateBody(isRotateBody,noEventSend)
	SetRotateBodyEvent.sendEvent(self, isRotateBody, noEventSend);
	-- Play RotateBody animation --
	self.isRotateBodyOn = isRotateBody;
	if self.isRotateBodyOn then
		if self.RotateBodyAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.RotateBodyAnimation, 1, nil, true);
			self.RotateBody = true;
		end;
	else
		if self.RotateBodyAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.RotateBodyAnimation, -1, nil, true);
			self.RotateBody = false;
		end;
	end;	
end;

setmoveSupportEvent = {};
setmoveSupportEvent_mt = Class(setmoveSupportEvent, Event);

InitEventClass(setmoveSupportEvent, "setmoveSupportEvent");

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

function setmoveSupportEvent:new(vehicle, ismoveSupport)
    local self = setmoveSupportEvent:emptyNew()
    self.vehicle = vehicle;
	self.ismoveSupport = ismoveSupport;
    return self;
end;

function setmoveSupportEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.ismoveSupport = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function setmoveSupportEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.ismoveSupport);
end;

function setmoveSupportEvent:run(connection)   
	self.vehicle:setmoveSupport(self.ismoveSupport, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(setmoveSupportEvent:new(self.vehicle, self.ismoveSupport), nil, connection, self.vehicle);
    end;
end;

function setmoveSupportEvent.sendEvent(vehicle, ismoveSupport, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(setmoveSupportEvent:new(vehicle, ismoveSupport), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(setmoveSupportEvent:new(vehicle, ismoveSupport));
		end;
	end;
end;

SetRotateBodyEvent = {};
SetRotateBodyEvent_mt = Class(SetRotateBodyEvent, Event);

InitEventClass(SetRotateBodyEvent, "SetRotateBodyEvent");

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

function SetRotateBodyEvent:new(vehicle, isRotateBody)
    local self = SetRotateBodyEvent:emptyNew()
    self.vehicle = vehicle;
	self.isRotateBody = isRotateBody;
    return self;
end;

function SetRotateBodyEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.isRotateBody = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function SetRotateBodyEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.isRotateBody);
end;

function SetRotateBodyEvent:run(connection)   
	self.vehicle:setRotateBody(self.isRotateBody, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(SetRotateBodyEvent:new(self.vehicle, self.isRotateBody), nil, connection, self.vehicle);
    end;
end;

function SetRotateBodyEvent.sendEvent(vehicle, isRotateBody, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetRotateBodyEvent:new(vehicle, isRotateBody), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetRotateBodyEvent:new(vehicle, isRotateBody));
		end;
	end;
end;

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