--
-- controlI3DAnim  v1.21 
-- Specialization to control I3D animations
-- Spezialisierung um I3D Animationen zu steuern
-- @author  Sven777b
-- 
-- frei verwendbar - keine erlaubnis nötig  |  free for use - no permission needed.
-- Modifikationen erst nach Rücksprache!    |  modifications only with my permission.
--
-- Hinweis: das kopieren von Sourcecode ist strafbar nach UrhG §2.1

controlI3DAnim = {};

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

function controlI3DAnim:load(xmlFile)
	self.setI3DAnimState = SpecializationUtil.callSpecializationsFunction("setI3DAnimState");
	local i=0;
	self.i3danims = {};
	self.hasOutsideControls = false;
	while true do
		local basename = string.format("vehicle.i3dAnims.anim(%d)#",i);
		local rnindex = getXMLString(xmlFile,basename.."rootnode");
		if rnindex == nil then break; end;
		local anim = {};
		anim.rootNode = Utils.indexToObject(self.components, rnindex);
		if anim.rootNode ~= nil and anim.rootNode ~= 0 then
			anim.charSet = getAnimCharacterSet(anim.rootNode);
			if anim.charSet ~= 0 then
				local clipname = getXMLString(xmlFile,basename.."clipname");
				local clip = getAnimClipIndex(anim.charSet, clipname);
				if clip ~= nil then
					assignAnimTrackClip(anim.charSet, 0, clip);
					anim.loop = Utils.getNoNil(getXMLBool(xmlFile,basename.."loop"),false);
					setAnimTrackLoopState(anim.charSet, 0, anim.loop);
					anim.duration = getAnimClipDuration(anim.charSet, clip);
					anim.speed = Utils.getNoNil(getXMLFloat(xmlFile,basename.."speed"),1.0);
					if anim.speed < 0 then
						enableAnimTrack(anim.charSet, 0);
						setAnimTrackTime(anim.charSet, 0,anim.duration);
						disableAnimTrack(anim.charSet,0);
					end;
					setAnimTrackSpeedScale(anim.charSet, 0, anim.speed);
					if not anim.loop then
						anim.speed = anim.speed * -1;
					end;
					anim.inputBinding = getXMLString(xmlFile,basename.."inputBinding");
					if anim.inputBinding ~= nil then
						if InputBinding[anim.inputBinding] == nil then
							anim.inputBinding = nil;
						end;
					end;
					anim.helpText = getXMLString(xmlFile,basename.."helpText");
					anim.helpTextOn = getXMLString(xmlFile,basename.."helpTextOn");
					anim.helpTextOff = getXMLString(xmlFile,basename.."helpTextOff");
					local sound = getXMLString(xmlFile,basename.."sound");
					if sound ~= nil then
						local soundFile = Utils.getFilename(sound, self.baseDirectory);
						anim.sound = createSample("soundFile");
						loadSample(anim.sound, soundFile, false);
					end;
					anim.outside = Utils.getNoNil(getXMLBool(xmlFile, basename.."outside"),false);
					if anim.outside then
						self.hasOutsideControls = true;
						anim.maxDist = Utils.getNoNil(getXMLFloat(xmlFile, basename.."maxDist"),3.0);
						anim.distNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(xmlFile, basename.."distNode"),"0>"));
						anim.pir = false;
					end;
					anim.inside = Utils.getNoNil(getXMLBool(xmlFile, basename.."inside"),true);
					if not (anim.inside or anim.outside) then
						anim.inside = true;
					end;
					anim.running = false;
					anim.state = false;
					table.insert(self.i3danims,anim);
				else
					print("Error: controlI3DAnims - ("..clipname..") clip not found");
				end;
			else
				print("Error: controlI3DAnims - ("..clipname..") charSet not found");
			end;
		else
			print("Error: controlI3DAnims - ("..clipname..") rootNode not found");
		end;
		i=i+1;
	end;
	self.runI3Danims = table.getn(self.i3danims) > 0;
	self.outsideMaxDist = 3.0;
	self.ci3daPlayerInRange = false;
	self.animsRunning = false;
end;

function controlI3DAnim:readStream(streamId, timestamp, connection)
	if self.runI3Danims then
		for i=1,table.getn(self.i3danims) do
			local anim=self.i3danims[i];
			local state = streamReadBool(streamId);
			local running = streamReadBool(streamId);
			if state ~= anim.state or running ~= anim.running then
				self:setI3DAnimState(i,state,true);
			end;
		end;
	end;
end;

function controlI3DAnim:writeStream(streamId, connection, dirtyMask)
	if self.runI3Danims then
		for i=1,table.getn(self.i3danims) do
			local anim=self.i3danims[i];
			streamWriteBool(streamId, anim.state);
			streamWriteBool(streamId, anim.running);
		end;
	end;
end;

function controlI3DAnim:update(dt)
	if self.runI3Danims then
		if self:getIsActiveForInput() or (self.ci3daPlayerInRange and self.hasOutsideControls) then
			for i=1,table.getn(self.i3danims) do
				local anim=self.i3danims[i];
				if anim.inputBinding ~= nil then
					if (anim.inside and self:getIsActiveForInput() ) or (anim.outside and anim.pir and not self:getIsActiveForInput() ) then
						if InputBinding.hasEvent(InputBinding[anim.inputBinding]) then
							self:setI3DAnimState(i,not anim.state,false);
						end;
					end;
					
					if not self:getIsActive() and anim.pir and anim.outside then
						if anim.helpText ~= nil then
							g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpText), InputBinding[anim.inputBinding]);
						elseif anim.helpTextOn ~= nil and not anim.state then
							g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpTextOn), InputBinding[anim.inputBinding]);
						elseif anim.helpTextOff ~= nil and anim.state then
							g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpTextOff), InputBinding[anim.inputBinding]);
						end;
					end;
					
				end;
			end;
		end;

	end;		
end;

function controlI3DAnim:updateTick(dt)
	if self.animsRunning then
		for i=1,table.getn(self.i3danims) do
			local anim=self.i3danims[i];
			if anim.running and not anim.loop then
				local tt = getAnimTrackTime(anim.charSet,0);
				if (anim.speed < 0 and tt < 0) or (anim.speed > 0 and tt > anim.duration) then
					anim.running = false;
					if anim.sound ~= nil then
						stopSample(anim.sound, 0, 1, 0);
					end;
					disableAnimTrack(anim.charSet,0);
				end;
			end;
		end;
	end;
	if self.hasOutsideControls and not self:getIsActive() and g_currentMission.player ~= nil then
		self.ci3daPlayerInRange = false;
		for i=1,table.getn(self.i3danims) do
			local anim = self.i3danims[i];
			if anim.outside then
				local x1,y1,z1 = getWorldTranslation(anim.distNode);
				local x2,y2,z2 = getWorldTranslation(g_currentMission.player.rootNode);
				local dist = Utils.vector2Length(x1-x2, z1-z2);
				anim.pir = false;
				if dist < anim.maxDist then
					self.ci3daPlayerInRange = true;
					anim.pir = true;
				end;
			end;
		end;
	end;
end;

function controlI3DAnim:draw()
	if self.runI3Danims then
		for i=1,table.getn(self.i3danims) do
			local anim=self.i3danims[i];
			if anim.inputBinding ~= nil and anim.inside then
				if anim.helpText ~= nil then
					g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpText), InputBinding[anim.inputBinding]);
				elseif anim.helpTextOn ~= nil and not anim.state then
					g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpTextOn), InputBinding[anim.inputBinding]);
				elseif anim.helpTextOff ~= nil and anim.state then
					g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpTextOff), InputBinding[anim.inputBinding]);
				end;
			end;
		end;
	end;
end;

function controlI3DAnim:setI3DAnimState(index,state,nes)
	local anim = self.i3danims[index];
	if state ~= anim.state then
		anim.state = state;
		if anim.sound ~= nil then
			playSample(anim.sound, 0, 1, 0);
		end;
		if anim.loop then
			if state then
				enableAnimTrack(anim.charSet,0);
				anim.running = true;
				self.animsRunning = true;
			else
				if anim.sound ~= nil then
					stopSample(anim.sound, 0, 1, 0);
				end;
				disableAnimTrack(anim.charSet,0);
				anim.running = false;
			end;
		else
			anim.speed = anim.speed * -1;
			if anim.running then
				disableAnimTrack(anim.charSet,0);
				if anim.sound ~= nil then
					stopSample(anim.sound, 0, 1, 0);
				end;
			end;
			setAnimTrackSpeedScale(anim.charSet,0,anim.speed);
			enableAnimTrack(anim.charSet,0);
			anim.running = true;
			self.animsRunning = true;
		end;
		setI3DAnimStateEvent.sendEvent(self,index,state,nes);
	end;
end;

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

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

function controlI3DAnim:delete()
end;

setI3DAnimStateEvent = {};
setI3DAnimStateEvent_mt = Class(setI3DAnimStateEvent, Event);
InitEventClass(setI3DAnimStateEvent, "setI3DAnimStateEvent");

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

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

function setI3DAnimStateEvent:readStream(streamId, connection)
		self.object = networkGetObject(streamReadInt32(streamId));
		self.id  = streamReadInt8(streamId);
		self.state = streamReadBool(streamId);
		self:run(connection);
end;

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

function setI3DAnimStateEvent:run(connection)
	self.object:setI3DAnimState(self.id,self.state, true);
  if not connection:getIsServer() then
      g_server:broadcastEvent(setI3DAnimStateEvent:new(self.object, self.id, self.state), nil, connection, self.object);
  end;	
end;

function setI3DAnimStateEvent.sendEvent(vehicle, id, state, nes)
	if nes == nil or nes == false then
		if g_server ~= nil then
			g_server:broadcastEvent(setI3DAnimStateEvent:new(vehicle, id, state), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(setI3DAnimStateEvent:new(vehicle, id, state));
		end;
	end;
end;
