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

package com.hypixel.hytale.server.npc.util;

import com.hypixel.hytale.common.util.FormatUtil;
import java.util.Formatter;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.common.benchmark.ContinuousValueRecorder;
import com.hypixel.hytale.common.benchmark.DiscreteValueRecorder;
import javax.annotation.Nonnull;
import com.hypixel.hytale.common.benchmark.TimeRecorder;

public class SensorSupportBenchmark
{
    public static final char DEFAULT_COLUMN_SEPARATOR = '|';
    public static final String DEFAULT_COLUMN_FORMAT_HEADER = "|%-6.6s";
    public static final String DEFAULT_COLUMN_FORMAT_VALUE = "|%6.6s";
    public static final String[] DEFAULT_COLUMNS_UPDATE;
    public static final String[] DEFAULT_COLUMNS_LOS;
    @Nonnull
    protected TimeRecorder playerGetTime;
    @Nonnull
    protected DiscreteValueRecorder playerDistance;
    @Nonnull
    protected DiscreteValueRecorder playerDistanceSorted;
    @Nonnull
    protected DiscreteValueRecorder playerDistanceAvoidance;
    @Nonnull
    protected DiscreteValueRecorder playerCount;
    @Nonnull
    protected TimeRecorder entityGetTime;
    @Nonnull
    protected DiscreteValueRecorder entityDistance;
    @Nonnull
    protected DiscreteValueRecorder entityDistanceSorted;
    @Nonnull
    protected DiscreteValueRecorder entityDistanceAvoidance;
    @Nonnull
    protected DiscreteValueRecorder entityCount;
    @Nonnull
    protected DiscreteValueRecorder losTest;
    @Nonnull
    protected ContinuousValueRecorder losCacheHit;
    @Nonnull
    protected DiscreteValueRecorder inverseLosTest;
    @Nonnull
    protected ContinuousValueRecorder inverseLosCacheHit;
    @Nonnull
    protected DiscreteValueRecorder friendlyBlockingTest;
    @Nonnull
    protected ContinuousValueRecorder friendlyBlockingCacheHit;
    @Nonnull
    protected TimeRecorder losTestTime;
    protected long losTestTick;
    protected long losCacheHitTick;
    protected long inverseLosTestTick;
    protected long inverseLosCacheHitTick;
    protected long friendlyBlockingTestTick;
    protected long friendlyBlockingCacheHitTick;
    
    public SensorSupportBenchmark() {
        this.playerGetTime = new TimeRecorder();
        this.playerDistance = new DiscreteValueRecorder();
        this.playerDistanceSorted = new DiscreteValueRecorder();
        this.playerDistanceAvoidance = new DiscreteValueRecorder();
        this.playerCount = new DiscreteValueRecorder();
        this.entityGetTime = new TimeRecorder();
        this.entityDistance = new DiscreteValueRecorder();
        this.entityDistanceSorted = new DiscreteValueRecorder();
        this.entityDistanceAvoidance = new DiscreteValueRecorder();
        this.entityCount = new DiscreteValueRecorder();
        this.losTest = new DiscreteValueRecorder();
        this.losCacheHit = new ContinuousValueRecorder();
        this.inverseLosTest = new DiscreteValueRecorder();
        this.inverseLosCacheHit = new ContinuousValueRecorder();
        this.friendlyBlockingTest = new DiscreteValueRecorder();
        this.friendlyBlockingCacheHit = new ContinuousValueRecorder();
        this.losTestTime = new TimeRecorder();
    }
    
    public void collectPlayerList(final long getNanos, final double maxPlayerDistanceSorted, final double maxPlayerDistance, final double maxPlayerDistanceAvoidance, final int numPlayers) {
        this.playerGetTime.recordNanos(getNanos);
        this.playerDistance.record(MathUtil.fastCeil(maxPlayerDistance));
        this.playerDistanceSorted.record(MathUtil.fastCeil(maxPlayerDistanceSorted));
        this.playerDistanceAvoidance.record(MathUtil.fastCeil(maxPlayerDistanceAvoidance));
        this.playerCount.record(numPlayers);
    }
    
    public void collectEntityList(final long getNanos, final double maxEntityDistanceSorted, final double maxEntityDistance, final double maxEntityDistanceAvoidance, final int numEntities) {
        this.entityGetTime.recordNanos(getNanos);
        this.entityDistance.record(MathUtil.fastCeil(maxEntityDistance));
        this.entityDistanceSorted.record(MathUtil.fastCeil(maxEntityDistanceSorted));
        this.entityDistanceAvoidance.record(MathUtil.fastCeil(maxEntityDistanceAvoidance));
        this.entityCount.record(numEntities);
    }
    
    public void collectLosTest(final boolean cacheHit, final long time) {
        ++this.losTestTick;
        if (cacheHit) {
            ++this.losCacheHitTick;
        }
        else {
            this.losTestTime.recordNanos(time);
        }
    }
    
    public void collectInverseLosTest(final boolean cacheHit) {
        ++this.inverseLosTestTick;
        if (cacheHit) {
            ++this.inverseLosCacheHitTick;
        }
    }
    
    public void collectFriendlyBlockingTest(final boolean cacheHit) {
        ++this.friendlyBlockingTestTick;
        if (cacheHit) {
            ++this.friendlyBlockingCacheHitTick;
        }
    }
    
    public void tickDone() {
        this.losTest.record(this.losTestTick);
        if (this.losTestTick > 0L) {
            this.losCacheHit.record(this.losCacheHitTick / (double)this.losTestTick);
        }
        this.losTestTick = 0L;
        this.losCacheHitTick = 0L;
        this.inverseLosTest.record(this.inverseLosTestTick);
        if (this.inverseLosTestTick > 0L) {
            this.inverseLosCacheHit.record(this.inverseLosCacheHitTick / (double)this.inverseLosTestTick);
        }
        this.inverseLosTestTick = 0L;
        this.inverseLosCacheHitTick = 0L;
        this.friendlyBlockingTest.record(this.friendlyBlockingTestTick);
        if (this.friendlyBlockingTestTick > 0L) {
            this.friendlyBlockingCacheHit.record(this.friendlyBlockingCacheHitTick / (double)this.friendlyBlockingTestTick);
        }
        this.friendlyBlockingTestTick = 0L;
        this.friendlyBlockingCacheHitTick = 0L;
    }
    
    public void formatHeaderUpdateTimes(@Nonnull final Formatter formatter) {
        FormatUtil.formatArray(formatter, "|%-6.6s", SensorSupportBenchmark.DEFAULT_COLUMNS_UPDATE);
    }
    
    public void formatValuesUpdateTimePlayer(@Nonnull final Formatter formatter) {
        this.formatValuesUpdateTime(formatter, "Player", this.playerGetTime, this.playerCount, this.playerDistanceSorted, this.playerDistance, this.playerDistanceAvoidance);
    }
    
    public void formatValuesUpdateTimeEntity(@Nonnull final Formatter formatter) {
        this.formatValuesUpdateTime(formatter, "Entity", this.entityGetTime, this.entityCount, this.entityDistanceSorted, this.entityDistance, this.entityDistanceAvoidance);
    }
    
    public void formatValuesUpdateTime(@Nonnull final Formatter formatter, final String kind, @Nonnull final TimeRecorder getTime, @Nonnull final DiscreteValueRecorder count, @Nonnull final DiscreteValueRecorder distanceSorted, @Nonnull final DiscreteValueRecorder distance, @Nonnull final DiscreteValueRecorder distanceAvoidance) {
        final long distanceMaxValue = distance.getMaxValue();
        final long distanceMinValue = distance.getMinValue();
        final long distanceMaxValueSorted = distanceSorted.getMaxValue();
        final long distanceMinValueSorted = distanceSorted.getMinValue();
        final long distanceMaxValueAvoidance = distanceAvoidance.getMaxValue();
        final long distanceMinValueAvoidance = distanceAvoidance.getMinValue();
        formatter.format("|%-6.6s", kind);
        FormatUtil.formatArgs(formatter, "|%6.6s", getTime.getCount(), TimeRecorder.formatTime(getTime.getAverage()), TimeRecorder.formatTime(getTime.getMinValue()), TimeRecorder.formatTime(getTime.getMaxValue()), count.getAverage(), count.getMaxValue(), (distanceMaxValueSorted == distanceMinValueSorted) ? Long.valueOf(distanceMaxValueSorted) : (distanceMinValueSorted + "-" + distanceMaxValueSorted), (distanceMaxValue == distanceMinValue) ? Long.valueOf(distanceMaxValue) : (distanceMinValue + "-" + distanceMaxValue), (distanceMaxValueAvoidance == distanceMinValueAvoidance) ? Long.valueOf(distanceMaxValueAvoidance) : (distanceMinValueAvoidance + "-" + distanceMaxValueAvoidance));
    }
    
    public boolean haveUpdateTimes() {
        return this.playerGetTime.getCount() > 0L || this.entityGetTime.getCount() > 0L;
    }
    
    public void formatHeaderLoS(@Nonnull final Formatter formatter) {
        FormatUtil.formatArray(formatter, "|%-6.6s", SensorSupportBenchmark.DEFAULT_COLUMNS_LOS);
    }
    
    public boolean formatValuesLoS(@Nonnull final Formatter formatter) {
        if (this.losTest.getMaxValue() == 0L && this.inverseLosTest.getMaxValue() == 0L && this.friendlyBlockingTest.getMaxValue() == 0L) {
            return false;
        }
        FormatUtil.formatArgs(formatter, "|%6.6s", this.losTest.getCount(), this.losTest.getAverage(), this.losTest.getMaxValue(), (int)(this.losCacheHit.getAverage() * 100.0), this.losTestTime.getCount(), TimeRecorder.formatTime(this.losTestTime.getAverage()), TimeRecorder.formatTime(this.losTestTime.getMinValue()), TimeRecorder.formatTime(this.losTestTime.getMaxValue()), this.inverseLosTest.getCount(), this.inverseLosTest.getAverage(), this.inverseLosTest.getMaxValue(), (int)(this.inverseLosCacheHit.getAverage() * 100.0), this.friendlyBlockingTest.getCount(), this.friendlyBlockingTest.getAverage(), this.friendlyBlockingTest.getMaxValue(), (int)(this.friendlyBlockingCacheHit.getAverage() * 100.0));
        return true;
    }
    
    static {
        DEFAULT_COLUMNS_UPDATE = new String[] { "KIND", "COUNT", "G-AVG", "G-MIN", "G-MAX", "L-AVG", "L-MAX", "SD-MAX", "UD-MAX", "AD-MAX" };
        DEFAULT_COLUMNS_LOS = new String[] { "L-CNT", "L-AVG", "L-MAX", "L-HIT%", "T-CNT", "T-AVG", "T-MIN", "T-MAX", "I-CNT", "I-AVG", "I-MAX", "I-HIT%", "F-CNT", "F-AVG", "F-MAX", "F-HIT%" };
    }
}
