--
-- controlI3DAnim  v1.21 
-- Specialization to control I3D animations
-- Spezialisierung um I3D Animationen zu steuern
-- @author  Sven777b
-- 
-- frei verwendbar - keine erlaubnis nötig  |  free for use - no permission needed.
-- Modifikationen erst nach Rücksprache!    |  modifications only with my permission.
--
-- Hinweis: das kopieren von Sourcecode ist strafbar nach UrhG §2.1

controlI3DAnim = {};

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

function controlI3DAnim:load(savegame)
    self.setI3DAnimState = SpecializationUtil.callSpecializationsFunction("setI3DAnimState");
    local i=0;
    self.i3danims = {};
    self.hasOutsideControls = false;
    while true do
        local basename = string.format("vehicle.i3dAnims.anim(%d)#",i);
        local rnindex = getXMLString(self.xmlFile,basename.."rootnode");
        if rnindex == nil then break; end;
        local anim = {};
        anim.rootNode = Utils.indexToObject(self.components, rnindex);
        if anim.rootNode ~= nil and anim.rootNode ~= 0 then
            anim.charSet = getAnimCharacterSet(anim.rootNode);
            if anim.charSet ~= 0 then
                local clipname = getXMLString(self.xmlFile,basename.."clipname");
                local clip = getAnimClipIndex(anim.charSet, clipname);
                if clip ~= nil then
                    assignAnimTrackClip(anim.charSet, 0, clip);
                    anim.loop = Utils.getNoNil(getXMLBool(self.xmlFile,basename.."loop"),false);
                    setAnimTrackLoopState(anim.charSet, 0, anim.loop);
                    anim.duration = getAnimClipDuration(anim.charSet, clip);
                    anim.speed = Utils.getNoNil(getXMLFloat(self.xmlFile,basename.."speed"),1.0);
                    if anim.speed < 0 then
                        enableAnimTrack(anim.charSet, 0);
                        setAnimTrackTime(anim.charSet, 0,anim.duration);
                        disableAnimTrack(anim.charSet,0);
                    end;
                    setAnimTrackSpeedScale(anim.charSet, 0, anim.speed);
                    if not anim.loop then
                        anim.speed = anim.speed * -1;
                    end;
                    anim.inputBinding = getXMLString(self.xmlFile,basename.."inputBinding");
                    if anim.inputBinding ~= nil then
                        if InputBinding[anim.inputBinding] == nil then
                            anim.inputBinding = nil;
                        end;
                    end;
                    anim.helpText = getXMLString(self.xmlFile,basename.."helpText");
                    anim.helpTextOn = getXMLString(self.xmlFile,basename.."helpTextOn");
                    anim.helpTextOff = getXMLString(self.xmlFile,basename.."helpTextOff");
                    anim.outside = Utils.getNoNil(getXMLBool(self.xmlFile, basename.."outside"),false);
                    if anim.outside then
                        self.hasOutsideControls = true;
                        anim.maxDist = Utils.getNoNil(getXMLFloat(self.xmlFile, basename.."maxDist"),3.0);
                        anim.distNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(self.xmlFile, basename.."distNode"),"0>"));
                        anim.pir = false;
                    end;
                    anim.inside = Utils.getNoNil(getXMLBool(self.xmlFile, basename.."inside"),true);
                    if not (anim.inside or anim.outside) then
                        anim.inside = true;
                    end;
                    anim.running = false;
                    anim.state = false;
                    table.insert(self.i3danims,anim);
                else
                    print("Error: controlI3DAnims - ("..clipname..") clip not found");
                end;
            else
                print("Error: controlI3DAnims - ("..clipname..") charSet not found");
            end;
        else
            print("Error: controlI3DAnims - ("..clipname..") rootNode not found");
        end;
        i=i+1;
    end;
    self.runI3Danims = table.getn(self.i3danims) > 0;
    self.outsideMaxDist = 3.0;
    self.ci3daPlayerInRange = false;
    self.animsRunning = false;
end;

function controlI3DAnim:readStream(streamId, timestamp, connection)
    if self.runI3Danims then
        for i=1,table.getn(self.i3danims) do
            local anim=self.i3danims[i];
            local state = streamReadBool(streamId);
            local running = streamReadBool(streamId);
            if state ~= anim.state or running ~= anim.running then
                self:setI3DAnimState(i,state,true);
            end;
        end;
    end;
end;

function controlI3DAnim:writeStream(streamId, connection, dirtyMask)
    if self.runI3Danims then
        for i=1,table.getn(self.i3danims) do
            local anim=self.i3danims[i];
            streamWriteBool(streamId, anim.state);
            streamWriteBool(streamId, anim.running);
        end;
    end;
end;

function controlI3DAnim:update(dt)
    if self.runI3Danims then
        if self:getIsActiveForInput() or (self.ci3daPlayerInRange and self.hasOutsideControls) then
            for i=1,table.getn(self.i3danims) do
                local anim=self.i3danims[i];
                if anim.inputBinding ~= nil then
                    if (anim.inside and self:getIsActiveForInput() ) or (anim.outside and anim.pir and not self:getIsActiveForInput() ) then
                        if InputBinding.hasEvent(InputBinding[anim.inputBinding]) then
                            self:setI3DAnimState(i,not anim.state,false);
                        end;
                    end;
                    
                    if not self:getIsActive() and anim.pir and anim.outside then
                        if anim.helpText ~= nil then
                            g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpText), InputBinding[anim.inputBinding]);
                        elseif anim.helpTextOn ~= nil and not anim.state then
                            g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpTextOn), InputBinding[anim.inputBinding]);
                        elseif anim.helpTextOff ~= nil and anim.state then
                            g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpTextOff), InputBinding[anim.inputBinding]);
                        end;
                    end;
                    
                end;
            end;
        end;

    end;        
end;

function controlI3DAnim:updateTick(dt)
    if self.animsRunning then
        for i=1,table.getn(self.i3danims) do
            local anim=self.i3danims[i];
            if anim.running and not anim.loop then
                local tt = getAnimTrackTime(anim.charSet,0);
                if (anim.speed < 0 and tt < 0) or (anim.speed > 0 and tt > anim.duration) then
                    anim.running = false;
                    disableAnimTrack(anim.charSet,0);
                end;
            end;
        end;
    end;
    if self.hasOutsideControls and not self:getIsActive() and g_currentMission.player ~= nil then
        self.ci3daPlayerInRange = false;
        for i=1,table.getn(self.i3danims) do
            local anim = self.i3danims[i];
            if anim.outside then
                local x1,y1,z1 = getWorldTranslation(anim.distNode);
                local x2,y2,z2 = getWorldTranslation(g_currentMission.player.rootNode);
                local dist = Utils.vector2Length(x1-x2, z1-z2);
                anim.pir = false;
                if dist < anim.maxDist then
                    self.ci3daPlayerInRange = true;
                    anim.pir = true;
                end;
            end;
        end;
    end;
end;

function controlI3DAnim:draw()
    if self.runI3Danims then
        for i=1,table.getn(self.i3danims) do
            local anim=self.i3danims[i];
            if anim.inputBinding ~= nil and anim.inside then
                if anim.helpText ~= nil then
                    g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpText), InputBinding[anim.inputBinding]);
                elseif anim.helpTextOn ~= nil and not anim.state then
                    g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpTextOn), InputBinding[anim.inputBinding]);
                elseif anim.helpTextOff ~= nil and anim.state then
                    g_currentMission:addHelpButtonText(g_i18n:getText(anim.helpTextOff), InputBinding[anim.inputBinding]);
                end;
            end;
        end;
    end;
end;

function controlI3DAnim:setI3DAnimState(index,state,nes)
    local anim = self.i3danims[index];
    if state ~= anim.state then
        anim.state = state;
        if anim.loop then
            if state then
                enableAnimTrack(anim.charSet,0);
                anim.running = true;
                self.animsRunning = true;
            else
                disableAnimTrack(anim.charSet,0);
                anim.running = false;
            end;
        else
            anim.speed = anim.speed * -1;
            if anim.running then
                disableAnimTrack(anim.charSet,0);
            end;
            setAnimTrackSpeedScale(anim.charSet,0,anim.speed);
            enableAnimTrack(anim.charSet,0);
            anim.running = true;
            self.animsRunning = true;
        end;
        setI3DAnimStateEvent.sendEvent(self,index,state,nes);
    end;
end;

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

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

function controlI3DAnim:delete()
end;

setI3DAnimStateEvent = {};
setI3DAnimStateEvent_mt = Class(setI3DAnimStateEvent, Event);
InitEventClass(setI3DAnimStateEvent, "setI3DAnimStateEvent");

function setI3DAnimStateEvent:emptyNew()
    local self = Event:new(setI3DAnimStateEvent_mt);
    self.className="setI3DAnimStateEvent";
    return self;
end;

function setI3DAnimStateEvent:new(object, id, state)
        local self = setI3DAnimStateEvent:emptyNew()
        self.object = object;
        self.id = id;
        self.state = state;
        return self;
end;

function setI3DAnimStateEvent:readStream(streamId, connection)
        self.object = networkGetObject(streamReadInt32(streamId));
        self.id  = streamReadInt8(streamId);
        self.state = streamReadBool(streamId);
        self:run(connection);
end;

function setI3DAnimStateEvent:writeStream(streamId, connection)
            streamWriteInt32(streamId, networkGetObjectId(self.object));
        streamWriteInt8(streamId, self.id);
        streamWriteBool(streamId, self.state);
end;

function setI3DAnimStateEvent:run(connection)
    self.object:setI3DAnimState(self.id,self.state, true);
  if not connection:getIsServer() then
      g_server:broadcastEvent(setI3DAnimStateEvent:new(self.object, self.id, self.state), nil, connection, self.object);
  end;    
end;

function setI3DAnimStateEvent.sendEvent(vehicle, id, state, nes)
    if nes == nil or nes == false then
        if g_server ~= nil then
            g_server:broadcastEvent(setI3DAnimStateEvent:new(vehicle, id, state), nil, nil, vehicle);
        else
            g_client:getServerConnection():sendEvent(setI3DAnimStateEvent:new(vehicle, id, state));
        end;
    end;
end;
