package speiger.src.coreengine.rendering.utils;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;

import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.coreengine.rendering.models.buffers.VertexBuffer;
import speiger.src.coreengine.utils.counters.averager.Averager;

public class AllocationTracker {
	public static final AllocationTracker INSTANCE = new AllocationTracker();
	long lastTime = 0;
	long lastMemory = 0L;
	long addedCPUMemory = 0L;
	long addedGPUMemory = 0L;
	Averager cpuAllocation = new Averager(20);
	Averager gpuAllocation = new Averager(20);
	Int2ObjectMap<VertexBuffer> allocatedBuffers = Int2ObjectMap.builder().linkedMap();
	MemoryMXBean offHeap = ManagementFactory.getMemoryMXBean();
	
	public void update() {
		long newTime = System.currentTimeMillis();
		if(newTime - lastTime < 1000) {
			updateAllocation();
			return;
		}
		lastTime = newTime;
		updateAllocation();
		cpuAllocation.addEntry(addedCPUMemory);
		addedCPUMemory = 0L;
		gpuAllocation.addEntry(addedGPUMemory);
		addedGPUMemory = 0L;
	}
	
	public void addGPUBytes(long amount) {
		addedGPUMemory += amount;
	}
	
	public void track(VertexBuffer buffer) {
		allocatedBuffers.put(buffer.id(), buffer);
	}
	
	public void untrack(VertexBuffer buffer) {
		allocatedBuffers.remove(buffer.id());
	}
	
	private void updateAllocation() {
		long memory = getMemory();
		if(memory > lastMemory) addedCPUMemory += (memory - lastMemory);
		lastMemory = memory;
	}
	
	public long getOffHeapMemory() {
		return offHeap.getNonHeapMemoryUsage().getUsed();
	}
	
	private long getMemory() {
		Runtime runtime = Runtime.getRuntime();
		return runtime.totalMemory() - runtime.freeMemory();
	}
	
	public long getCPUAllocatedBytes() { return cpuAllocation.getAverage(); }
	public long getGPUAllocatedBytes() { return gpuAllocation.getAverage(); }
}
