--author: igor29381 (Manuscript GT)
--v1.0
--date: 16.01.17

LockingParts = {};

function LockingParts.prerequisitesPresent(specializations)
	return true;
end;

function LockingParts:load(savegame)
	self.lockingParts = {};
	if hasXMLProperty(self.xmlFile, "vehicle.lockComponentJoints") then
		self.setLockComponentJoints = LockingParts.setLockComponentJoints;
		self.getIsLockActivatable = LockingParts.getIsLockActivatable;
		self.lockingParts.foldTimeForLockJoints = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.lockComponentJoints#foldTimeForLock"), 0);
		self.lockingParts.lockComponentJoints = {};
		self.lockingParts.lockComponentJoints[true] = {};
		self.lockingParts.lockComponentJoints[false] = {};
		self.lockingParts.hasManualLock = false;
		self.lockingParts.hasExternalControl = false;
		local c = 0;
		while true do
			local baseString = string.format("vehicle.lockComponentJoints.joint(%d)",c);
			local index = getXMLInt(self.xmlFile, baseString.."#index");
			if index == nil then break; end;
			if index > 0 and self.componentJoints[index] then
				local manualLock = Utils.getNoNil(getXMLBool(self.xmlFile, baseString.."#manualLock"), false);
				if manualLock then
					self.lockingParts.hasManualLock = true;
				end;
				local externalControl = Utils.getNoNil(getXMLBool(self.xmlFile, baseString.."#externalControl"), false);
				if externalControl then
					self.lockingParts.hasExternalControl = true;
				end;
				local jointDesc = self.componentJoints[index];
				table.insert(self.lockingParts.lockComponentJoints[manualLock],
				{index = index,
				rotLimit = jointDesc.rotLimit,
				rotMinLimit = jointDesc.rotMinLimit,
				externalControl = externalControl,
				lockOnZeroAngle = Utils.getNoNil(getXMLBool(self.xmlFile, baseString.."#lockOnZeroAngle"), false)});
			end;
			c = c + 1;
		end;
		if self.lockingParts.hasManualLock then
			self.lockingParts.manualLockActive = false;
			self.lockingParts.manualLockText = {};
			local lockText = Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.lockComponentJoints#lockText"), "lockSupport");
			local unlockText = Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.lockComponentJoints#unlockText"), "unlockSupport");
			self.lockingParts.manualLockText[true] = g_i18n:getText(unlockText);
			self.lockingParts.manualLockText[false] = g_i18n:getText(lockText);
			local lockInputButtonStr = getXMLString(self.xmlFile, "vehicle.lockComponentJoints#lockInputButton");
			if lockInputButtonStr then
				self.lockingParts.lockInputButton = InputBinding[lockInputButtonStr];
			end
			self.lockingParts.lockInputButton = Utils.getNoNil(self.lockingParts.lockInputButton, InputBinding.IMPLEMENT_EXTRA3);
		end;
	end;
	if hasXMLProperty(self.xmlFile, "vehicle.lockMovingTools") then
		if self.movingTools then
			self.setMovingToolsFreezedStates = LockingParts.setMovingToolsFreezedStates;
			self.lockingParts.foldTimeForLockMovingTools = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.lockMovingTools#foldTimeForLock"), 0);
			self.lockingParts.lockingMovingTools = {};
			local useAllMovingTools = true;
			local c = 0;
			while true do
				local baseString = string.format("vehicle.lockMovingTools.tool(%d)",c);
				local index = getXMLInt(self.xmlFile, baseString.."#index");
				if index == nil then break; end;
				useAllMovingTools = false;
				if self.movingTools[index] then
					self.lockingParts.lockingMovingTools[index] = true;
				end;
				c = c + 1;
			end;
			if useAllMovingTools then
				for i=1, #self.movingTools do
					self.lockingParts.lockingMovingTools[i] = true;
				end;
			end;
			self.lockingParts.movingToolsIsFreezed = false;
			self.lockingParts.enableLockMovingTools = true;
		else
			print("Warning: "..self.configFileName.." has no movingTools! Can't lock movingTools.");
		end;
	else
		self.lockingParts.enableLockMovingTools = false;
	end;
	if SpecializationUtil.hasSpecialization(Foldable, self.specializations) then
		self.getIsFoldAllowed = LockingParts.getIsFoldAllowed;
		self.lockingParts.lastFoldAnimTime = 0.1;
	end;
	if SpecializationUtil.hasSpecialization(Trailer, self.specializations) then
		self.getCanTip = LockingParts.getCanTip;
	end;
end;

function LockingParts:postLoad(savegame)
	if self.foldAnimTime then
		if g_server and self.lockingParts.foldTimeForLockJoints and self.foldAnimTime <= self.lockingParts.foldTimeForLockJoints then
			self:setLockComponentJoints(true, false);
		end;
		if self.movingTools and self.lockingParts.enableLockMovingTools and self.foldAnimTime <= self.lockingParts.foldTimeForLockMovingTools then
			self:setMovingToolsFreezedStates(true);
		end;
	end;
end;

function LockingParts:delete()
end;

function LockingParts:readStream(streamId, connection)
end;

function LockingParts:writeStream(streamId, connection)
end;

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

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

function LockingParts:update(dt)
	if self.lockingParts.enableLockMovingTools then
		local rootAttacherVehicle = self:getRootAttacherVehicle();
		if rootAttacherVehicle and rootAttacherVehicle.motor then
			if rootAttacherVehicle:getIsMotorStarted() then
				if self.foldAnimTime then
					if self.foldAnimTime >= self.lockingParts.foldTimeForLockMovingTools and self.lockingParts.movingToolsIsFreezed then
						self:setMovingToolsFreezedStates(false);
					elseif self.foldAnimTime < self.lockingParts.foldTimeForLockMovingTools and not self.lockingParts.movingToolsIsFreezed then
						self:setMovingToolsFreezedStates(true);
					end;
				elseif self.lockingParts.movingToolsIsFreezed then
					self:setMovingToolsFreezedStates(false);
				end;
			elseif not self.lockingParts.movingToolsIsFreezed then
				self:setMovingToolsFreezedStates(true);
			end;
		end;
	end;
	if self.lockingParts.lockComponentJoints then
		if g_server and self.foldAnimTime and self.foldAnimTime ~= self.lockingParts.lastFoldAnimTime then
			if self.foldAnimTime == 0 and self.lockingParts.lastFoldAnimTime > 0 then
				self:setLockComponentJoints(true, false);
			elseif self.foldAnimTime > 0 and self.lockingParts.lastFoldAnimTime == 0 then
				self:setLockComponentJoints(false, false);
			end;
			self.lockingParts.lastFoldAnimTime = self.foldAnimTime;
		end;
		if self.lockingParts.hasManualLock then
			local drawLock = false;
			local lockWarning = false;
			if self.lockingParts.hasExternalControl and #self.lockingParts.lockComponentJoints[true] > 0 and g_currentMission.player.isEntered then
				local x,_,z = getWorldTranslation(g_currentMission.player.rootNode);
				for i=1, #self.lockingParts.lockComponentJoints[true] do
					local lockInfo = self.lockingParts.lockComponentJoints[true][i];
					if lockInfo.externalControl then
						local jointDesc = self.componentJoints[lockInfo.index];
						local jx, _, jz = getWorldTranslation(jointDesc.jointNode);
						if Utils.vector2Length(jx-x, jz-z) < 3 then
							drawLock = true;
							if lockInfo.lockOnZeroAngle then
								if not self:getIsLockActivatable(jointDesc.componentIndices[1], jointDesc.componentIndices[2]) then
									lockWarning = true;
									break;
								end;
							end;
							break;
						end;
					end;
				end;
			end;
			if self:getIsActive() and self:getIsActiveForInput() then
				for i=1, #self.lockingParts.lockComponentJoints[true] do
					local lockInfo = self.lockingParts.lockComponentJoints[true][i];
					if lockInfo.lockOnZeroAngle then
						local jointDesc = self.componentJoints[lockInfo.index];
						if not self:getIsLockActivatable(jointDesc.componentIndices[1], jointDesc.componentIndices[2]) then
							lockWarning = true;
							break;
						end;
					end;
				end;
				drawLock = true;
			end;
			if drawLock then
				g_currentMission:addHelpButtonText(self.lockingParts.manualLockText[self.lockingParts.manualLockActive], self.lockingParts.lockInputButton, nil, GS_PRIO_HIGH);
				if InputBinding.hasEvent(self.lockingParts.lockInputButton) then
					if lockWarning then
						g_currentMission:showBlinkingWarning(g_i18n:getText("alignForLock"), 3000);
					else
						if g_server then
							self:setLockComponentJoints(not self.lockingParts.manualLockActive, true);
						else
							g_client:getServerConnection():sendEvent(LockingPartsEvent:new(not self.lockingParts.manualLockActive, self));
						end;
					end;
				end;
			end;
		end;
	end;
end;

function LockingParts:draw()
end;

function LockingParts:updateTick(dt)
end;

function LockingParts:setLockComponentJoints(state, manual)
	manual = Utils.getNoNil(manual, false);
	for i=1, #self.lockingParts.lockComponentJoints[manual] do
		local lockInfo = self.lockingParts.lockComponentJoints[manual][i];
		local jointDesc = self.componentJoints[lockInfo.index];
		if state then
			for ii=1, 3 do
				setJointRotationLimit(jointDesc.jointIndex, ii-1, true, 0, 0);
			end;
		else
			for ii=1, 3 do
				setJointRotationLimit(jointDesc.jointIndex, ii-1, true, lockInfo.rotLimit[ii], lockInfo.rotMinLimit[ii]);
			end;
		end;
	end;
	if manual then
		self.lockingParts.manualLockActive = state;
		g_server:broadcastEvent(LockingPartsEvent:new(state, self));
	end;
end;

function LockingParts:setMovingToolsFreezedStates(state)
	for i=1, #self.movingTools do
		if self.lockingParts.lockingMovingTools[i] then
			self.movingTools[i].isFreezed = state;
		end;
	end;
	self.lockingParts.movingToolsIsFreezed = state;
end;

function LockingParts:getIsLockActivatable(int1, int2)
	local _,rot,_ = localRotationToLocal(self.components[int2].node, self.components[int1].node, 0,0,0);
	if rot and math.abs(rot) > 0.05 then
		return false;
	end;
	return true;
end;

function LockingParts:getIsFoldAllowed(superFunc, onAiTurnOn)
	local rootAttacherVehicle = self:getRootAttacherVehicle();
	if rootAttacherVehicle and rootAttacherVehicle.motor and not rootAttacherVehicle:getIsMotorStarted() then
		return false;
	end;
	if self.onlyFoldOnDetach and self.attacherVehicle ~= nil then
        return false;
    end;
    if self.onlyFoldOnEmpty and self:getFillLevel() > 0 then
        return false;
    end;
    if superFunc ~= nil then
        return superFunc(self);
    end;
    return true;
end;

function LockingParts:getCanTip()
	local rootAttacherVehicle = self:getRootAttacherVehicle();
	return rootAttacherVehicle and rootAttacherVehicle.motor and rootAttacherVehicle:getIsMotorStarted();
end;

----------------------------------------------------------------------------------------------------------------

LockingPartsEvent = {};
LockingPartsEvent_mt = Class(LockingPartsEvent, Event);
InitEventClass(LockingPartsEvent, "LockingPartsEvent");

function LockingPartsEvent:emptyNew()
	local self = Event:new(LockingPartsEvent_mt);
    return self;
end;

function LockingPartsEvent:new(state, object)
	local self = LockingPartsEvent:emptyNew();
	self.state = state;
	self.object = object;
	return self;
end;

function LockingPartsEvent:readStream(streamId, connection)
	local state = streamReadBool(streamId);
    local object = networkGetObject(streamReadInt32(streamId));
	if g_server then
		object:setLockComponentJoints(state, true);
	else
		object.lockingParts.manualLockActive = state;
	end;
end;

function LockingPartsEvent:writeStream(streamId, connection)
	streamWriteBool(streamId, self.state);
	streamWriteInt32(streamId, networkGetObjectId(self.object));
end;
