--
-- TamLeguan
--
-- SFM-Modding
-- @author  Manuel Leithner
-- @date:		27/08/11
-- @version:	v1.0
-- @history:	v1.0 - initial implementation
--


TamLeguan = {};

function TamLeguan.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Cylindered, specializations);
end;

function TamLeguan:load(xmlFile)

	self.attachCutter = SpecializationUtil.callSpecializationsFunction("attachCutter");
	self.detachCutter = SpecializationUtil.callSpecializationsFunction("detachCutter");

	self.cutterCallback = TamLeguan.cutterCallback;

	self.updateOffset = 200;
	
	self.cutterTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.cutterTrigger#index"));
	addTrigger(self.cutterTrigger, "cutterCallback", self);
	
	self.cutterInRange = nil;
	self.attachedCutter = nil;
	self.onPostSync = false;
end;

function TamLeguan:delete()
	removeTrigger(self.cutterTrigger);
end;

function TamLeguan:readStream(streamId, connection)
	self.onPostSync = streamReadBool(streamId);
end;

function TamLeguan:writeStream(streamId, connection)
	streamWriteBool(streamId, self.attachedCutter ~= nil);
end;

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

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

function TamLeguan:update(dt)

	if self.onPostSync then
		self.attachedCutter = self.attachedImplements[1].object;
		self.cutterInRange = self.attachedCutter;
		self.attachedCutter.allowsDetaching = false;
		self.onPostSync = false;
	end;

	if self:getIsActive() then	
		if self:getIsActiveForInput() then
			if InputBinding.hasEvent(InputBinding.ATTACH_CUTTER) then
				if self.attachedCutter == nil then
					if self.cutterInRange ~= nil then
						if self.cutterInRange.attacherVehicle == nil then						
							self:attachCutter(self.cutterInRange);
						end;
					end;
				else
					self:detachCutter(self.attachedCutter);
				end;			
			end;
		end;	
	
		self.updateOffset = 200;
		
		if self.isServer then
			local jointNode = self.componentJoints[2].jointNode;
			local jointIndex = self.componentJoints[2].jointIndex;
			local x,_,z = worldDirectionToLocal(self.components[1].node, localDirectionToWorld(self.components[2].node, 0, 0, 1));
			local dot = z / Utils.vector2Length(x,z);
			local angle = math.acos(dot);
			if x > 0 then
				angle = -angle;
			end;
			setRotation(jointNode, 0, angle , 0);
			setJointFrame(jointIndex, 0, jointNode);
		end;
	end;
	
	if self.updateOffset > 0 then
		Cylindered.updateMovingPart(self, self.movingParts[1]);
		Cylindered.updateMovingPart(self, self.movingParts[2]);
		self.updateOffset = self.updateOffset - 1;
	end;
end;

function TamLeguan:updateTick(dt)

	if not self:getIsActive() then	
		local jointNode = self.componentJoints[2].jointNode;
		local jointIndex = self.componentJoints[2].jointIndex;
		local x,_,z = worldDirectionToLocal(self.components[1].node, localDirectionToWorld(self.components[2].node, 0, 0, 1));
		local dot = z / Utils.vector2Length(x,z);
		local angle = math.acos(dot);
		if x > 0 then
			angle = -angle;
		end;
		setRotation(jointNode, 0, angle , 0);
		setJointFrame(jointIndex, 0, jointNode);
		Cylindered.updateMovingPart(self, self.movingParts[1]);
		Cylindered.updateMovingPart(self, self.movingParts[2]);
	end;
end;

function TamLeguan:draw()
	if self.attachedCutter == nil then
		if self.cutterInRange ~= nil then
			if self.cutterInRange.attacherVehicle == nil then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("ATTACH_CUTTER"), self.typeDesc), InputBinding.ATTACH_CUTTER);
			end;
		end;
	else
		g_currentMission:addHelpButtonText(string.format(g_i18n:getText("DETACH_CUTTER"), self.typeDesc), InputBinding.ATTACH_CUTTER);
	end;
end;

function TamLeguan:attachCutter(cutter, noEventSend)
	CutterTrailerEvent.sendEvent(self, cutter, true, noEventSend);
	
	-- adjust joint position
	local joint = self.attacherJoints[1].jointTransform;
	local cutterJoint = cutter.attacherJoint.node;
	local x,y,z = getWorldTranslation(cutterJoint);
	x,y,z = worldToLocal(getParent(joint), x,y,z);
	setTranslation(joint, x,y,z);							
	-- adjust joint rotation
	local xUp,yUp,zUp = localDirectionToWorld(cutterJoint, 0,1,0);
	local dx,dy,dz = localDirectionToWorld(cutterJoint, 0,0,1);
	Utils.setWorldDirection(joint, dx, dy, dz, xUp, yUp, zUp);
	cutter.allowsDetaching = false;
	-- attach cutter
	self:attachImplement(cutter, 1, true);
	self.selectedImplement = 0;
	self.attachedCutter = cutter;
	self.attachedCutter.isSelected = false;
end;


function TamLeguan:detachCutter(cutter, noEventSend)
	CutterTrailerEvent.sendEvent(self, cutter, false, noEventSend);
	
	self.attachedCutter.allowsDetaching = true;
	self:detachImplement(1, true);
	self.attachedCutter = nil;
	-- reset jointTransform to a non attachable position
	setTranslation(self.attacherJoints[1].jointTransform, 0,0,5);
end;

function TamLeguan:onDetach()
	if self.attachedCutter ~= nil then
		self:detachCutter(self.attachedCutter, true);
	end;
end;


function TamLeguan:cutterCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)

	if onEnter then		
		local object = g_currentMission.nodeToVehicle[otherShapeId];
		if object ~= nil then
			if SpecializationUtil.hasSpecialization(Cutter, object.specializations) then
				if self.cutterInRange == nil then
					self.cutterInRange = object;
				end;
			end;
		end;
	elseif onLeave then
		local object = g_currentMission.nodeToVehicle[otherShapeId];
		if object == self.cutterInRange then
			self.cutterInRange = nil;
		end;
	end;
end;


local oldFoldableDraw = Foldable.draw;
Foldable.draw = function(self)
	if table.getn(self.foldingParts) > 0 then
        if self.foldMoveDirection > 0.1 or (self.foldMoveDirection == 0 and self.foldAnimTime > 0.5) then
            g_currentMission:addHelpButtonText(string.format(g_i18n:getText(self.negDirectionText), self.typeDesc), self.foldInputButton);
        else
            g_currentMission:addHelpButtonText(string.format(g_i18n:getText(self.posDirectionText), self.typeDesc), self.foldInputButton);
        end;
    end;
end;




--
-- CutterTrailerEvent
--
-- SFM-Modding
-- @author  Manuel Leithner
-- @date:		14/12/11
-- @version:	v1.0
-- @history:	v1.0 - initial implementation
--
CutterTrailerEvent = {};
CutterTrailerEvent_mt = Class(CutterTrailerEvent, Event);

InitEventClass(CutterTrailerEvent, "CutterTrailerEvent");

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

function CutterTrailerEvent:new(vehicle, cutter, doAttach)
    local self = CutterTrailerEvent:emptyNew()
    self.vehicle = vehicle;
	self.cutter = cutter;
	self.doAttach = doAttach;
    return self;
end;

function CutterTrailerEvent:readStream(streamId, connection)
	self.vehicle = networkGetObject(streamReadInt32(streamId));
	self.cutter = networkGetObject(streamReadInt32(streamId));
	self.doAttach = streamReadBool(streamId);
    self:run(connection);
end;

function CutterTrailerEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));	
	streamWriteInt32(streamId, networkGetObjectId(self.cutter));
	streamWriteBool(streamId, self.doAttach);
end;

function CutterTrailerEvent:run(connection)
	if self.doAttach then
		self.vehicle:attachCutter(self.cutter, true);
	else
		self.vehicle:detachCutter(self.cutter, true);
	end;
	if not connection:getIsServer() then
		g_server:broadcastEvent(CutterTrailerEvent:new(self.vehicle, self.cutter, self.doAttach), nil, connection, self.vehicle);
	end;
end;

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