--
-- InteractiveControl v2.0
-- Specialization for an interactive control
--
-- SFM-Modding
-- @author:  	Manuel Leithner
-- @date:		17/10/10
-- @version:	v2.0
-- @history:	v1.0 - initial implementation
--				v2.0 - convert to LS2011 and some bugfixes
--
-- free for noncommerical-usage
--

InteractiveControl = {};

function InteractiveControl.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Steerable, specializations);
end;

function InteractiveControl:load(xmlFile)

	source(Utils.getFilename("specializations/InteractiveComponentInterface.lua", self.baseDirectory));

	self.doActionOnObject = SpecializationUtil.callSpecializationsFunction("doActionOnObject");
	self.setPanelOverlay = SpecializationUtil.callSpecializationsFunction("setPanelOverlay");
	
	self.infoBar = {};
	self.infoBar.posX = 0.4;
	self.infoBar.posY = 0.9359;
	
	self.infoBar.width = 0.3156;
	-- self.infoBar.hud = Overlay:new("icInfobar", Utils.getFilename("textures/Glas_diffuse.png", self.baseDirectory), self.infoBar.posX, self.infoBar.posY, self.infoBar.width, 0.0526);
	self.infoBar.hud = Overlay:new("icInfobar", Utils.getFilename("textures/interactiveControl_info.dds", self.baseDirectory), self.infoBar.posX, self.infoBar.posY, self.infoBar.width, 0.0526);
	
	self.interactiveObjects = {};	
	
	self.indoorCamIndex = 2;
	self.outdoorCamIndex = 1;
	
	self.lastMouseXPos = 0;
	self.lastMouseYPos = 0;					

	self.panelOverlay = nil;
	self.foundInteractiveObject = nil;
	self.isMouseActive = false;
end;

function InteractiveControl:delete()
	for _,v in pairs(self.interactiveObjects) do
		v:delete();
	end;
	if self.infoBar ~= nil then
		self.infoBar.hud:delete();
		self.infoBar = nil;
	end;
end;

function InteractiveControl:readStream(streamId, connection)
	local icCount = streamReadInt8(streamId);
	for i=1, icCount do
		local isOpen = streamReadBool(streamId);
		if self.interactiveObjects[i] ~= nil then
			if self.interactiveObjects[i].synch then
				self.interactiveObjects[i]:doAction(true, isOpen);	
			end;
		end;
	end;
end;

function InteractiveControl:writeStream(streamId, connection)
	streamWriteInt8(streamId, table.getn(self.interactiveObjects));
	for k,v in pairs(self.interactiveObjects) do
		streamWriteBool(streamId, v.isOpen);
	end;
end;

function InteractiveControl:mouseEvent(posX, posY, isDown, isUp, button)	

	self.lastMouseXPos = posX;
	self.lastMouseYPos = posY;

	if isDown then
		if Input.isMouseButtonPressed(Input.MOUSE_BUTTON_LEFT) and self.foundInteractiveObject ~= nil then			
			self:doActionOnObject(self.foundInteractiveObject);					
		end;
		local currentCam = self.cameras[self.camIndex];
		if currentCam.allowTranslation then
			if Input.isMouseButtonPressed(Input.MOUSE_BUTTON_WHEEL_UP) then
				currentCam:zoomSmoothly(-0.75);
			elseif Input.isMouseButtonPressed(Input.MOUSE_BUTTON_WHEEL_DOWN) then
				currentCam:zoomSmoothly(0.75);
			end;
		end;	
	end;
	
	for _,v in pairs(self.interactiveObjects) do
		v:mouseEvent(posX, posY, isDown, isUp, button);
	end;
	
	if self.isMouseActive then
		self.mouseButton = MouseControlsVehicle.BUTTON_NONE;
	end;
end;

function InteractiveControl:keyEvent(unicode, sym, modifier, isDown)
	for _,v in pairs(self.interactiveObjects) do
		v:keyEvent(unicode, sym, modifier, isDown);
	end;
end;

function InteractiveControl:update(dt)
	if self:getIsActive() then	
		self.foundInteractiveObject = nil;
		local icObject = nil;
		for k,v in pairs(self.interactiveObjects) do
			v:update(dt);
			if self.isMouseActive then
				v:onExit(dt);
				if icObject == nil and self.camIndex == self.indoorCamIndex then
					local worldX,worldY,worldZ = getWorldTranslation(v.mark);
					local x,y,z = project(worldX,worldY,worldZ);
					if z <= 1 then	
						if self.lastMouseXPos > (x-v.size/2) and self.lastMouseXPos < (x+v.size/2) then
							if self.lastMouseYPos > (y-v.size/2) and self.lastMouseYPos < (y+v.size/2) then
								local isOverlapped = false;
								
								if self.panelOverlay ~= nil then								
									local overlay = self.panelOverlay.mainBackground;
									isOverlapped = self.lastMouseXPos >= overlay.x and self.lastMouseXPos <= overlay.x+overlay.width and self.lastMouseYPos >= overlay.y and self.lastMouseYPos <= overlay.y+overlay.height;
								end;
								
								if not isOverlapped then
									icObject = v;
									self.foundInteractiveObject = k;
									break;
								end;
							end;
						end;
					end;
				end;				
			end;
		end;
		
		if icObject ~= nil then
			icObject:onEnter(dt);
		end;
		
		if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() then
			if InputBinding.hasEvent(InputBinding.INTERACTIVE_CONTROL_SWITCH) then
				self.isMouseActive = not self.isMouseActive;
				g_mouseControlsHelp.active = not self.isMouseActive;
				
				if not self.isMouseActive then
					InputBinding.setShowMouseCursor(false);
					self.cameras[self.camIndex].isActivated = true;
					for _,v in pairs(self.interactiveObjects) do
						v:onExit(dt);
					end;
				end;
				
				for _,v in pairs(self.interactiveObjects) do
					v:setVisible(self.isMouseActive);
				end;
			end;
			if self.isMouseActive then
				local currentCam = self.cameras[self.camIndex];
				
				self.mouseDirectionY = 0;
				self.mouseDirectionX = 0;
				
				if Input.isMouseButtonPressed(Input.MOUSE_BUTTON_RIGHT) then
					InputBinding.wrapMousePositionEnabled = true;		
					currentCam.rotX = currentCam.rotX + InputBinding.mouseMovementY;
					currentCam.rotY = currentCam.rotY - InputBinding.mouseMovementX;

					self.cameras[self.indoorCamIndex].isActivated = self.camIndex == self.indoorCamIndex;
					self.cameras[self.outdoorCamIndex].isActivated = self.camIndex == self.outdoorCamIndex;
					setShowMouseCursor(false);
				else
					self.cameras[self.indoorCamIndex].isActivated = self.camIndex ~= self.indoorCamIndex;
					self.cameras[self.outdoorCamIndex].isActivated = self.camIndex ~= self.outdoorCamIndex;
					InputBinding.setShowMouseCursor(true);
				end;
			else
				self.foundInteractiveObject = nil;
			end;
		else
			self.foundInteractiveObject = nil;
		end;
	end;	
end;

function InteractiveControl:updateTick(dt)
end;

function InteractiveControl:doActionOnObject(id, noEventSend)
	if self.interactiveObjects[id].isLocalOnly == nil or not self.interactiveObjects[id].isLocalOnly then
		InteractiveControlEvent.sendEvent(self, id, noEventSend);	
	end;
	self.interactiveObjects[id]:doAction(noEventSend);	
end;

function InteractiveControl:draw()	
	for _,v in pairs(self.interactiveObjects) do
		v:draw();
	end;
	if self.isMouseActive then
		g_currentMission:addHelpButtonText(g_i18n:getText("InteractiveControl_Off"), InputBinding.INTERACTIVE_CONTROL_SWITCH);
	else
		g_currentMission:addHelpButtonText(g_i18n:getText("InteractiveControl_On"), InputBinding.INTERACTIVE_CONTROL_SWITCH);
	end;
end;

function InteractiveControl:onLeave()
	self.cameras[self.indoorCamIndex].isActivated = true;
	g_mouseControlsHelp.active = true;
	if g_gui.currentGui == nil then
		InputBinding.setShowMouseCursor(false);
	end;
end;


function InteractiveControl:setPanelOverlay(panel)
	
	if self.panelOverlay ~= nil then
		if self.panelOverlay.setActive ~= nil then
			self.panelOverlay:setActive(false);
		end;
	end;
	self.panelOverlay = panel;

	if panel ~= nil then
		if panel.setActive ~= nil then
			panel:setActive(true);
		end;
	end;
end;



--
-- InteractiveControlEvent 
-- Specialization for an interactive control
--
-- SFM-Modding
-- @author:  	Manuel Leithner
-- @date:		14/12/11
-- @version:	v2.0
-- @history:	v1.0 - initial implementation
--				v2.0 - convert to LS2011 and some bugfixes
--
InteractiveControlEvent = {};
InteractiveControlEvent_mt = Class(InteractiveControlEvent, Event);

InitEventClass(InteractiveControlEvent, "InteractiveControlEvent");

function InteractiveControlEvent:emptyNew()
    local self = Event:new(InteractiveControlEvent_mt);
    return self;
end;

function InteractiveControlEvent:new(vehicle, interactiveControlID)
    local self = InteractiveControlEvent:emptyNew()
    self.vehicle = vehicle;
	self.interactiveControlID = interactiveControlID;
    return self;
end;

function InteractiveControlEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.interactiveControlID = streamReadInt8(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function InteractiveControlEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));	
	streamWriteInt8(streamId, self.interactiveControlID);
end;

function InteractiveControlEvent:run(connection)
	self.vehicle:doActionOnObject(self.interactiveControlID, true);
	if not connection:getIsServer() then
		g_server:broadcastEvent(InteractiveControlEvent:new(self.vehicle, self.interactiveControlID), nil, connection, self.vehicle);
	end;
end;

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