--[[
FlieglTransportPack

Class for my Fliegl Transportpack to fix some stuff!

Author:		Ifko[nator]
Datum:		15.08.2019
Version:	v1.0

History:	v1.0 @ 15.08.2019 - initial implementation in FS 19
			-------------------------------------------------------------------------------------------------------------------------------------------------------------
]]

FlieglTransportPack = {};

TensionBelts.NUM_SEND_BITS = 16;

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

function FlieglTransportPack.registerEventListeners(vehicleType)
    local functionNames = {
        "onLoad",
        "onUpdate"
    };
    
    for _, functionName in ipairs(functionNames) do
        SpecializationUtil.registerEventListener(vehicleType, functionName, FlieglTransportPack);
    end;
end;

function FlieglTransportPack:onLoad(savegame)
    if SpecializationUtil.hasSpecialization(TensionBelts, self.specializations) then    
        TensionBelts.onLoad = Utils.overwrittenFunction(TensionBelts.onLoad, FlieglTransportPack.onLoadTensionBeltsFix);
    end;
    
    self.getFullName = Utils.overwrittenFunction(self.getFullName, FlieglTransportPack.getFullName);

	self.allowShowBrandOnName = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.storeData.allowShowBrandOnName"), true);
end;

function FlieglTransportPack:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
    local specDischargeable = self.spec_dischargeable;

    if specDischargeable ~= nil then
        for fillUnit, _ in ipairs(self:getFillUnits()) do
            specDischargeable.currentDischargeNode.stopDischargeOnEmpty = self:getFillUnitFillLevel(fillUnit) > 0;
        end;
    end;
end;

function FlieglTransportPack:onLoadTensionBeltsFix(superFunc, savegame)
    local specTensionBelts = self.spec_tensionBelts;
    local tensionBeltConfigurationId = Utils.getNoNil(self.configurations["tensionBelts"], 1);
    local configKey = string.format("vehicle.tensionBelts.tensionBeltsConfigurations.tensionBeltsConfiguration(%d).tensionBelts", tensionBeltConfigurationId - 1);

    ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.tensionBelts.tensionBeltsConfigurations.tensionBeltsConfiguration", tensionBeltConfigurationId , self.components, self);

    specTensionBelts.hasTensionBelts = true;

    if not hasXMLProperty(self.xmlFile, configKey) then
        specTensionBelts.hasTensionBelts = false;

        return;
    end;

    specTensionBelts.belts = {};
    specTensionBelts.activatable = TensionBeltsActivatable:new(self);
    specTensionBelts.totalInteractionRadius = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey .. "#totalInteractionRadius"), 6);
    specTensionBelts.interactionRadius = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey .. "#interactionRadius"), 1);
    specTensionBelts.interactionBaseNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey .. "#interactionBasenode"), self.i3dMappings), self.rootNode);
    specTensionBelts.activationTrigger = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey .. "#activationTrigger"), self.i3dMappings);

    if specTensionBelts.activationTrigger ~= nil then
        addTrigger(specTensionBelts.activationTrigger, "tensionBeltActivationTriggerCallback", self);
    end;

    specTensionBelts.isPlayerInTrigger = false;
    specTensionBelts.checkSizeOffsets = {0 * 0.5, 5 * 0.5, 3 * 0.5};
    specTensionBelts.numObjectsIntensionBeltRange = 0;

    local tensionBeltType = Utils.getNoNil(getXMLString(self.xmlFile, configKey .. "#tensionBeltType"), "basic");
    local beltData = g_tensionBeltManager:getBeltData(tensionBeltType);

    if beltData ~= nil then
        specTensionBelts.tensionBelts = {};
        specTensionBelts.singleBelts = {};
        specTensionBelts.sortedBelts = {};

        specTensionBelts.width = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey .. "#width"), 0.15);
        specTensionBelts.ratchetPosition = getXMLFloat(self.xmlFile, configKey .. "#ratchetPosition");
        specTensionBelts.useHooks = Utils.getNoNil(getXMLBool(self.xmlFile, configKey .. "#useHooks"), true);
        specTensionBelts.maxEdgeLength = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey .. "#maxEdgeLength"), 0.1);
        specTensionBelts.geometryBias = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey .. "#geometryBias"), 0.01);
        specTensionBelts.defaultOffsetSide = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey .. "#defaultOffsetSide"), 0.1);
        specTensionBelts.defaultOffset = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey .. "#defaultOffset"), 0);
        specTensionBelts.defaultHeight = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey .. "#defaultHeight"), 5);

        specTensionBelts.beltData = beltData;

        specTensionBelts.linkNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey .. "#linkNode"), self.i3dMappings);

        specTensionBelts.rootNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey .. "#rootNode"), self.i3dMappings), self.components[1].node);
        specTensionBelts.jointNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey .. "#jointNode"), self.i3dMappings), specTensionBelts.rootNode);

        specTensionBelts.checkTimerDuration = 500;
        specTensionBelts.checkTimer = specTensionBelts.checkTimerDuration;

        if getRigidBodyType(specTensionBelts.jointNode) ~= "Dynamic" and getRigidBodyType(specTensionBelts.jointNode) ~= "Kinematic" then
            print("Error: Given jointNode '" .. getName(specTensionBelts.jointNode) .. "' has invalid rigidBodyType. Have to be 'Dynamic' or 'Kinematic'! Using '" .. getName(self.components[1].node) .. "' instead!");

            specTensionBelts.jointNode = self.components[1].node;
        end;

        local rigidBodyType = getRigidBodyType(specTensionBelts.jointNode);

        specTensionBelts.isDynamic = rigidBodyType == "Dynamic";

        local x, y, z = localToLocal(specTensionBelts.linkNode, specTensionBelts.jointNode, 0, 0, 0);
        local rx, ry, rz = localRotationToLocal(specTensionBelts.linkNode, specTensionBelts.jointNode, 0, 0, 0);

        specTensionBelts.linkNodePosition = {x, y, z};
        specTensionBelts.linkNodeRotation = {rx, ry, rz};

        local tensionBeltNumber = 0;

        while true do
            local key = string.format(configKey .. ".tensionBelt(%d)", tensionBeltNumber);

            if not hasXMLProperty(self.xmlFile, key) then
                break;
            end;

            if #specTensionBelts.sortedBelts == 2^TensionBelts.NUM_SEND_BITS then
                print("Warning: Max number of tension belts is '" .. 2 ^ TensionBelts.NUM_SEND_BITS .. "'!");

                break;
            end;

            local startNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. "#startNode"), self.i3dMappings);
            local endNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. "#endNode"), self.i3dMappings);

            if startNode ~= nil and endNode ~= nil then
                local x, _, _ = localToLocal(endNode, startNode, 0, 0, 0);

                if math.abs(x) < 0.0001 then
                    if specTensionBelts.linkNode == nil then
                        specTensionBelts.linkNode = getParent(startNode);
                    end;

                    if specTensionBelts.startNode == nil then
                        specTensionBelts.startNode = startNode;
                    end;

                    specTensionBelts.endNode = endNode;

                    local offsetLeft = getXMLFloat(self.xmlFile, key .. "#offsetLeft");
                    local offsetRight = getXMLFloat(self.xmlFile, key .. "#offsetRight");
                    local offset = getXMLFloat(self.xmlFile, key .. "#offset");
                    local height = getXMLFloat(self.xmlFile, key .. "#height");

                    local intersectionNodes = {};

                    local intersectionNodeNumber = 0;

                    while true do
                        local intersectionKey = string.format(key .. ".intersectionNode(%d)", intersectionNodeNumber);

                        if not hasXMLProperty(self.xmlFile, intersectionKey) then
                            break;
                        end;

                        local node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, intersectionKey .. "#node"), self.i3dMappings);

                        if node ~= nil then
                            table.insert(intersectionNodes, node);
                        end;

                        intersectionNodeNumber = intersectionNodeNumber + 1;
                    end;

                    local belt = {
                        id = tensionBeltNumber + 1, 
                        startNode = startNode, 
                        endNode = endNode, 
                        offsetLeft = offsetLeft, 
                        offsetRight = offsetRight, 
                        offset = offset, 
                        height = height, 
                        mesh = nil, 
                        intersectionNodes = intersectionNodes, 
                        dummy = nil, 
                        objectsToMount = nil
                    };

                    specTensionBelts.singleBelts[belt] = belt;

                    table.insert(specTensionBelts.sortedBelts, belt);
                else
                    print("Warning: x position of endNode need to be 0 for tension belt '" .. key .. "' in '" .. self.configFileName .. "'!");
                end;
            end;

            tensionBeltNumber = tensionBeltNumber + 1;
        end;

        local minX, minZ = math.huge, math.huge;
        local maxX, maxZ = -math.huge, -math.huge;

        for _, belt in pairs(specTensionBelts.singleBelts) do
            local sx, _, sz = localToLocal(belt.startNode, specTensionBelts.interactionBaseNode, 0, 0, 0);
            local ex, _, ez = localToLocal(belt.endNode, specTensionBelts.interactionBaseNode, 0, 0, 0);

            minX = math.min(minX, sx, ex);
            minZ = math.min(minZ, sz, ez);
            maxX = math.max(maxX, sx, ex);
            maxZ = math.max(maxZ, sz, ez);
        end;

        specTensionBelts.interactionBasePointX = (maxX + minX) / 2;
        specTensionBelts.interactionBasePointZ = (maxZ + minZ) / 2;

        for _, belt in pairs(specTensionBelts.singleBelts) do
            local sx, _, sz = localToLocal(belt.startNode, specTensionBelts.interactionBaseNode, 0, 0, 0);
            local sl = MathUtil.vector2Length(specTensionBelts.interactionBasePointX - sx, specTensionBelts.interactionBasePointZ - sz) + 1;
            local el = MathUtil.vector2Length(specTensionBelts.interactionBasePointX - sx, specTensionBelts.interactionBasePointZ - sz) + 1;

            specTensionBelts.totalInteractionRadius = math.max(specTensionBelts.totalInteractionRadius, sl, el);
        end;

        specTensionBelts.hasTensionBelts = #specTensionBelts.sortedBelts > 0;
    else
        print("Warning: No belt data found for tension belts in '" .. self.configFileName .. "'!");
    end;

    specTensionBelts.checkBoxes = {};
    specTensionBelts.objectsToJoint = {};
    
    specTensionBelts.isPlayerInRange = false;
    specTensionBelts.currentBelt = nil;
    specTensionBelts.areBeltsFasten = false;
end;

function FlieglTransportPack:getFullName(superFunc)
    local name = self:getName()
    local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName);
	
	if storeItem ~= nil then
        local brand = g_brandManager:getBrandByIndex(storeItem.brandIndex);
		
		if brand ~= nil and self.allowShowBrandOnName then
            name = brand.title .. " " .. name;
        end;
    end;
	
	if self:getIsAIActive() then
        name = name .. " (" .. g_i18n:getText("ui_helper") .. " " .. self:getCurrentHelper().name .. ")";
	end;
	
    return name;
end;