--
-- CustomTrackSystem
--
-- @author:        Xentro (Marcus@Xentro.se)
-- @website:    www.Xentro.se
-- @history:    v1.0 - 2015-03-01 - Initial implementation
--                 v2.0 - 2016-12-10 - FS 17 Convert
-- 

CustomTrackSystem = {};

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

function CustomTrackSystem:preLoad(savegame)
    local file = getXMLString(self.xmlFile, "vehicle.CustomTrackSystem#file");
    if file ~= nil and file ~= "" and g_currentMission.tireTrackSystem ~= nil then
        file = Utils.getFilename(file, self.baseDirectory);
        
        if fileExists(file) then
            local i3dNode = Utils.loadSharedI3DFile(file, nil, false, false, false);
            
            if i3dNode ~= 0 then
                local system = TireTrackSystem:new();
                local node = getChildAt(i3dNode, 0);
                
                if node ~= nil and system:load(node) then
                    self.customTrackSystem = system;
                    self.customTrackFile = file;
                    
                    if g_currentMission.customTrackSystem == nil then
                        g_currentMission.customTrackSystem = {};
                    end;
                    
                    table.insert(g_currentMission.customTrackSystem, self.customTrackSystem);
                else
                    system:delete();
                    print("CustomTrackSystem - Error: Couldn't create new track system");
                end;
            end;
        else
            print("CustomTrackSystem - Error: Can't load " .. tostring(file));
        end;
    end;
    
    self.loadDynamicWheelDataFromXML = Utils.overwrittenFunction(self.loadDynamicWheelDataFromXML, CustomTrackSystem.loadDynamicWheelDataFromXML);
    self.loadWheelDataFromXML = Utils.overwrittenFunction(self.loadWheelDataFromXML, CustomTrackSystem.loadWheelDataFromXML);
end;

function CustomTrackSystem:load(savegame)
end;

function CustomTrackSystem:delete()
    if self.customTrackSystem ~= nil then
        for _, wheel in ipairs(self.wheels) do
            if wheel.customTrackIndex ~= nil then
                self.customTrackSystem:destroyTrack(wheel.customTrackIndex);
            end;
            
            if wheel.additionalWheels ~= nil then
                for _, additionalWheel in pairs(wheel.additionalWheels) do
                    if additionalWheel.customTrackIndex ~= nil then
                        self.customTrackSystem:destroyTrack(additionalWheel.customTrackIndex);
                    end;
                end;
            end;
        end;
        
        -- Remove tracks if we dont have Game Extension mod
        if not g_currentMission.customTrackController then
            for i = 1, #g_currentMission.customTrackSystem do
                if g_currentMission.customTrackSystem[i] == self.customTrackSystem then
                    table.remove(g_currentMission.customTrackSystem, i);
                    break;
                end;
            end;
            
            if #g_currentMission.customTrackSystem == 0 then
                g_currentMission.customTrackSystem = nil;
            end;
            
            self.customTrackSystem:delete();
            self.customTrackSystem = nil;
        end;
    end;
    
    if customTrackFile ~= nil then
        Utils.releaseSharedI3DFile(self.customTrackFile, nil, true);
    end;
end;

function CustomTrackSystem:readStream(streamId, connection)
    if self.customTrackSystem ~= nil and connection:getIsServer() then
        for i=1, table.getn(self.wheels) do
            local wheel = self.wheels[i];
            
            if wheel.customTrackIndex ~= nil then
                wheel.contact = streamReadUIntN(streamId, 2);
            end;
        end;
    end;
end;

function CustomTrackSystem:writeStream(streamId, connection)
    if self.customTrackSystem ~= nil and not connection:getIsServer() then
        for i = 1, table.getn(self.wheels) do
            local wheel = self.wheels[i];
            
            if wheel.customTrackIndex ~= nil then
                streamWriteUIntN(streamId, wheel.contact, 2);
            end;
        end;
    end;
end;

function CustomTrackSystem:readUpdateStream(streamId, timestamp, connection)
    CustomTrackSystem.readStream(self, streamId, connection);
end;

function CustomTrackSystem:writeUpdateStream(streamId, connection, dirtyMask)
    CustomTrackSystem.writeStream(self, streamId, connection);
end;

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

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

function CustomTrackSystem:update(dt)
    if self.customTrackSystem ~= nil then
        if self.firstTimeRun then
            if self.updateWheelsTime > 0 then
                for p, wheel in ipairs(self.wheels) do
                    if wheel.customTrackIndex ~= nil then
                        local wheelSpeed = 0;
                        local color;
                        
                        if self.isServer and self.isAddedToPhysics then
                            wheelSpeed = getWheelShapeAxleSpeed(wheel.node, wheel.wheelShape);
                        else
                            if self.movingDirection > 0 then
                                wheelSpeed = 1;
                            elseif self.movingDirection < 0 then
                                wheelSpeed = -1;
                            end;
                        end;
                        
                        if wheel.contact == Vehicle.WHEEL_GROUND_CONTACT then
                            color = wheel.lastColor;
                        elseif wheel.contact == Vehicle.WHEEL_OBJ_CONTACT then
                            if wheel.dirtAmount > 0 then
                                color = wheel.lastColor;
                                color[4] = 0; -- no depth to tire tracks on road etc.
                            end;
                        end;
                    
                        if color ~= nil then
                            local ux, uy, uz = localDirectionToWorld(self.rootNode, 0, 1, 0);
                            local wx, wy, wz = wheel.netInfo.x, wheel.netInfo.y, wheel.netInfo.z;
                            wy = wy - wheel.radius;
                            wx = wx + wheel.xOffset;
                            wx, wy, wz = localToWorld(wheel.node, wx, wy, wz);
                            
                            self.customTrackSystem:addTrackPoint(wheel.customTrackIndex, wx, wy, wz, ux, uy, uz, color[1], color[2], color[3], wheel.dirtAmount, color[4], wheelSpeed);
                            
                            if wheel.additionalWheels ~= nil then
                                for _, additionalWheel in pairs(wheel.additionalWheels) do
                                    if additionalWheel.customTrackIndex ~= nil then
                                        local wx, wy, wz = worldToLocal(wheel.node, getWorldTranslation(additionalWheel.wheelTire));
                                        wy = wy - wheel.radius;
                                        wx = wx + wheel.xOffset;
                                        wx, wy, wz = localToWorld(wheel.node, wx,wy,wz);
                                        self.customTrackSystem:addTrackPoint(additionalWheel.customTrackIndex, wx, wy, wz, ux, uy, uz, color[1], color[2], color[3], wheel.dirtAmount, color[4], wheelSpeed);
                                    end
                                end;
                            end;
                        else
                            self.customTrackSystem:cutTrack(wheel.customTrackIndex);
                            
                            if wheel.additionalWheels ~= nil then
                                for _, additionalWheel in pairs(wheel.additionalWheels) do
                                    if additionalWheel.customTrackIndex ~= nil then
                                        g_currentMission.tireTrackSystem:cutTrack(additionalWheel.customTrackIndex);
                                    end
                                end;
                            end;
                        end;
                    end;
                end;
            else
                for p, wheel in ipairs(self.wheels) do
                    if wheel.customTrackIndex ~= nil then
                        self.customTrackSystem:cutTrack(wheel.customTrackIndex);
                        
                        if wheel.additionalWheels ~= nil then
                            for _, additionalWheel in pairs(wheel.additionalWheels) do
                                if additionalWheel.customTrackIndex ~= nil then
                                    g_currentMission.tireTrackSystem:cutTrack(additionalWheel.customTrackIndex);
                                end
                            end;
                        end;
                    end;
                end;
            end;
        end;
    end;
end;

function CustomTrackSystem:updateTick(dt)
end;

function CustomTrackSystem:draw()
end;

function CustomTrackSystem:loadTrackIndex(wheel, index)
    if index ~= nil and g_currentMission.tireTrackSystem ~= nil and self.customTrackSystem ~= nil then
        if wheel.tireTrackIndex == nil then
            wheel.customTrackIndex = self.customTrackSystem:createTrack(wheel.width, index);
        else
            print("CustomTrackSystem - Warning: You can't use the default track system along with CustomTrackSystem on wheel, CustomTrackSystem have been deactivated for this wheel.");
        end;
    end;
end;

-- Wheel data in vehicle xml
function CustomTrackSystem:loadDynamicWheelDataFromXML(superFunc, xmlFile, key, wheelnamei, wheel)
    local state;
    
    if superFunc ~= nil then
        state = superFunc(self, xmlFile, key, wheelnamei, wheel);
    end;
    
    local fallbackOldKey = "vehicle.wheels";
    local customTrackIndex = Vehicle.getConfigurationValue(xmlFile, key, wheelnamei, "#customTrackAtlasIndex", getXMLInt, nil, nil, fallbackOldKey);
    CustomTrackSystem.loadTrackIndex(self, wheel, customTrackIndex);
    
    return state;
end;

-- Wheel data in dedicated wheel xml
function CustomTrackSystem:loadWheelDataFromXML(superFunc, wheel, xmlFilename, wheelConfigIndex, isLeft, isRealWheel, xRotOffset)
    local state;
    if superFunc ~= nil then
        state = superFunc(self, wheel, xmlFilename, wheelConfigIndex, isLeft, isRealWheel, xRotOffset);
    end;
    
    local xmlFilename = Utils.getFilename(xmlFilename, self.baseDirectory);
    local xmlFile = loadXMLFile("TempConfig", xmlFilename);
    
    if xmlFile ~= nil then
        local customTrackIndex = getXMLInt(xmlFile, "wheel.tire#customTrackAtlasIndex");
        CustomTrackSystem.loadTrackIndex(self, wheel, customTrackIndex);
    end;
    
    delete(xmlFile);
    
    return state;
end;


-- remove tracks from surface if cultivated etc
if not Utils.CustomTrackSystemTrackFix20161208 then
    Utils.CustomTrackSystemTrackFix20161208 = true;
    
    local udc = Utils.updateDestroyCommonArea;
    Utils.updateDestroyCommonArea = function(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, limitToField)
        if g_currentMission.customTrackSystem ~= nil then
            for i, v in ipairs(g_currentMission.customTrackSystem) do
                v:eraseParallelogram(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ);
            end;
        end;
        
        udc(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, limitToField);
    end;
    
    local usa = Utils.updateSowingArea;
    Utils.updateSowingArea = function(fruitId, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, angle, useDirectPlanting, plantValue)
        local ids = g_currentMission.fruits[fruitId]

        if ids == nil or ids.id == 0 then
            return 0;
        end;
    
        if g_currentMission.customTrackSystem ~= nil then
            for i, v in ipairs(g_currentMission.customTrackSystem) do
                v:eraseParallelogram(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ);
            end;
        end;
        
        return usa(fruitId, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, angle, useDirectPlanting, plantValue);
    end;
end;