// 
// Decompiled by Procyon v0.6.0
// 

package com.google.common.flogger;

import com.google.common.flogger.util.Checks;
import com.google.common.flogger.backend.Metadata;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

final class LogSiteStats
{
    private static final LogSiteMap<LogSiteStats> map;
    private final AtomicLong invocationCount;
    private final AtomicLong lastTimestampNanos;
    private final AtomicInteger skippedLogStatements;
    
    LogSiteStats() {
        this.invocationCount = new AtomicLong();
        this.lastTimestampNanos = new AtomicLong();
        this.skippedLogStatements = new AtomicInteger();
    }
    
    static RateLimitPeriod newRateLimitPeriod(final int n, final TimeUnit unit) {
        return new RateLimitPeriod(n, unit);
    }
    
    static LogSiteStats getStatsForKey(final LogSiteKey logSiteKey, final Metadata metadata) {
        return LogSiteStats.map.get(logSiteKey, metadata);
    }
    
    boolean incrementAndCheckInvocationCount(final int rateLimitCount) {
        return this.invocationCount.getAndIncrement() % rateLimitCount == 0L;
    }
    
    boolean checkLastTimestamp(final long timestampNanos, final RateLimitPeriod period) {
        final long lastNanos = this.lastTimestampNanos.get();
        final long deadlineNanos = lastNanos + period.toNanos();
        if (deadlineNanos >= 0L && (timestampNanos >= deadlineNanos || lastNanos == 0L) && this.lastTimestampNanos.compareAndSet(lastNanos, timestampNanos)) {
            period.setSkipCount(this.skippedLogStatements.getAndSet(0));
            return true;
        }
        this.skippedLogStatements.incrementAndGet();
        return false;
    }
    
    static {
        map = new LogSiteMap<LogSiteStats>() {
            @Override
            protected LogSiteStats initialValue() {
                return new LogSiteStats();
            }
        };
    }
    
    static final class RateLimitPeriod
    {
        private final int n;
        private final TimeUnit unit;
        private int skipCount;
        
        private RateLimitPeriod(final int n, final TimeUnit unit) {
            this.skipCount = -1;
            if (n <= 0) {
                throw new IllegalArgumentException("time period must be positive: " + n);
            }
            this.n = n;
            this.unit = Checks.checkNotNull(unit, "time unit");
        }
        
        private long toNanos() {
            return this.unit.toNanos(this.n);
        }
        
        private void setSkipCount(final int skipCount) {
            this.skipCount = skipCount;
        }
        
        @Override
        public String toString() {
            final StringBuilder out = new StringBuilder().append(this.n).append(' ').append(this.unit);
            if (this.skipCount > 0) {
                out.append(" [skipped: ").append(this.skipCount).append(']');
            }
            return out.toString();
        }
        
        @Override
        public int hashCode() {
            return this.n * 37 ^ this.unit.hashCode();
        }
        
        @Override
        public boolean equals(final Object obj) {
            if (obj instanceof RateLimitPeriod) {
                final RateLimitPeriod that = (RateLimitPeriod)obj;
                return this.n == that.n && this.unit == that.unit;
            }
            return false;
        }
    }
}
