--
-- 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(savegame)

    source(Utils.getFilename("shaders/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("shaders/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;
    

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.InteractiveControl_Switch) then
                self.isMouseActive = 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.InteractiveControl_Switch);
    else
        g_currentMission:addHelpButtonText(g_i18n:getText("InteractiveControl_On"), InputBinding.InteractiveControl_Switch);
    end;
end;

function InteractiveControl:onLeave()
    self.cameras[self.indoorCamIndex].isActivated = 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;