waitUntil {!isNil "save_is_loaded"};
waitUntil {!isNil "KP_liberation_logistics"};
waitUntil {save_is_loaded};

["Logistic management started", "LOGISTIC"] call KPLIB_fnc_log;

KP_liberation_convoy_ambush_inProgress = false;
KP_liberation_convoy_ambush_check = 0;
private _start = 0;
while {GRLIB_endgame == 0} do {

    if (((count (allPlayers - entities "HeadlessClient_F")) > 0) && ((count KP_liberation_logistics) > 0)) then {
        _start = diag_tickTime;
        if (KP_liberation_logistic_debug > 0) then {[format ["Logistic interval started: %1", diag_tickTime], "LOGISTIC"] call KPLIB_fnc_log;};

        private _tempLogistics = +KP_liberation_logistics;

        {
            private _locPos = -1;
            private _locRes = -1;
            switch (_x select 7) do {
                case 0: {};
                case 1;
                case 3: {
                    if ((_x select 8) > 1) then {
                        switch (_x select 7) do {case 1: {_locPos = 2; _locRes = 4;}; case 3: {_locPos = 3; _locRes = 5;};};
                        switch (_x select 9) do {case 2: {_x set [9,0];}; case 3: {_x set [9,1];};};
                        private _storage_areas = nearestObjects [(_x select _locPos), [KP_liberation_small_storage_building, KP_liberation_large_storage_building], 150];

                        if (((_x select 9) == 0) && !((_x select 6) isEqualTo [0,0,0])) then {

                            if ((count (_storage_areas)) == 0) exitWith {_x set [9,2];};

                            private _toProcess = ceil ((ceil (((_x select 6) select 0) / 100)) + (ceil (((_x select 6) select 1) / 100)) + (ceil (((_x select 6) select 2) / 100)));
                            if (_toProcess > 3) then {_toProcess = 3;};
                            private _spaceSum = 0;
                            {
                                if (typeOf _x == KP_liberation_large_storage_building) then {
                                    _spaceSum = _spaceSum + (count KP_liberation_large_storage_positions) - (count (attachedObjects _x));
                                };
                                if (typeOf _x == KP_liberation_small_storage_building) then {
                                    _spaceSum = _spaceSum + (count KP_liberation_small_storage_positions) - (count (attachedObjects _x));
                                };
                            } forEach _storage_areas;

                            if (_spaceSum < _toProcess) exitWith {_x set [9,2];};

                            _x set [8,((_x select 8) - 1)];
                            private _currentIndex = _forEachIndex;
                            private _processed = 0;
                            while {_processed < _toProcess} do {
                                {
                                    private _space = 0;
                                    if (typeOf _x == KP_liberation_large_storage_building) then {
                                        _space = (count KP_liberation_large_storage_positions) - (count (attachedObjects _x));
                                    };
                                    if (typeOf _x == KP_liberation_small_storage_building) then {
                                        _space = (count KP_liberation_small_storage_positions) - (count (attachedObjects _x));
                                    };

                                    if ((_space > 0) && ((((_tempLogistics select _currentIndex) select 6) select 0) > 0)) then {
                                        private _amount = 100;
                                        if (((((_tempLogistics select _currentIndex) select 6) select 0) / 100) < 1) then {
                                            _amount = ((_tempLogistics select _currentIndex) select 6) select 0;
                                        };
                                        (_tempLogistics select _currentIndex) set [6,
                                            [(((_tempLogistics select _currentIndex) select 6) select 0) - _amount,
                                            (((_tempLogistics select _currentIndex) select 6) select 1),
                                            (((_tempLogistics select _currentIndex) select 6) select 2)]
                                        ];
                                        private _crate = [KP_liberation_supply_crate, _amount, getPos _x] call KPLIB_fnc_createCrate;
                                        [_crate, _x] call KPLIB_fnc_crateToStorage;
                                        _processed = _processed + 1;
                                        _space = _space - 1;
                                    };
                                    if (_processed >= _toProcess) exitWith {};

                                    if ((_space > 0) && ((((_tempLogistics select _currentIndex) select 6) select 1) > 0)) then {
                                        private _amount = 100;
                                        if (((((_tempLogistics select _currentIndex) select 6) select 1) / 100) < 1) then {
                                            _amount = ((_tempLogistics select _currentIndex) select 6) select 1;
                                        };
                                        (_tempLogistics select _currentIndex) set [6,
                                                [(((_tempLogistics select _currentIndex) select 6) select 0),
                                                (((_tempLogistics select _currentIndex) select 6) select 1) - _amount,
                                                (((_tempLogistics select _currentIndex) select 6) select 2)]
                                            ];
                                        private _crate = [KP_liberation_ammo_crate, _amount, getPos _x] call KPLIB_fnc_createCrate;
                                        [_crate, _x] call KPLIB_fnc_crateToStorage;
                                        _processed = _processed + 1;
                                        _space = _space - 1;
                                    };
                                    if (_processed >= _toProcess) exitWith {};

                                    if ((_space > 0) && ((((_tempLogistics select _currentIndex) select 6) select 2) > 0)) then {
                                        private _amount = 100;
                                        if (((((_tempLogistics select _currentIndex) select 6) select 2) / 100) < 1) then {
                                            _amount = ((_tempLogistics select _currentIndex) select 6) select 2;
                                        };
                                        (_tempLogistics select _currentIndex) set [6,
                                                [(((_tempLogistics select _currentIndex) select 6) select 0),
                                                (((_tempLogistics select _currentIndex) select 6) select 1),
                                                (((_tempLogistics select _currentIndex) select 6) select 2) - _amount]
                                            ];
                                        private _crate = [KP_liberation_fuel_crate, _amount, getPos _x] call KPLIB_fnc_createCrate;
                                        [_crate, _x] call KPLIB_fnc_crateToStorage;
                                        _processed = _processed + 1;
                                        _space = _space - 1;
                                    };
                                    if (_processed >= _toProcess) exitWith {};
                                } forEach _storage_areas;
                            };
                            please_recalculate = true;
                            if (KP_liberation_logistic_debug > 0) then {[format ["Logistic Group Update: %1", _x], "LOGISTIC"] call KPLIB_fnc_log;};
                        } else {
                            _x set [9,1];
                        };

                        if (((_x select 9) == 1) && !((_x select _locRes) isEqualTo [0,0,0])) then {

                            if ((count (_storage_areas)) == 0) exitWith {_x set [9,3];};

                            private _supplyValue = 0;
                            private _ammoValue = 0;
                            private _fuelValue = 0;

                            {
                                {
                                    switch ((typeOf _x)) do {
                                        case KP_liberation_supply_crate: {_supplyValue = _supplyValue + (_x getVariable ["KP_liberation_crate_value",0]);};
                                        case KP_liberation_ammo_crate: {_ammoValue = _ammoValue + (_x getVariable ["KP_liberation_crate_value",0]);};
                                        case KP_liberation_fuel_crate: {_fuelValue = _fuelValue + (_x getVariable ["KP_liberation_crate_value",0]);};
                                        default {[format ["Invalid object (%1) at storage area", (typeOf _x)], "ERROR"] call KPLIB_fnc_log;};
                                    };
                                } forEach (attachedObjects _x);
                            } forEach _storage_areas;

                            private _toProcess = ceil ((ceil (((_x select _locRes) select 0) / 100)) + (ceil (((_x select _locRes) select 1) / 100)) + (ceil (((_x select _locRes) select 2) / 100)));
                            if (_toProcess > 3) then {_toProcess = 3;};

                            private _maxGetSupply = ((_x select _locRes) select 0);
                            if (_maxGetSupply > 300) then {_maxGetSupply = 300;};
                            private _maxGetAmmo = ((_x select _locRes) select 1);
                            if (_maxGetAmmo > 300) then {_maxGetAmmo = 300;};
                            private _maxGetFuel = ((_x select _locRes) select 2);
                            if (_maxGetFuel > 300) then {_maxGetFuel = 300;};

                            private _getSupply = 0;
                            private _getAmmo = 0;
                            private _getFuel = 0;
                            private _i = 0;
                            private _j = 0;

                            while {(_i < _toProcess) && (_j < _toProcess)} do {
                                if ((_maxGetSupply - _getSupply) > 0) then {
                                    if ((floor ((_maxGetSupply - _getSupply) / 100)) > 0) then {
                                        if ((_supplyValue - _getSupply) >= 100) then {
                                            _getSupply = _getSupply + 100;
                                            _i = _i + 1;
                                        };
                                    } else {
                                        if ((_maxGetSupply - _getSupply) <= (_supplyValue - _getSupply)) then {
                                            _getSupply = _maxGetSupply;
                                            _i = _i + 1;
                                        };
                                    };
                                };
                                if (((_maxGetAmmo - _getAmmo) > 0) && (_i < _toProcess)) then {
                                    if ((floor ((_maxGetAmmo - _getAmmo) / 100)) > 0) then {
                                        if ((_ammoValue - _getAmmo) >= 100) then {
                                            _getAmmo = _getAmmo + 100;
                                            _i = _i + 1;
                                        };
                                    } else {
                                        if ((_maxGetAmmo - _getAmmo) <= (_ammoValue - _getAmmo)) then {
                                            _getAmmo = _maxGetAmmo;
                                            _i = _i + 1;
                                        };
                                    };
                                };
                                if (((_maxGetFuel - _getFuel) > 0) && (_i < _toProcess)) then {
                                    if ((floor ((_maxGetFuel - _getFuel) / 100)) > 0) then {
                                        if ((_fuelValue - _getFuel) >= 100) then {
                                            _getFuel = _getFuel + 100;
                                            _i = _i + 1;
                                        };
                                    } else {
                                        if ((_maxGetFuel - _getFuel) <= (_fuelValue - _getFuel)) then {
                                            _getFuel = _maxGetFuel;
                                            _i = _i + 1;
                                        };
                                    };
                                };
                                _j = _j + 1;
                            };

                            if ((_j == _toProcess) && (_i != _toProcess)) exitWith {_x set [9,3];};

                            _x set [_locRes,[((_x select _locRes) select 0) - _getSupply,((_x select _locRes) select 1) - _getAmmo,((_x select _locRes) select 2) - _getFuel]];
                            _x set [6,[((_x select 6) select 0) + _getSupply,((_x select 6) select 1) + _getAmmo,((_x select 6) select 2) + _getFuel]];
                            _x set [8,((_x select 8) - 1)];

                            {
                                private _storage_positions = [];
                                private _storedCrates = (attachedObjects _x);
                                reverse _storedCrates;

                                {
                                    private _crateValue = _x getVariable ["KP_liberation_crate_value",0];

                                    switch ((typeOf _x)) do {
                                        case KP_liberation_supply_crate: {
                                            if (_getSupply > 0) then {
                                                if (_crateValue > _getSupply) then {
                                                    _crateValue = _crateValue - _getSupply;
                                                    _x setVariable ["KP_liberation_crate_value", _crateValue, true];
                                                    _getSupply = 0;
                                                } else {
                                                    detach _x;
                                                    deleteVehicle _x;
                                                    _getSupply = _getSupply - _crateValue;
                                                };
                                            };
                                        };
                                        case KP_liberation_ammo_crate: {
                                            if (_getAmmo > 0) then {
                                                if (_crateValue > _getAmmo) then {
                                                    _crateValue = _crateValue - _getAmmo;
                                                    _x setVariable ["KP_liberation_crate_value", _crateValue, true];
                                                    _getAmmo = 0;
                                                } else {
                                                    detach _x;
                                                    deleteVehicle _x;
                                                    _getAmmo = _getAmmo - _crateValue;
                                                };
                                            };
                                        };
                                        case KP_liberation_fuel_crate: {
                                            if (_getFuel > 0) then {
                                                if (_crateValue > _getFuel) then {
                                                    _crateValue = _crateValue - _getFuel;
                                                    _x setVariable ["KP_liberation_crate_value", _crateValue, true];
                                                    _getFuel = 0;
                                                } else {
                                                    detach _x;
                                                    deleteVehicle _x;
                                                    _getFuel = _getFuel - _crateValue;
                                                };
                                            };
                                        };
                                        default {[format ["Invalid object (%1) at storage area", (typeOf _x)], "ERROR"] call KPLIB_fnc_log;};
                                    };
                                } forEach _storedCrates;

                                ([_x] call KPLIB_fnc_getStoragePositions) params ["_storage_positions"];

                                private _area = _x;
                                _i = 0;
                                {
                                    _height = [typeOf _x] call KPLIB_fnc_getCrateHeight;
                                    detach _x;
                                    _x attachTo [_area, [(_storage_positions select _i) select 0, (_storage_positions select _i) select 1, _height]];
                                    _i = _i + 1;
                                } forEach attachedObjects (_x);

                                if ((_getSupply == 0) && (_getAmmo == 0) && (_getFuel == 0)) exitWith {};

                            } forEach _storage_areas;

                            if (KP_liberation_logistic_debug > 0) then {[format ["Logistic Group Update: %1", _x], "LOGISTIC"] call KPLIB_fnc_log;};
                        };
                    } else {
                        private _nextState = 0;
                        private _time = -1;
                        if (((_x select 4) isEqualTo [0,0,0]) && ((_x select 5) isEqualTo [0,0,0]) && ((_x select 6) isEqualTo [0,0,0])) then {
                            _x set [2, [0,0,0]];
                            _x set [3, [0,0,0]];
                        } else {
                            _nextState = switch (_x select 7) do {case 1: {2}; case 3: {4};};
                            _time = ceil (((_x select 2) distance2D (_x select 3)) / 400);
                        };

                        _x set [7,_nextState];
                        _x set [8,_time];
                        _x set [9,0];

                        if (KP_liberation_logistic_debug > 0) then {[format ["Logistic Group Update: %1", _x], "LOGISTIC"] call KPLIB_fnc_log;};
                    };
                };
                case 2;
                case 4: {
                    if ((_x select 8) > 1) then {

                        if (((_x select 8) <= ((ceil (((_x select 2) distance2D (_x select 3)) / 400)) - 3)) && ((_x select 8) >= 3) && !((_x select 6) isEqualTo [0,0,0]) && !KP_liberation_convoy_ambush_inProgress && (KP_liberation_civ_rep <= -25) && (((_x select 8) % 2) == 0)) then {
                            private _dice = round (random 100);
                            private _chance = KP_liberation_convoy_ambush_chance;
                            if (chance > 0) then {
                                _chance = _chance + ([] call KPLIB_fnc_crGetMulti);
                            };
                            if (KP_liberation_asymmetric_debug > 0) then {[format ["Logistic convoy %1: ambush possible - current ETA: %2 - Dice: %3 - Chance: %4", (_x select 0), (_x select 8), _dice, _chance], "ASYMMETRIC"] call KPLIB_fnc_log;};
                            if (_dice <= _chance) then {
                                private _convoy = +_x;
                                sleep 0.1;
                                [_convoy] spawn logistic_convoy_ambush;
                                waitUntil {sleep 0.1; KP_liberation_convoy_ambush_check != 0};
                                if (KP_liberation_convoy_ambush_check == 2) then {
                                    _x set [1,0];
                                    _x set [2,[0,0,0]];
                                    _x set [3,[0,0,0]];
                                    _x set [4,[0,0,0]];
                                    _x set [5,[0,0,0]];
                                    _x set [6,[0,0,0]];
                                    _x set [7,0];
                                    _x set [8,-1];
                                } else {
                                    _x set [8,((_x select 8) - 1)];
                                    KP_liberation_convoy_ambush_check = 0;
                                };
                            } else {
                                _x set [8,((_x select 8) - 1)];
                            };
                        } else {
                            _x set [8,((_x select 8) - 1)];
                        };

                        if (KP_liberation_logistic_debug > 0) then {[format ["Logistic Group Update: %1", _x], "LOGISTIC"] call KPLIB_fnc_log;};

                    } else {
                        private _nextState = -1;
                        private _time = 0;
                        switch (_x select 7) do {
                            case 2: {
                                _nextState = 3;
                                _time = ceil (((ceil (((_x select 5) select 0) / 100)) + (ceil (((_x select 5) select 1) / 100)) + (ceil (((_x select 5) select 2) / 100))) / 3);
                            };
                            case 4: {
                                _nextState = 1;
                                _time = ceil (((ceil (((_x select 4) select 0) / 100)) + (ceil (((_x select 4) select 1) / 100)) + (ceil (((_x select 4) select 2) / 100))) / 3);
                            };
                        };
                        if (_time > (_x select 1)) then {_time = (_x select 1);};

                        _time = _time + (ceil (((ceil (((_x select 6) select 0) / 100)) + (ceil (((_x select 6) select 1) / 100)) + (ceil (((_x select 6) select 2) / 100))) / 3));
                        _time = _time + 1;

                        _x set [7,_nextState];
                        _x set [8,_time];

                        if (KP_liberation_logistic_debug > 0) then {[format ["Logistic Group Update: %1", _x], "LOGISTIC"] call KPLIB_fnc_log;};
                    };
                };
                case 5;
                case 6: {
                    if ((_x select 8) > 1) then {
                        _locPos = switch (_x select 7) do {case 5: {2}; case 6: {3};};
                        _x set [9,0];
                        private _storage_areas = nearestObjects [(_x select _locPos), [KP_liberation_small_storage_building, KP_liberation_large_storage_building], 150];

                        if ((count (_storage_areas)) == 0) exitWith {_x set [9,2];};

                        private _toProcess = ceil ((ceil (((_x select 6) select 0) / 100)) + (ceil (((_x select 6) select 1) / 100)) + (ceil (((_x select 6) select 2) / 100)));
                        if (_toProcess > 3) then {_toProcess = 3;};
                        private _spaceSum = 0;
                        {
                            if (typeOf _x == KP_liberation_large_storage_building) then {
                                _spaceSum = _spaceSum + (count KP_liberation_large_storage_positions) - (count (attachedObjects _x));
                            };
                            if (typeOf _x == KP_liberation_small_storage_building) then {
                                _spaceSum = _spaceSum + (count KP_liberation_small_storage_positions) - (count (attachedObjects _x));
                            };
                        } forEach _storage_areas;

                        if (_spaceSum < _toProcess) exitWith {_x set [9,2];};

                        _x set [8,((_x select 8) - 1)];
                        private _currentIndex = _forEachIndex;
                        private _processed = 0;
                        while {_processed < _toProcess} do {
                            {
                                private _space = 0;
                                if (typeOf _x == KP_liberation_large_storage_building) then {
                                    _space = (count KP_liberation_large_storage_positions) - (count (attachedObjects _x));
                                };
                                if (typeOf _x == KP_liberation_small_storage_building) then {
                                    _space = (count KP_liberation_small_storage_positions) - (count (attachedObjects _x));
                                };

                                if ((_space > 0) && ((((_tempLogistics select _currentIndex) select 6) select 0) > 0)) then {
                                    private _amount = 100;
                                    if (((((_tempLogistics select _currentIndex) select 6) select 0) / 100) < 1) then {
                                        _amount = ((_tempLogistics select _currentIndex) select 6) select 0;
                                    };
                                    (_tempLogistics select _currentIndex) set [6,
                                        [(((_tempLogistics select _currentIndex) select 6) select 0) - _amount,
                                        (((_tempLogistics select _currentIndex) select 6) select 1),
                                        (((_tempLogistics select _currentIndex) select 6) select 2)]
                                    ];
                                    private _crate = [KP_liberation_supply_crate, _amount, getPos _x] call KPLIB_fnc_createCrate;
                                    [_crate, _x] call KPLIB_fnc_crateToStorage;
                                    _processed = _processed + 1;
                                    _space = _space - 1;
                                };
                                if (_processed >= _toProcess) exitWith {};

                                if ((_space > 0) && ((((_tempLogistics select _currentIndex) select 6) select 1) > 0)) then {
                                    private _amount = 100;
                                    if (((((_tempLogistics select _currentIndex) select 6) select 1) / 100) < 1) then {
                                        _amount = ((_tempLogistics select _currentIndex) select 6) select 1;
                                    };
                                    (_tempLogistics select _currentIndex) set [6,
                                            [(((_tempLogistics select _currentIndex) select 6) select 0),
                                            (((_tempLogistics select _currentIndex) select 6) select 1) - _amount,
                                            (((_tempLogistics select _currentIndex) select 6) select 2)]
                                        ];
                                    private _crate = [KP_liberation_ammo_crate, _amount, getPos _x] call KPLIB_fnc_createCrate;
                                    [_crate, _x] call KPLIB_fnc_crateToStorage;
                                    _processed = _processed + 1;
                                    _space = _space - 1;
                                };
                                if (_processed >= _toProcess) exitWith {};

                                if ((_space > 0) && ((((_tempLogistics select _currentIndex) select 6) select 2) > 0)) then {
                                    private _amount = 100;
                                    if (((((_tempLogistics select _currentIndex) select 6) select 2) / 100) < 1) then {
                                        _amount = ((_tempLogistics select _currentIndex) select 6) select 2;
                                    };
                                    (_tempLogistics select _currentIndex) set [6,
                                            [(((_tempLogistics select _currentIndex) select 6) select 0),
                                            (((_tempLogistics select _currentIndex) select 6) select 1),
                                            (((_tempLogistics select _currentIndex) select 6) select 2) - _amount]
                                        ];
                                    private _crate = [KP_liberation_fuel_crate, _amount, getPos _x] call KPLIB_fnc_createCrate;
                                    [_crate, _x] call KPLIB_fnc_crateToStorage;
                                    _processed = _processed + 1;
                                    _space = _space - 1;
                                };
                                if (_processed >= _toProcess) exitWith {};
                            } forEach _storage_areas;
                        };
                        please_recalculate = true;

                        if (KP_liberation_logistic_debug > 0) then {[format ["Logistic Group Update: %1", _x], "LOGISTIC"] call KPLIB_fnc_log;};
                    } else {
                        _x set [2,[0,0,0]];
                        _x set [3,[0,0,0]];
                        _x set [4,[0,0,0]];
                        _x set [5,[0,0,0]];
                        _x set [6,[0,0,0]];
                        _x set [7,0];
                        _x set [8,-1];

                        if (KP_liberation_logistic_debug > 0) then {[format ["Logistic Group Update: %1", _x], "LOGISTIC"] call KPLIB_fnc_log;};
                    };
                };
                default {};
            };
        } forEach _tempLogistics;

        KP_liberation_logistics = +_tempLogistics;

        if (KP_liberation_logistic_debug > 0) then {[format ["Logistic interval finished - Time needed: %1 seconds", diag_tickTime - _start], "LOGISTIC"] call KPLIB_fnc_log;};
    };
    uiSleep 60;
};
