--
-- Big thanks to all of those who helped with development of IC
-- SFM-Modding, LoogleCZ, And other...
-- Original IC:                     Manuel Leithner
-- Edit IC and current development: Martin Fabík (LoogleCZ)
-- Testing: Daniel Zapletal, Martin Fabík
-- and others...
-- 
-- Free for non-comerecial usage
-- 
-- Important note: this is BETA script. If anyone found errors, please contact me at mar.fabik@gmail.com
--                 Script is under active development. You can discuss changes with me at mar.fabik@gmail.com
--
-- version ID   - 2.95
-- version date - 24.4.2016 (19:44)
--

if originalInputBindingUpdate == nil then
    originalInputBindingUpdate = InputBinding.update;
    InputBinding.update = function(dt)
        InputBinding.accumMouseMovementXBackUp = InputBinding.accumMouseMovementX;
        InputBinding.accumMouseMovementYBackUp = InputBinding.accumMouseMovementY;
        originalInputBindingUpdate(dt);
    end;
end;

InteractiveControl = {};

local MDR = g_currentModDirectory;
source(MDR.."ICSources/actionFunction.lua");
source(MDR.."ICSources/extraFunctions.lua");
source(MDR.."ICSources/InteractiveControlEvent.lua");

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

function InteractiveControl:load(savegame)
    self.renderOverlayAndInfo = SpecializationUtil.callSpecializationsFunction("renderOverlayAndInfo");
    self.toggleICState = SpecializationUtil.callSpecializationsFunction("toggleICState");
    self.actionOnObject = SpecializationUtil.callSpecializationsFunction("actionOnObject");
    self.updateOpenStatus = SpecializationUtil.callSpecializationsFunction("updateOpenStatus");
    self.loadICButtonFromXML = InteractiveControl.loadICButtonFromXML;
    
    source(MDR.."ICSources/functionsInit.lua");
    
    self.LIC = {};
    self.LIC.interactiveObjects = {};
    self.LIC.objectsListeners = {};
    self.LIC.getElementListeners = {};
    self.indoorCamIndex = 1;
    self.outdoorCamIndex = 2;
    self.LIC.lastMouseXPos = 0;
    self.LIC.lastMouseYPos = 0;                    
    self.LIC.foundInteractiveObject = nil;
    self.LIC.isMouseActive = false;
    self.LIC.minOutsideDistance = Utils.getNoNil(getXMLFloat(self.xmlFile,"vehicle.interactiveComponents#minDist"), 3);
    self.LIC.toggleStateStyle = Utils.getNoNil(getXMLFloat(self.xmlFile,"vehicle.interactiveComponents#toggleStyle"), 0);
    self.LIC.isInOutsideRange = false;
    self.LIC.isInitialized = false;
    self.LIC.isClicked = false;
    self.LIC.camRotPlayer = {};
    self.LIC.partLen = {};
    
    local j = 0;
    --=========================================--
    self.LIC.joints = {};
    self.LIC.joints.front = {};
    self.LIC.joints.back = {};
    for k,joint in pairs(self.attacherJoints) do
        if joint.jointType == Vehicle.JOINTTYPE_IMPLEMENT or joint.jointType == Vehicle.JOINTTYPE_CUTTER or joint.jointType == Vehicle.JOINTTYPE_CUTTERHARVESTER or joint.jointType == Vehicle.JOINTTYPE_TRAILER or joint.jointType == Vehicle.JOINTTYPE_TRAILERLOW then
            local x,y,z = getWorldTranslation(self.attacherJoints[k].jointTransform);
            local rx,ry,rz = worldToLocal(self.rootNode,x,y,z);
            if rz > 0 then
                table.insert(self.LIC.joints.front,k);
            else
                table.insert(self.LIC.joints.back,k);
            end;
        end;
    end;
    --=========================================--
    --             Interactive Window          --
    
    local i=0;
    while true do
        local objectType = 0;
        local key = string.format("vehicle.interactiveComponents.windows.window(%d)", i);    
        if not hasXMLProperty(self.xmlFile, key) then
            break;
        end;
        local animation = getXMLString(self.xmlFile, key .. "#animName");
        local looping = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#looping"), false);
        local speedScale = -Utils.getNoNil(getXMLFloat(self.xmlFile, key .. "#animSpeedScale"), 1);
        local clipParent = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key .. "#clipRoot"));
        local animClip = nil;
        if clipParent ~= nil and clipParent ~= 0 then
            animClip = {};
            animClip.animCharSet = getAnimCharacterSet(clipParent);
            if animClip.animCharSet ~= 0 then
                local clip = getAnimClipIndex(animClip.animCharSet, getXMLString(self.xmlFile, key .. "#clip"));
                assignAnimTrackClip(animClip.animCharSet, 0, clip);
                setAnimTrackLoopState(animClip.animCharSet, 0, looping);
                animClip.animDuration = getAnimClipDuration(animClip.animCharSet, clip);
                setAnimTrackTime(animClip.animCharSet, 0, 0);
            end;
        end;
        if animation ~= nil or animClip ~= nil then
            self.LIC.interactiveObjects[j] = {};
            self.LIC.interactiveObjects[j].animation = animation;
            self.LIC.interactiveObjects[j].animClip = animClip;
            self.LIC.interactiveObjects[j].speedScale = speedScale;
            self.LIC.interactiveObjects[j].objectType = objectType;
            self.LIC.interactiveObjects[j].looping = looping;
            self.LIC.interactiveObjects[j].isEntered = false;
            self:loadICButtonFromXML(self.xmlFile, key, self.LIC.interactiveObjects[j], j);
            j = j + 1;
        else
            print(string.format("Cannot load Interactive Window - vehicle.interactiveComponents.windows.window(%d)",i));
            print("  - Missing animation or animation clip.");
        end;
        i = i + 1;
    end;
    self.LIC.partLen.animation = j;
    --=========================================--
    
    --=========================================--
    --           Interactive Buttons           --
    
    local i=0;
    while true do
        local objectType = 1;
        local key = string.format("vehicle.interactiveComponents.buttons.button(%d)", i);    
        if not hasXMLProperty(self.xmlFile, key) then
            break;
        end;
        local event = getXMLString(self.xmlFile, key .. "#event");
        if event ~= nil then
            self.LIC.interactiveObjects[j] = {};
            self.LIC.interactiveObjects[j].event = event;
            self.LIC.interactiveObjects[j].objectType = objectType;
            self.LIC.interactiveObjects[j].isEntered = false;
            self:loadICButtonFromXML(self.xmlFile, key, self.LIC.interactiveObjects[j], j);
            if string.sub( self.LIC.interactiveObjects[j].event, 1, 10 ) == "l2gsToggle" then
                self.LIC.interactiveObjects[j].synch = false;
            end;
            j = j + 1;
        else
            print(string.format("Cannot load Interactive Button - vehicle.interactiveComponents.buttons.button(%d)",i));
            print("  - missing event");
        end;        
        i = i + 1;
    end;
    self.LIC.partLen.button = j-self.LIC.partLen.animation;
    --=========================================--
    --=========================================--
    --           Interactive Monitors          --
    
    local i=0;
    local m=0;
    while true do
        local objectType = 2;
        local key = string.format("vehicle.interactiveComponents.monitors.monitor(%d)", i);    
        if not hasXMLProperty(self.xmlFile, key) then
            break;
        end;
        local useStart = Utils.getNoNil(getXMLBool(self.xmlFile, key .. "#useStart"), true);
        local startAnimation = getXMLString(self.xmlFile, key .. "#animName");
        local layerBackupPos = getXMLString(self.xmlFile, key .. "#layerClosePos");
        local layerVisPos = getXMLString(self.xmlFile, key .. "#layerVisPos");
        local defaultLayer = getXMLInt(self.xmlFile, key .. "#defaultLayer");
        local moveDef = Utils.getNoNil(getXMLBool(self.xmlFile, key .. "#moveDefaultLayer"), false);
        if layerBackupPos ~= nil and layerVisPos ~= nil then
            self.LIC.interactiveObjects[j] = {};
            self.LIC.interactiveObjects[j].objectType = objectType;
            self.LIC.interactiveObjects[j].useStart = useStart;
            self.LIC.interactiveObjects[j].startAnimation = startAnimation;
            self.LIC.interactiveObjects[j].defaultLayer = defaultLayer;
            self.LIC.interactiveObjects[j].moveDef = moveDef;
            self.LIC.interactiveObjects[j].layerBackupPos = {};
            self.LIC.interactiveObjects[j].layerBackupPos[1],self.LIC.interactiveObjects[j].layerBackupPos[2],self.LIC.interactiveObjects[j].layerBackupPos[3] = Utils.getVectorFromString(layerBackupPos);
            self.LIC.interactiveObjects[j].layerVisPos = {};
            self.LIC.interactiveObjects[j].layerVisPos[1],self.LIC.interactiveObjects[j].layerVisPos[2],self.LIC.interactiveObjects[j].layerVisPos[3] = Utils.getVectorFromString(layerVisPos);
            self.LIC.interactiveObjects[j].isEntered = false;
            self.LIC.interactiveObjects[j].activeLayer = defaultLayer;
            self.LIC.interactiveObjects[j].layerButtons = {};
            self.LIC.interactiveObjects[j].layerIndexes = {};
            self:loadICButtonFromXML(self.xmlFile, key, self.LIC.interactiveObjects[j]);
            local k = 0;
            local upperLayerIndex = j;
            while true do
                local key2 = string.format(key..".layer(%d)", k);
                if not hasXMLProperty(self.xmlFile, key2) then
                    break;
                end;
                local name = Utils.getNoNil((getXMLString(self.xmlFile, key2 .. "#name")), "ERROR");
                local index = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key2 .. "#index"));
                local size = Utils.getNoNil(getXMLFloat(self.xmlFile, key2 .. ".open#size"), 0.1);
                local mark = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key2 .. ".open#mark"));
                local size1 = Utils.getNoNil(getXMLFloat(self.xmlFile, key2 .. ".close#size"), 0.1);
                local mark1 = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key2 .. ".close#mark"));
                local onMessage = g_i18n:getText(Utils.getNoNil(getXMLString(self.xmlFile, key2 .. "#onMessage"), "ic_button_on"));
                local offMessage =  g_i18n:getText(Utils.getNoNil(getXMLString(self.xmlFile, key2 .. "#offMessage") , "ic_button_off"));
                if mark ~= nil then
                    setVisibility(mark,false);
                end;
                if mark1 ~= nil then
                    setVisibility(mark1,false);
                end;
                if index ~= nil then
                    self.LIC.interactiveObjects[upperLayerIndex].layerIndexes[k] = index;
                    if mark1 ~= nil and mark ~= nil then
                        j = j + 1;
                        m = m + 1;
                        self.LIC.interactiveObjects[j] = {};
                        self.LIC.interactiveObjects[j].event = "openDisplayLayer";
                        self.LIC.interactiveObjects[j].objectType = 1;
                        self.LIC.interactiveObjects[j].index = k;
                        self.LIC.interactiveObjects[j].name = name;
                        self.LIC.interactiveObjects[j].mark = mark;
                        self.LIC.interactiveObjects[j].size = size;
                        self.LIC.interactiveObjects[j].onMessage = onMessage;
                        self.LIC.interactiveObjects[j].offMessage = onMessage;
                        self.LIC.interactiveObjects[j].synch = self.LIC.interactiveObjects[upperLayerIndex].synch;
                        self.LIC.interactiveObjects[j].parentLayer = upperLayerIndex;
                        self.LIC.interactiveObjects[j].isOpen = false;
                        local sf = getXMLString(self.xmlFile, key2..".open#soundFile");
                        if sf ~= nil then
                            self.LIC.interactiveObjects[j].audio = createSample(string.format("ICSound%d",j));
                            loadSample(self.LIC.interactiveObjects[j].audio, MDR..sf, false);
                        end;                        
                        table.insert(self.LIC.interactiveObjects[upperLayerIndex].layerButtons,j);
                        j = j + 1;
                        m = m + 1;
                        self.LIC.interactiveObjects[j] = {};
                        self.LIC.interactiveObjects[j].event = "closeDisplayLayer";
                        self.LIC.interactiveObjects[j].objectType = 1;
                        self.LIC.interactiveObjects[j].index = k;
                        self.LIC.interactiveObjects[j].name = name;
                        self.LIC.interactiveObjects[j].mark = mark1;
                        self.LIC.interactiveObjects[j].size = size1;
                        self.LIC.interactiveObjects[j].onMessage = offMessage;
                        self.LIC.interactiveObjects[j].offMessage = offMessage;
                        self.LIC.interactiveObjects[j].synch = self.LIC.interactiveObjects[upperLayerIndex].synch;
                        self.LIC.interactiveObjects[j].parentLayer = upperLayerIndex;
                        self.LIC.interactiveObjects[j].isOpen = false;
                        local sf = getXMLString(self.xmlFile, key2..".close#soundFile");
                        if sf ~= nil then
                            self.LIC.interactiveObjects[j].audio = createSample(string.format("ICSound%d",j));
                            loadSample(self.LIC.interactiveObjects[j].audio, MDR..sf, false);
                        end;
                        table.insert(self.LIC.interactiveObjects[upperLayerIndex].layerButtons,j);
                        setVisibility(index, false);
                        -- prvne open a potom close
                    end;
                end;
                k = k + 1;
            end;
            j = j + 1;
            m = m + 1;
            self:actionOnObject(upperLayerIndex, false, true);
        else
            print(string.format("Cannot load Interactive monitor - vehicle.interactiveComponents.monitors.monitor(%d)",i));
            print("  - invalid backup and vis positions");
        end;
        i = i + 1;
    end;
    self.LIC.partLen.monitor = m;
    --=========================================--
    --=========================================--
    --         Interactive visibility          --
    
    local i=0;
    local m=0;
    while true do
        local objectType = 3;
        local key = string.format("vehicle.interactiveComponents.visControls.button(%d)", i);    
        if not hasXMLProperty(self.xmlFile, key) then
            break;
        end;
        local defVis = getXMLBool(self.xmlFile, key .. "#defaultVis");
        local typeChange = Utils.getNoNil(getXMLString(self.xmlFile, key .. "#typeChange"), "set");
        local controlObject = getXMLString(self.xmlFile, key .. "#controlElem");
        self.LIC.interactiveObjects[j] = {};
        self.LIC.interactiveObjects[j].objectType = objectType;
        self.LIC.interactiveObjects[j].typeChange = typeChange;
        self.LIC.interactiveObjects[j].isEntered = false;
        if controlObject ~= nil then
            self.LIC.interactiveObjects[j].controlObject = Utils.indexToObject(self.components, controlObject); 
        end;
        self.LIC.interactiveObjects[j].objects = {};
        local k = 0;
        while true do
            local key2 = string.format(key..".index(%d)", k);
            if not hasXMLProperty(self.xmlFile, key2) then
                break;
            end;
            local index = getXMLString(self.xmlFile, key2.."#index");
            if index ~= nil then
                self.LIC.interactiveObjects[j].objects[(k+1)] = Utils.indexToObject(self.components, index);
                if defVis ~= nil then
                    setVisibility(self.LIC.interactiveObjects[j].objects[(k+1)], defVis);
                end;
            end;
            k = k + 1;
        end;
        self:loadICButtonFromXML(self.xmlFile, key, self.LIC.interactiveObjects[j], j);
        j = j + 1;
        m = m + 1;
        i = i + 1;
    end;
    self.LIC.partLen.visibility = m;
    --=========================================--
    
    --============ MULTI BUTTONS ==============--

    local i=0;
    self.LIC.partLen.mbutton = 0;
    while true do
        local objectType = 4;
        local key = string.format("vehicle.interactiveComponents.multiButtons.mbutton(%d)", i);    
        if not hasXMLProperty(self.xmlFile, key) then
            break;
        end;
        self.LIC.interactiveObjects[j] = {};
        self.LIC.interactiveObjects[j].objectType = objectType;
        self.LIC.interactiveObjects[j].isEntered = false;
        if hasXMLProperty(self.xmlFile, key..".control") then
            local mbtype = getXMLString(self.xmlFile, key..".control#type");
            local index = getXMLInt(self.xmlFile, key..".control#index");
            if index <= self.LIC.partLen[mbtype] then
                local indexFinal = index;
                if mbtype == "animation" then
                elseif mbtype == "button" then
                    indexFinal = indexFinal + self.LIC.partLen.animation;
                elseif mbtype == "monitor" then
                    indexFinal = indexFinal + self.LIC.partLen.button + self.LIC.partLen.animation;
                elseif mbtype == "visibility" then
                    indexFinal = indexFinal + self.LIC.partLen.monitor + self.LIC.partLen.button + self.LIC.partLen.animation;
                elseif mbtype == "mbutton" then
                    indexFinal = indexFinal + self.LIC.partLen.visibility + self.LIC.partLen.monitor + self.LIC.partLen.button + self.LIC.partLen.animation;
                end;
                self.LIC.interactiveObjects[j].controlElement = indexFinal;
            end;
        end;
        local k = 0;
        self.LIC.interactiveObjects[j].actionElements = {};
        while true do
            key2 = string.format(key..".part(%d)",k);
            if not hasXMLProperty(self.xmlFile, key2) then
                break;
            end;
            local mbtype = getXMLString(self.xmlFile, key2.."#type");
            local index = getXMLInt(self.xmlFile, key2.."#index");
            local neg = Utils.getNoNil(getXMLInt(self.xmlFile, key2.."#negStatus"),false);
            if index <= self.LIC.partLen[mbtype] then
                local indexFinal = index;
                if mbtype == "animation" then
                elseif mbtype == "button" then
                    indexFinal = indexFinal + self.LIC.partLen.animation;
                elseif mbtype == "monitor" then
                    indexFinal = indexFinal + self.LIC.partLen.button + self.LIC.partLen.animation;
                elseif mbtype == "visibility" then
                    indexFinal = indexFinal + self.LIC.partLen.monitor + self.LIC.partLen.button + self.LIC.partLen.animation;
                elseif mbtype == "mbutton" then
                    indexFinal = indexFinal + self.LIC.partLen.visibility + self.LIC.partLen.monitor + self.LIC.partLen.button + self.LIC.partLen.animation;
                end;
                self.LIC.interactiveObjects[j].actionElements[indexFinal] = neg;
            end;
            k = k + 1;
        end;
        self:loadICButtonFromXML(self.xmlFile, key, self.LIC.interactiveObjects[j], j);
        j = j + 1;
        self.LIC.partLen.mbutton = self.LIC.partLen.mbutton + 1;    
        i = i + 1;
    end;
    
    --====================================--
    --=== LOAD CROSS BUTTONS LISTENERS ===--
    local i=0;
    while true do
        local key = string.format("vehicle.interactiveComponents.buttonsListeners.listener(%d)", i);    
        if not hasXMLProperty(self.xmlFile, key) then
            break;
        end;
        self.LIC.objectsListeners[i] = {};
        local j = 0;
        while true do
            local key2 = string.format(key .. ".element(%d)", j);
            if not hasXMLProperty(self.xmlFile, key2) then
                break;
            end;
            local Ltype = getXMLString(self.xmlFile, key2.."#type");
            local Oindex = getXMLInt(self.xmlFile, key2.."#index");
            if Oindex <= self.LIC.partLen[Ltype] then
                local indexFinal = Oindex;
                if Ltype == "animation" then
                elseif Ltype == "button" then
                    indexFinal = indexFinal + self.LIC.partLen.animation;
                elseif Ltype == "monitor" then
                    indexFinal = indexFinal + self.LIC.partLen.button + self.LIC.partLen.animation;
                elseif Ltype == "visibility" then
                    indexFinal = indexFinal + self.LIC.partLen.monitor + self.LIC.partLen.button + self.LIC.partLen.animation;
                elseif Ltype == "mbutton" then
                    indexFinal = indexFinal + self.LIC.partLen.visibility + self.LIC.partLen.monitor + self.LIC.partLen.button + self.LIC.partLen.animation;
                end;
                table.insert(self.LIC.objectsListeners[i],indexFinal);
                if self.LIC.getElementListeners[indexFinal] == nil then
                    table.insert(self.LIC.getElementListeners,indexFinal,{});
                end;
                self.LIC.getElementListeners[indexFinal][table.getn(self.LIC.getElementListeners[indexFinal])] = i;
            end;
            j = j + 1;
        end;
        i = i + 1;
    end;
end;

function InteractiveControl:delete()
end;

function InteractiveControl:readStream(streamId, connection)
    local icCount = streamReadInt8(streamId);
    for i=0, icCount do
        local LICId = streamReadInt8(streamId);
        local isOpen = streamReadBool(streamId);
        if self.LIC.interactiveObjects[LICId] ~= nil then
            if self.LIC.interactiveObjects[LICId].synch then
                self:actionOnObject(LICId, isOpen, false);
            end;
        end;
    end;
end;

function InteractiveControl:writeStream(streamId, connection)
    local icCount = (table.getn(self.LIC.interactiveObjects)-1);
    streamWriteInt8(streamId, icCount);
    for i=0, icCount do
        streamWriteInt8(streamId, i);
        streamWriteBool(streamId, self.LIC.interactiveObjects[i].isOpen);
    end;
end;

function InteractiveControl:mouseEvent(posX, posY, isDown, isUp, button)
    self.LIC.lastMouseXPos = posX;
    self.LIC.lastMouseYPos = posY;
end;

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

function InteractiveControl:update(dt)
    local blockToggle = false;
    if self.isMotorStarted then
        self.forceIsActive = true;
        if not self.LIC.isInitialized then
            self.LIC.isInitialized = not self.LIC.isInitialized;
            for k,v in pairs(self.LIC.interactiveObjects) do
                if v.objectType == 2 and v.useStart then
                    self:actionOnObject(k, true);
                end;
            end;
        end;
    else
        self.forceIsActive = false;
        if self.LIC.isInitialized then
            self.LIC.isInitialized = not self.LIC.isInitialized;
            for k,v in pairs(self.LIC.interactiveObjects) do
                if v.objectType == 2 then
                    self:actionOnObject(k, false);
                end;
            end;
        end;
    end;

    if Input.isMouseButtonPressed(Input.MOUSE_BUTTON_LEFT) and self.LIC.foundInteractiveObject ~= nil then
        if not self.LIC.isClicked then
            self.LIC.isClicked = true;
            self:actionOnObject(self.LIC.foundInteractiveObject);
            if self.LIC.interactiveObjects[self.LIC.foundInteractiveObject].audio ~= nil then
                if self:getIsActiveForSound() then
                    playSample(self.LIC.interactiveObjects[self.LIC.foundInteractiveObject].audio,1,1,0);
                end;
            end;
        end;
    else
        self.LIC.isClicked = false;
    end;
    if self.isMouseActive then
        self.mouseButton = MouseControlsVehicle.BUTTON_NONE;
    end;
    self.LIC.foundInteractiveObject = nil;
    if self.LIC.isInOutsideRange and not blockToggle then
        if self.LIC.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;
        if self.LIC.toggleStateStyle == 0 then
            if InputBinding.hasEvent(InputBinding.INTERACTIVE_CONTROL_SWITCH) then
                self:toggleICState(true);
            end;
        elseif self.LIC.toggleStateStyle == 1 then
            if InputBinding.isPressed(InputBinding.INTERACTIVE_CONTROL_SWITCH) then
                self:toggleICState(true,true);
            else
                self:toggleICState(true,false);
            end;
        end;
        blockToggle = true;
    end;
    if self:getIsActive() then
        if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() and not blockToggle then
            if self.LIC.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;
            if self.LIC.toggleStateStyle == 0 then
                if InputBinding.hasEvent(InputBinding.INTERACTIVE_CONTROL_SWITCH) then
                    self:toggleICState(false);
                end;
            elseif self.LIC.toggleStateStyle == 1 then
                if InputBinding.isPressed(InputBinding.INTERACTIVE_CONTROL_SWITCH) then
                    self:toggleICState(false,true);
                else
                    self:toggleICState(false,false);
                end;
            end;
            blockToggle = true;
        end;
    end;

    if self.LIC.isMouseActive and not self.isEntered then
        self.LIC.lastMouseXPos = InputBinding.mousePosXLast;
        self.LIC.lastMouseYPos = InputBinding.mousePosYLast;
        for _,v in pairs(self.LIC.interactiveObjects) do
            v.isEntered = false;
        end
        if self.LIC.lastMouseXPos ~= nil and self.LIC.lastMouseYPos ~= nil then
            for k,v in pairs(self.LIC.interactiveObjects) do
                if v.mark ~= nil and self.LIC.foundInteractiveObject == nil then
                    local worldX,worldY,worldZ = getWorldTranslation(v.mark);
                    local x,y,z = project(worldX,worldY,worldZ);
                    if z <= 1 then
                        if self.LIC.lastMouseXPos > (x-v.size/2) and self.LIC.lastMouseXPos < (x+v.size/2) then
                            if self.LIC.lastMouseYPos > (y-v.size/2) and self.LIC.lastMouseYPos < (y+v.size/2) then
                                if v.canOutside then
                                    v.isEntered = true;
                                    self:renderOverlayAndInfo(v);
                                    self:updateOpenStatus(k);
                                    self.LIC.foundInteractiveObject = k;
                                    break;
                                end;
                            end;
                        end;
                    end;
                end;
            end;
        end;
    end;

    if self:getIsActive() then
        InputBinding.accumMouseMovementXBackUp = 0;
        InputBinding.accumMouseMovementYBackUp = 0;
    end;
end;

function InteractiveControl:updateTick(dt)
    if g_currentMission.player ~= nil then
        local nearestDistance = self.LIC.minOutsideDistance;
        local px, py, pz = getWorldTranslation(self.rootNode); 
        local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
        local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
        if distance < nearestDistance then
            self.LIC.isInOutsideRange = true;
        else
            if self.LIC.isInOutsideRange then
                self:toggleICState(false, false);
                self.LIC.isInOutsideRange = false;
            end;
        end;
    end;
end;

function InteractiveControl:draw()
    if self.LIC.isMouseActive and self.isEntered then
        for _,v in pairs(self.LIC.interactiveObjects) do
            v.isEntered = false;
        end
        if self.LIC.lastMouseXPos ~= nil and self.LIC.lastMouseYPos ~= nil then
            for k,v in pairs(self.LIC.interactiveObjects) do
                if v.mark ~= nil and self.LIC.foundInteractiveObject == nil then
                    local worldX,worldY,worldZ = getWorldTranslation(v.mark);
                    local x,y,z = project(worldX,worldY,worldZ);
                    if z <= 1 then
                        if self.LIC.lastMouseXPos > (x-v.size/2) and self.LIC.lastMouseXPos < (x+v.size/2) then
                            if self.LIC.lastMouseYPos > (y-v.size/2) and self.LIC.lastMouseYPos < (y+v.size/2) then
                                if not v.canOutside then
                                    v.isEntered = true;
                                    self:renderOverlayAndInfo(v);
                                    self:updateOpenStatus(k);
                                    self.LIC.foundInteractiveObject = k;
                                    break;
                                end;
                            end;
                        end;
                    end;
                end;
            end;
        end;
    end;
end;

function InteractiveControl:onEnter()
end;

function InteractiveControl:onLeave()
    self:toggleICState(false, false);
    -- g_mouseControlsHelp.active = true;
    if g_gui.currentGui == nil then
        InputBinding.setShowMouseCursor(false);
    end;
end;

function InteractiveControl:renderOverlayAndInfo(object)
    if object.isOpen then
        g_currentMission:addExtraPrintText(string.format(object.offMessage, object.name));
    else
        g_currentMission:addExtraPrintText(string.format(object.onMessage, object.name));
    end;
end;

function InteractiveControl:toggleICState(isOutside, forceStatus)
    if self.isClient then
        if self.LIC.isMouseActive == nil then
            print("Shit happens");
            self.LIC.isMouseActive = false;
            self:toggleICState(false, true);
            self:toggleICState(false, false);
        end;
        if self.LIC.isMouseActive ~= forceStatus then
            if forceStatus == nil then
                self.LIC.isMouseActive = not self.LIC.isMouseActive;
            else
                self.LIC.isMouseActive = forceStatus;
            end;
            -- g_mouseControlsHelp.active = not self.LIC.isMouseActive;
            if self.LIC.isMouseActive then
                if g_currentMission.player ~= nil then
                    g_currentMission.player.walkingIsLocked = true;
                end;
                
                InputBinding.setShowMouseCursor(true);
                if self.cameras ~= nil then
                    for _,v in pairs(self.cameras) do
                        v.isActivated = false;
                    end;
                end;
            else
                if g_currentMission.player ~= nil then
                    g_currentMission.player.walkingIsLocked = false;
                end;

                InputBinding.setShowMouseCursor(false);
                for _,v in pairs(self.LIC.interactiveObjects) do
                    v.isEntered = false;
                    if v.mark ~= nil then
                        setVisibility(v.mark, false);
                    end;
                end;
                if self.cameras ~= nil then
                    for _,v in pairs(self.cameras) do
                        v.isActivated = true;
                    end;
                end;
            end;
            if self.LIC.isMouseActive then
                for k,v in pairs(self.LIC.interactiveObjects) do
                    if isOutside and v.canOutside then
                        if v.mark ~= nil then
                            setVisibility(v.mark, true);
                        end;
                    elseif (not isOutside or isOutside == nil) and not v.canOutside then
                        if v.mark ~= nil then
                            setVisibility(v.mark, true);
                        end;
                    end;
                end;
            end;
            if not self.LIC.isMouseActive then
                self.LIC.foundInteractiveObject = nil;
            end;
        end;
    end;
end;

function InteractiveControl:loadICButtonFromXML(xmlFile, key, ICBtn, index)
    ICBtn.name = g_i18n:getText(Utils.getNoNil((getXMLString(xmlFile, key .. "#name")), "ERROR"));
    ICBtn.size = Utils.getNoNil((getXMLFloat(xmlFile, key .. "#size")), 0.05);
    ICBtn.mark = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#mark"));
    if ICBtn.mark ~= nil then
        setVisibility(ICBtn.mark,false);
    end;
    ICBtn.isOpen = Utils.getNoNil((getXMLBool(xmlFile, key .. "#defaultStatus")), false);
    
    ICBtn.onMessage = g_i18n:getText(Utils.getNoNil(getXMLString(xmlFile, key .. "#onMessage"), "ic_button_on"));
    ICBtn.offMessage =  g_i18n:getText(Utils.getNoNil(getXMLString(xmlFile, key .. "#offMessage") , "ic_button_off"));
    
    ICBtn.canOutside =  Utils.getNoNil(getXMLBool(xmlFile, key.."#isOutside"), false);
    ICBtn.synch =  Utils.getNoNil(getXMLBool(xmlFile, key.."#synch"), true);
    
    local initAction = Utils.getNoNil((getXMLBool(xmlFile, key .. "#initAction")), true);
    local soundFile = getXMLString(xmlFile, key.."#soundFile");
    if soundFile ~= nil and index ~= nil then
        ICBtn.audio = createSample(string.format("ICSound%d",index));
        loadSample(ICBtn.audio, MDR..soundFile, false);
    end;
    if initAction and index ~= nil and self.isServer then
        self:actionOnObject(index, ICBtn.isOpen, true);
    end;
end;