InteractiveControls = {};

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

function InteractiveControls:load(xmlFile)
	self.toggleSupport = SpecializationUtil.callSpecializationsFunction("toggleSupport");
	self.puntepos = 2
	-- Punte
	self.punte = {};
	self.punte.interne = {};
	self.punte.interne.animation = getXMLString(xmlFile, "vehicle.punte#interneAnimation");
	if self.punte.interne.animation then 
		self.punte.rangeIndex = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.punte#RangeIndex"));
		self.punte.inRange = false;
		self.punte.interne.isOpen = true;
		self.punte.interne.dirtyFlag = self:getNextDirtyFlag();
	end;	
	self.punte.esterne = {};
	self.punte.esterne.animation = getXMLString(xmlFile, "vehicle.punte#esterneAnimation");
	if self.punte.esterne.animation then 
		self.punte.rangeIndex = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.punte#RangeIndex"));
		self.punte.inRange = false;
		self.punte.esterne.isOpen = true;
		self.punte.esterne.dirtyFlag = self:getNextDirtyFlag();
	end;	
	self.punte.centrali = {};
	self.punte.centrali.animation = getXMLString(xmlFile, "vehicle.punte#centraliAnimation");
	if self.punte.centrali.animation then 
		self.punte.rangeIndex = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.punte#RangeIndex"));
		self.punte.inRange = false;
		self.punte.centrali.isOpen = true;
		self.punte.centrali.dirtyFlag = self:getNextDirtyFlag();
	end;	
	-- Hydraulic hoses
	self.hydraulicHoses = {};
	self.hydraulicHoses.attached = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.hydraulicHoses#attached"));
	self.hydraulicHoses.detached = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.hydraulicHoses#detached"));
	self.helpico = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.hydraulicHoses#helpico"));	
	-- Support
	self.manualSupportAnimation = getXMLString(xmlFile, "vehicle.manualSupport#animationName");
	self.supportRangeIndex = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.manualSupport#RangeIndex"));
	self.isInRangeSupport = false;
	self.isSupport = false;
	self.OpenClose = getXMLString(xmlFile, "vehicle.manualSupport#punte");
	self.setOpenClose = false;	
	self.loadingIsActive = SpecializationUtil.callSpecializationsFunction("loadingIsActive");
	self.balesAttached = SpecializationUtil.callSpecializationsFunction("balesAttached");
	self.Piloni = getXMLString(xmlFile, "vehicle.Piloni#animationName");
	self.PiloniSet = SpecializationUtil.callSpecializationsFunction("PiloniSet");
	self.Collisione = getXMLString(xmlFile, "vehicle.Collisione#animationName");
	self.CollisioneSet = true;
	setRotate = true;
	self.CameraPosX = 0.68;
	self.CameraWidth = 0.1;
	self.CameraPosY = 0.24;
	self.CameraHeight = 0.1;
	self.OpenFrame = Utils.getFilename("Huds/Open.dds", self.baseDirectory);
	self.OpenFrameOverlay = Overlay:new("OpenFrameOverlay", self.OpenFrame, self.CameraPosX, self.CameraPosY, self.CameraWidth, self.CameraHeight);
	self.CloseFrame = Utils.getFilename("Huds/Close.dds", self.baseDirectory);
	self.CloseFrameOverlay = Overlay:new("CloseFrameOverlay", self.CloseFrame, self.CameraPosX, self.CameraPosY, self.CameraWidth, self.CameraHeight);
	self.roundFrame = Utils.getFilename("Huds/round.dds", self.baseDirectory);
	self.roundFrameOverlay = Overlay:new("roundFrameOverlay", self.roundFrame, self.CameraPosX, self.CameraPosY, self.CameraWidth, self.CameraHeight);
	self.normalFrame = Utils.getFilename("Huds/normal.dds", self.baseDirectory);
	self.normalFrameOverlay = Overlay:new("normalFrameOverlay", self.normalFrame, self.CameraPosX, self.CameraPosY, self.CameraWidth, self.CameraHeight);
	self.bigFrame = Utils.getFilename("Huds/big.dds", self.baseDirectory);
	self.bigFrameOverlay = Overlay:new("bigFrameOverlay", self.bigFrame, self.CameraPosX, self.CameraPosY, self.CameraWidth, self.CameraHeight);
	self.setGripperCameraState = SpecializationUtil.callSpecializationsFunction("setGripperCameraState");
	self.numCameras = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.cameras#count"), 0);
    self.cameras = {};
	self.setCamera = false;
	for i=1, self.numCameras do
		local cameranamei = string.format("vehicle.cameras.camera%d", i);
		local camera = VehicleCamera:new(self);
		if camera:loadFromXML(xmlFile, cameranamei) then
			table.insert(self.cameras, camera);
		end;
	end;
	self.cameraInsertNum = nil;
	self.gripperCameraActive = false;
	self:setGripperCameraState(self.gripperCameraActive);
end;

function InteractiveControls:delete()
end;

function InteractiveControls:readStream(streamId, connection)
	local isSupport = streamReadBool(streamId);
	self:toggleSupport(isSupport, true);
	self.punte.interne.isOpen = streamReadBool(streamId);
	self.punte.esterne.isOpen = streamReadBool(streamId);
	self.punte.centrali.isOpen = streamReadBool(streamId);
	if self.punte.interne.animation ~= nil and self.playAnimation ~= nil then
		if self.punte.interne.isOpen then
			self:playAnimation(self.punte.interne.animation, 1, nil, true);
		end;
	end;
	if self.punte.esterne.animation ~= nil and self.playAnimation ~= nil then
		if self.punte.esterne.isOpen then
			self:playAnimation(self.punte.esterne.animation, 1, nil, true);
		end;
	end;
	if self.punte.centrali.animation ~= nil and self.playAnimation ~= nil then
		if self.punte.centrali.isOpen then
			self:playAnimation(self.punte.centrali.animation, 1, nil, true);
		end;
	end;
end;

function InteractiveControls:writeStream(streamId, connection)
	streamWriteBool(streamId, self.isSupport);
	streamWriteBool(streamId, self.punte.interne.isOpen);
	streamWriteBool(streamId, self.punte.esterne.isOpen);
	streamWriteBool(streamId, self.punte.centrali.isOpen);
end;

function InteractiveControls:readUpdateStream(streamId, timestamp, connection)
    if connection:getIsServer() then
        local updateInternePanel = streamReadBool(streamId);
        if updateInternePanel then
			self.punte.interne.isOpen = streamReadBool(streamId);
        end;
        local updateEsternePanel = streamReadBool(streamId);
        if updateEsternePanel then
			self.punte.esterne.isOpen = streamReadBool(streamId);
        end;
        local updateCentraliDoor = streamReadBool(streamId);
        if updateCentraliPanel then
			self.punte.centrali.isOpen = streamReadBool(streamId);
        end;
    end;
end;

function InteractiveControls:writeUpdateStream(streamId, connection, dirtyMask)
    if not connection:getIsServer() then
        if bitAND(dirtyMask, self.punte.interne.dirtyFlag) ~= 0 then
            streamWriteBool(streamId, true);
            streamWriteBool(streamId, self.punte.interne.isOpen);
        else
            streamWriteBool(streamId, false);
        end;
        if bitAND(dirtyMask, self.punte.esterne.dirtyFlag) ~= 0 then
            streamWriteBool(streamId, true);
            streamWriteBool(streamId, self.punte.esterne.isOpen);
        else
            streamWriteBool(streamId, false);
        end;
        if bitAND(dirtyMask, self.punte.centrali.dirtyFlag) ~= 0 then
            streamWriteBool(streamId, true);
            streamWriteBool(streamId, self.punte.centrali.isOpen);
        else
            streamWriteBool(streamId, false);
        end;
    end;
end;

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

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

function InteractiveControls:update(dt)	
	if self.supportRangeIndex then
		-- Manage key events for inrange support --
		if self.isInRangeSupport then
			if InputBinding.hasEvent(InputBinding.MODE) and self.balesAttached == false and not self.loadingIsActive then
				if self.isSupport then
					self:toggleSupport(false);
				else
					self:toggleSupport(true);
				end;
			end;
			setRotate = false;
			setVisibility(self.helpico, false);
			-- Display key when in range --
			if self.isSupport then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("ATTACH_SUPPORT")), InputBinding.MODE);
			elseif self.balesAttached == false and not self.loadingIsActive then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("DETACH_SUPPORT")), InputBinding.MODE);
			end;
			if InputBinding.hasEvent(InputBinding.Piloni) and self.PiloniSet == false then
				self:playAnimation(self.Piloni, 1);
				self.PiloniSet = true;
			elseif InputBinding.hasEvent(InputBinding.Piloni) and self.PiloniSet == true then
				self:playAnimation(self.Piloni, -1);
				self.PiloniSet = false;
			end;
			if not self.PiloniSet then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("PiloniOpen")), InputBinding.Piloni);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("PiloniClose")), InputBinding.Piloni);
			end;
		else
			setRotate = true;
		end;
	end;
	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.Collisione) and not self.loadingIsActive and self.balesAttached == false and self.CollisioneSet == false and self.setOpenClose == true then
			self:playAnimation(self.Collisione, -1);
			self.CollisioneSet = true;
		elseif InputBinding.hasEvent(InputBinding.Collisione) and not self.loadingIsActive and self.balesAttached == false and self.CollisioneSet == true and self.setOpenClose == true then
			self:playAnimation(self.Collisione, 1);
			self.CollisioneSet = false;
		end;
		if self.balesAttached == false and self.setOpenClose == true and not self.loadingIsActive then
			if not self.CollisioneSet then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("CollisioneOn")), InputBinding.Collisione);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("CollisioneOff")), InputBinding.Collisione);
			end;
		end;
	end;
	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.OpenClose) and self.setOpenClose == false then
			self:playAnimation(self.OpenClose, -1);
			self.setOpenClose = true;
			self:playAnimation(self.Collisione, 1);
			self.CollisioneSet = false;
		elseif InputBinding.hasEvent(InputBinding.OpenClose) and self.setOpenClose == true and self.balesAttached == false and not self.loadingIsActive then
			if self.CollisioneSet == true then 
				self:playAnimation(self.OpenClose, 1);
				self.setOpenClose = false;
			else
				self:playAnimation(self.Collisione, -1);
				self.CollisioneSet = true;
				self:playAnimation(self.OpenClose, 1);
				self.setOpenClose = false;
			end;
		end;
		if self.setOpenClose == false then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Open")), InputBinding.OpenClose);
		elseif self.setOpenClose == true and self.balesAttached == false and not self.loadingIsActive then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Close")), InputBinding.OpenClose);
		end;
	end;
	if self.isSupport then
		if self.punte.rangeIndex then
			-- Manage key events for inrange punte --
			if self.punte.inRange then
				if InputBinding.hasEvent(InputBinding.MODE1) then
					if self.punte.interne.isOpen then
						if self.punte.interne.animation ~= nil and self.playAnimation ~= nil then
							self:playAnimation(self.punte.interne.animation, -1, nil);
							self.puntepos = 1;
						end;
					else
						if self.punte.interne.animation ~= nil and self.playAnimation ~= nil then
							self:playAnimation(self.punte.interne.animation, 1, nil);
						end;
					end;
					self.punte.interne.isOpen = self.punte.interne.isOpen;		
					self:raiseDirtyFlags(self.punte.interne.dirtyFlag);
				end;
				-- Display key when in range --
				if self.punte.interne.isOpen then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("MODE1")), InputBinding.MODE1);
				else
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("ISBI")), InputBinding.MODE1);
				end;

				if InputBinding.hasEvent(InputBinding.MODE2) then
					if self.punte.centrali.isOpen then
						if self.punte.centrali.animation ~= nil and self.playAnimation ~= nil then
							self:playAnimation(self.punte.centrali.animation, -1, nil);
							self.puntepos = 2;
						end;
					else
						if self.punte.centrali.animation ~= nil and self.playAnimation ~= nil then
							self:playAnimation(self.punte.centrali.animation, 1, nil);
						end;
					end;
					self.punte.centrali.isOpen = self.punte.centrali.isOpen;
					self:raiseDirtyFlags(self.punte.centrali.dirtyFlag);
				end;
				-- Display key when in range --
				if self.punte.centrali.isOpen then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("MODE2")), InputBinding.MODE2);
				else
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("ISBC")), InputBinding.MODE2);
				end;

				if InputBinding.hasEvent(InputBinding.MODE3) then
					if self.punte.esterne.isOpen then
						if self.punte.esterne.animation ~= nil and self.playAnimation ~= nil then
							self:playAnimation(self.punte.esterne.animation, -1, nil);
							self.puntepos = 3;
						end;
					else
						if self.punte.esterne.animation ~= nil and self.playAnimation ~= nil then
							self:playAnimation(self.punte.esterne.animation, 1, nil);
						end;
					end;
					self.punte.esterne.isOpen = self.punte.esterne.isOpen;
					self:raiseDirtyFlags(self.punte.esterne.dirtyFlag);
				end;
				-- Display key when in range --
				if self.punte.esterne.isOpen then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("MODE3")), InputBinding.MODE3);
				else
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("ISBE")), InputBinding.MODE3);
				end;
				-- Display key when in range --
				if self.isSupport then
					if self.puntepos ~= 2 and self.puntepos ~= 3 then
						g_currentMission:addExtraPrintText(g_i18n:getText("ISBI"));
					end;
					if self.puntepos ~= 1 and self.puntepos ~= 3 then
						g_currentMission:addExtraPrintText(g_i18n:getText("ISBC"));
					end;
					if self.puntepos ~= 1 and self.puntepos ~= 2 then
						g_currentMission:addExtraPrintText(g_i18n:getText("ISBE"));
					end;
				end;
			end;
		end;
	end;
	if self:getIsActive() then		
		if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() then
			-- Show warning about the support being down
			if self.isSupport then
				g_currentMission:addWarning(string.format(g_i18n:getText("SUPPORT_WARNING")), 0.018, 0.033);
			end;
		end;
	end;
	if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() then
		setVisibility(self.helpico, false);
	elseif self.balesAttached == false and setRotate == true then
		setVisibility(self.helpico, true);
	end;
	if self:getIsActiveForInput() then
		if self.cameraInsertNum ~= nil and self.attacherVehicle ~= nil then
			if (self.attacherVehicle.camIndex == self.cameraInsertNum) and not self.gripperCameraActive then
				self:setGripperCameraState(true);
			elseif self.gripperCameraActive and (self.attacherVehicle.camIndex ~= self.cameraInsertNum) then
				self:setGripperCameraState(false);
			end;
		end;
	end;
	if self:getIsActiveForInput() then
		if self.cameraInsertNum == nil then
			for k, steerable in pairs(g_currentMission.steerables) do
				table.insert(steerable.cameras, self.cameras[1]);
				steerable.numCameras = steerable.numCameras+1;
				self.cameraInsertNum = table.getn(steerable.cameras);
			end;
			self.setCamera = false;
		end;
		if self.cameraInsertNum ~= nil and self.setCamera == false then
			for k, steerable in pairs(g_currentMission.steerables) do
				steerable.camIndex = self.cameraInsertNum;
				steerable.cameras[steerable.camIndex]:onActivate();
			end;
			self.setCamera = true;
		end;
		if self.cameraInsertNum ~= nil and (InputBinding.hasEvent(InputBinding.SWITCH_VEHICLE) or InputBinding.hasEvent(InputBinding.ENTER) or InputBinding.hasEvent(InputBinding.ATTACH)) then
			for k, steerable in pairs(g_currentMission.steerables) do
				steerable.steeringEnabled = true;
				steerable.camIndex = 1;
				steerable.cameras[steerable.camIndex]:onActivate();
			end;
			for k, steerable in pairs(g_currentMission.steerables) do
				steerable.steeringEnabled = true;
				if self.gripperCameraActive then
					steerable.cameras[self.cameraInsertNum]:onDeactivate();
					steerable.camIndex = 1;
				end;
				table.remove(steerable.cameras, self.cameraInsertNum);
				steerable.numCameras = steerable.numCameras-1;
				self.cameraInsertNum = nil;
				if self.gripperCameraActive then
					steerable.cameras[steerable.camIndex]:onActivate();
					self:setGripperCameraState(false);
				end;
				self.setCamera = false;
			end;
		end;
	end;
end;

function InteractiveControls:updateTick(dt)
	if self.supportRangeIndex then
		if g_currentMission.player ~= nil then
			-- Getting the distance between the player and the support
			local nearestDistance = 3.0; --max distance allowed
			local px, py, pz = getWorldTranslation(self.supportRangeIndex);
			local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
			local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
			if distance < nearestDistance then
				self.isInRangeSupport = true;
			else
				self.isInRangeSupport = false;
			end;
		end;
	else
		self.isInRangeSupport = false;
	end;
	if self.punte.rangeIndex then
		if g_currentMission.player ~= nil then
			-- Getting the distance between the player and the punte
			local nearestDistance = 3.0; --max distance allowed
			local px, py, pz = getWorldTranslation(self.punte.rangeIndex);
			local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
			local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
			if distance < nearestDistance then
				self.punte.inRange = true;
			else
				self.punte.inRange = false;
			end;
		end;
	else
		self.punte.inRange = false;
	end;
end;

function InteractiveControls:draw()
	if self:getIsActiveForInput(true) then
		g_currentMission:addExtraPrintText(g_i18n:getText("Help"));
	end;
	if self.setOpenClose == false then
		self.CloseFrameOverlay:render();
	else
		self.OpenFrameOverlay:render();
	end;
end;

function InteractiveControls:onAttach(attacherVehicle)
	setVisibility(self.hydraulicHoses.attached, true);
	setVisibility(self.hydraulicHoses.detached, false);
	setVisibility(self.helpico, false);
	self.attacherVehicle = attacherVehicle;
	self.setOpenClose = false;
end;

function InteractiveControls:onDetach()
	setVisibility(self.hydraulicHoses.attached, false);
	setVisibility(self.hydraulicHoses.detached, true);
	setVisibility(self.helpico, true);
	self:playAnimation(self.Collisione, -1);
	self.CollisioneSet = true;
	self.attacherVehicle = nil;
	self.setOpenClose = false;
end;

function InteractiveControls:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	local isSupport = Utils.getNoNil(getXMLBool(xmlFile, key .. "#isSupport"), false);
	self:toggleSupport(isSupport);
    return BaseMission.VEHICLE_LOAD_OK;
end;

function InteractiveControls:getSaveAttributesAndNodes(nodeIdent)
end;

function InteractiveControls:toggleSupport(isSupport, noEventSend)
	ToggleSupportEvent.sendEvent(self, isSupport, noEventSend);	
	if not isSupport then
		if self.manualSupportAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.manualSupportAnimation, -1, nil, true);
		end;
	else
		if self.manualSupportAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.manualSupportAnimation, 1, nil, true);
		end;
	end;
	self.isSupport = isSupport;
end;

-- Support event
ToggleSupportEvent = {};
ToggleSupportEvent_mt = Class(ToggleSupportEvent, Event);
InitEventClass(ToggleSupportEvent, "ToggleSupportEvent");

function ToggleSupportEvent:emptyNew()
    local self = Event:new(ToggleSupportEvent_mt);
    return self;
end;

function ToggleSupportEvent:new(vehicle, isSupport)
    local self = ToggleSupportEvent:emptyNew()
    self.vehicle = vehicle;
	self.isSupport = isSupport;
    return self;
end;

function ToggleSupportEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.vehicle = networkGetObject(id);
	self.isSupport = streamReadBool(streamId);
    self:run(connection);
end;

function ToggleSupportEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));	
	streamWriteBool(streamId, self.isSupport);
end;

function ToggleSupportEvent:run(connection)
	self.vehicle:toggleSupport(self.isSupport, true);
end;

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

function InteractiveControls:setGripperCameraState(cameraState, noEventSend)
	GripperCameraActivState.sendEvent(self, cameraState, noEventSend);
	self.gripperCameraActive = cameraState;
	setVisibility(self.characterNode, cameraState);
end;

function InteractiveControls:onDeactivate()
	self:setGripperCameraState(false);
end;