--
-- Lights - HardPoint
--
-- @author:    	Xentro (Marcus@Xentro.se)
-- @website:	www.Xentro.se
-- @history:	v1.0 - 2015-01-06 - Initial implementation
-- 				v1.1 - 2015-09-20 - Brake lights, Changed the need of dummy turn lights
-- 				v1.2 - 2015-09-28 - Real Lights, Reverse Lights
-- 

Lights = {};

function Lights:prerequisitesPresent(specializations)
	return true;
end;

function Lights:load(xmlFile)
	self.activateRealLights = Lights.activateRealLights;
	
	local mirrorNodes = Lights.loadXML(self, xmlFile, "mirrors", "mirror");
	if mirrorNodes ~= nil then
		self.mirrors = {};
		self.mirrors.nodes = mirrorNodes
		self.mirrors["LAST"] = -1;
	end;
	
	local turnRightNodes = Lights.loadXML(self, xmlFile, "turnSignal", "right");
	local turnLeftNodes = Lights.loadXML(self, xmlFile, "turnSignal", "left");
	if turnRightNodes ~= nil and turnLeftNodes ~= nil then
		self.turnSignal = {};
		self.turnSignal["right"] = {};
		self.turnSignal["right"].lastUpdate = false;
		self.turnSignal["right"].nodes = turnRightNodes;
		self.turnSignal["left"] = {};
		self.turnSignal["left"].lastUpdate = false;
		self.turnSignal["left"].nodes = turnLeftNodes;
	end;
	
	local lightNodes = Lights.loadXML(self, xmlFile, "lights", "light");
	if lightNodes ~= nil then
		self.light = {};
		self.light.lastRealLightUpdate = true;
		self.light.lastUpdate = -1;
		self.light.maxNumLights = getXMLInt(xmlFile, "vehicle.Lights.lights#maxRealLights"); -- if you want to override the default num max lights for HP lights
		self.light.nodes = lightNodes;
	end;
	
	local brakeNodes = Lights.loadXML(self, xmlFile, "brakeLights", "brakeLight");
	if brakeNodes ~= nil then
		self.brakeLights = {};
		self.brakeLights.lastUpdate = true;
		self.brakeLights.nodes = brakeNodes;
	end;
	
	local reverseNodes = Lights.loadXML(self, xmlFile, "reverseLights", "reverseLight");
	if reverseNodes ~= nil then
		self.reverseLights = {};
		self.reverseLights.lastUpdate = true;
		self.reverseLights.nodes = reverseNodes;
	end;
	
	local beaconNodes = Lights.loadXML(self, xmlFile, "beacons", "beacon");
	if beaconNodes ~= nil then
		self.beacons = beaconNodes;
	end;
end;

function Lights.loadXML(self, xmlFile, tag, tag2)
	local entry;
	i = 0;
	while true do
		local key = string.format("vehicle.Lights." .. tag .. "." .. tag2 .. "(%d)", i);
		if not hasXMLProperty(xmlFile, key) then break; end;
		
		local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#node"));
		if node ~= nil then
			if entry == nil then
				entry = {};
			end;
			
			setVisibility(node, false); -- deactivate light if active
			
			if tag2 == "light" then
				--[[
				0  front
				1  back work
				2  front work
				3  headlight
				]]--
				local lightType = Utils.getNoNil(getXMLInt(xmlFile, key .. "#lightType"), 0);
				
				if lightType <= self.vehicle.numLightTypes then
					local realLight = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#realLight"));
					local fakeLight = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#fakeLight")); -- light cones
					local useFakeLightIfNotReal = Utils.getNoNil(getXMLBool(xmlFile, key .. "#useFakeLightIfNotReal"), realLight == nil or self.vehicle.useFakeLightsIfNotReal);
					
					if realLight ~= nil then
						setVisibility(realLight, false);
					end;
					if fakeLight ~= nil then
						setVisibility(fakeLight, false);
					end;
					
					table.insert(entry, {realLight = realLight, fakeLight = fakeLight, decoration = node, lightType = lightType, useFakeLightIfNotReal = useFakeLightIfNotReal});
				else
					print("HP_Light: lightType ( " .. lightType .. ") haven't been defined by the machine yet.");
					-- we could improve this part in the future if its needed but as it stands now I dont see the point to do so.
				end;
				
			elseif tag2 == "beacon" then
				local rotatorNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#rotator"));
				local speed = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#speed"), 0.015);
				
				if rotatorNode ~= nil then
					table.insert(entry, {node = node, rotator = rotatorNode, speed = speed, active = false});
				end;
			else
				table.insert(entry, node);
			end;
		end;
		
		i = i + 1;
	end;
	
	return entry;
end;

function Lights:delete()
end;

function Lights:readStream(streamId, connection)
end;

function Lights:writeStream(streamId, connection)
end;

function Lights:update(dt)
	local v = self.vehicle;
	
	-- brakes are fast toggle so we need faster updates of them
	if self.brakeLights ~= nil then
		if self.brakeLights.lastUpdate ~= v.brakeLightsVisibility then
			for _, node in ipairs(self.brakeLights.nodes) do
				setVisibility(node, v.brakeLightsVisibility);
			end;
			
			self.brakeLights.lastUpdate = v.brakeLightsVisibility;
		end;
	end;
	
	if self.reverseLights ~= nil then
		if self.reverseLights.lastUpdate ~= v.reverseLightsVisibility then
			for _, node in ipairs(self.reverseLights.nodes) do
				setVisibility(node, v.reverseLightsVisibility);
			end;
			
			self.reverseLights.lastUpdate = v.reverseLightsVisibility;
		end;
	end;
end;

function Lights:updateTick(dt)
	local v = self.vehicle;
	
	if self.isClient then
		if self.mirrors ~= nil then
			if v.camIndex ~= self.mirrors["LAST"] then
				local cam = v.cameras[v.camIndex];
				
				if cam ~= nil then
					for _, node in ipairs(self.mirrors.nodes) do
						setVisibility(node, cam.useMirror and v.isEntered);
					end;
				end;
				
				self.mirrors["LAST"] = v.camIndex;
			else
				if v.forceLightsMirrorChange then
					self.mirrors["LAST"] = -1;
					v.forceLightsMirrorChange = false;
				end;
			end;
		end;
	end;
	
	if self.light ~= nil then
		self.lightsTypesMask = v.lightsTypesMask; -- for activation of realLights
		
		if v.lightsTypesMask ~= self.light.lastUpdate then
			for _, l in ipairs(self.light.nodes) do
				local lightActive = bitAND(v.lightsTypesMask, 2^l.lightType) ~= 0;
				
				if l.decoration ~= nil then
					setVisibility(l.decoration, lightActive);
				end;
				
				if l.fakeLight ~= nil then
					setVisibility(l.fakeLight, lightActive and not v.realLightsActive);
				end;
				
				if l.realLight ~= nil then
					setVisibility(l.realLight, false);
				end;
            end;
			
			if v.realLightsActive then
				self:activateRealLights();
			end;
			
			self.light.lastUpdate = v.lightsTypesMask;
		end;
		
		if v.lightsTypesMask > 0 then
			local realLightsActive = v:getIsActiveForLights();
			
			if self.light.lastRealLightUpdate ~= realLightsActive then
				self.light.lastRealLightUpdate = realLightsActive;
				
				for _, l in ipairs(self.light.nodes) do
					if realLightsActive then
						if l.fakeLight ~= nil then 
							setVisibility(l.fakeLight, false);
						end;
						
						-- activate realLights
						self:activateRealLights();
					else
						if l.realLight ~= nil then 
							setVisibility(l.realLight, false);
						end;

                        if l.fakeLight ~= nil and bitAND(v.lightsTypesMask, 2^l.lightType) ~= 0 then
                            setVisibility(l.fakeLight, true);
                        end;
					end;
				end;
			end;
		end;
	end;
	
	if self.turnSignal ~= nil then
		for i, k in pairs(self.turnSignal) do
			local state = v.turnSignalState;
			local activate = false;
			
			if i == "left" and state == 1 then
				activate = true;
			elseif i == "right" and state == 2 then
				activate = true;
			elseif state == 3 then -- hazard
				activate = true;
			end;
			
			if k.lastUpdate ~= activate then
				for _, node in ipairs(k.nodes) do
					setVisibility(node, activate);
				end;
				
				k.lastUpdate = activate;
			end;
		end;
	end;
	
	if self.beacons ~= nil then		
		for _, b in ipairs(self.beacons) do
			if b.active ~= v.beaconLightsActive then
				setVisibility(b.node, v.beaconLightsActive);
				b.active = v.beaconLightsActive;
			end;
			
			if v.beaconLightsActive then
				rotate(b.node, 0, b.speed * dt, 0);
				rotate(b.rotator, 0, b.speed * dt, 0);
			end;
		end;
	end;
end;

function Lights:draw()
end;

function Lights:activateRealLights()
    if self.vehicle.lightsTypesMask > 0 then
        local highestLightsType = bitHighestSet(self.vehicle.lightsTypesMask);
        local maxLights = Utils.getNoNil(self.light.maxNumLights, self.vehicle.maxNumRealLights);
        local numActiveRealLights = 0;
        local numLights1 = table.getn(self.vehicle.lights);
        local numLights2 = table.getn(self.light.nodes);
		
        for lightType = highestLightsType, 0, -1 do
            if bitAND(self.vehicle.lightsTypesMask, 2^lightType) ~= 0 then
                for i = numLights1, 1, -1 do
                    local light = self.vehicle.lights[i];
					
					if light.lightType == lightType and light.realLight ~= nil then
						if getVisibility(light.realLight) then
							numActiveRealLights = numActiveRealLights + 1;
						end;
					end;
				end;
				
                for i = numLights2, 1, -1 do
                    local light = self.light.nodes[i];
					if light.lightType == lightType then
						if numActiveRealLights < maxLights and light.realLight ~= nil then
                            setVisibility(light.realLight, true);
                            numActiveRealLights = numActiveRealLights + 1;
                        elseif light.fakeLight ~= nil and light.useFakeLightIfNotReal then
                            setVisibility(light.fakeLight, true);
                        end;
                    end;
                end;
            end;
        end;
    end;
end;