package no.stelar7.api.l4j8.basic.ratelimiting;


import no.stelar7.api.l4j8.basic.DataCall;

import java.time.Instant;
import java.util.*;
import java.util.Map.Entry;

/**
 * Burst ratelimiter will use as many calls as possible, then wait when it reaches the limit
 */
public class BurstRateLimiter extends RateLimiter
{
    
    public BurstRateLimiter(RateLimit... limits)
    {
        super(limits);
    }
    
    @Override
    public void acquire()
    {
        try
        {
            for (RateLimit limit : limits)
            {
                callCountInTime.compute(limit, (k, v) -> v + 1);
            }
            
            Thread.sleep(getDelay());
            
            update();
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
    
    @Override
    public void updatePermitsPerX(Map<Integer, Long> data)
    {
        for (Entry<Integer, Long> key : data.entrySet())
        {
            for (RateLimit l : limits)
            {
                if (l.getTimeframeInMS() / 1000 == key.getKey())
                {
                    long oldVal = callCountInTime.get(l);
                    long newVal = key.getValue();
                    if (oldVal + 1 < newVal)
                    {
                        callCountInTime.put(l, newVal);
                        
                        if (DataCall.VERBOSE_LIMITING)
                        {
                            System.out.println("limit " + key + " has changed from " + oldVal + " to " + newVal);
                        }
                    }
                }
            }
        }
    }
    
    private long getDelay()
    {
        Instant now   = Instant.now();
        long[]  delay = {0};
        int     bias  = 1;
        
        for (RateLimit limit : limits)
        {
            if (callCountInTime.get(limit) >= limit.getRequests())
            {
                long newDelay = firstCallInTime.get(limit).toEpochMilli() + limit.getTimeframeInMS() - now.toEpochMilli();
                if (newDelay > delay[0])
                {
                    delay[0] = newDelay;
                }
            }
        }
        
        if (delay[0] != 0)
        {
            delay[0] = (long) ((Math.ceil(delay[0] / 1000f) + bias) * 1000L);
        }
        
        if (DataCall.VERBOSE_LIMITING)
        {
            System.out.println("Sleeping for: " + delay[0]);
        }
        
        return delay[0];
    }
    
    private void update()
    {
        Instant now = Instant.now();
        for (RateLimit limit : limits)
        {
            if ((firstCallInTime.get(limit).toEpochMilli() - now.toEpochMilli()) + limit.getTimeframeInMS() < 0)
            {
                firstCallInTime.put(limit, now);
                callCountInTime.put(limit, 0L);
            }
            
            if (DataCall.VERBOSE_LIMITING)
            {
                System.out.println("Calls made: " + callCountInTime.get(limit) + " in: " + limit.getTimeframeInMS() / 1000);
            }
        }
    }
    
}
@@ -493,145 +493,34 @@
     
-for (RateLimit limit : limits)%0A            %7B%0A                callCountInTime.compute(limit, (k, v) -%3E v + 1);%0A            %7D%0A            %0A
+update();%0A            %0A   
     
@@ -524,19 +524,16 @@
         
-   
 Thread.s
@@ -554,43 +554,8 @@
 ));%0A
-            %0A            update();%0A
     
@@ -2691,32 +2691,106 @@
  %7D%0A            %0A
+            callCountInTime.compute(limit, (k, v) -%3E v + 1);%0A            %0A
             if (

Move callcounter back to update