package net.minecraftforge.server;

import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.MapMaker;

import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity;

public class ForgeTimeTracker {
	public static boolean tileEntityTracking;
	public static int tileEntityTrackingDuration;
	public static long tileEntityTrackingTime;
	
	private Map<TileEntity,int[]> tileEntityTimings;
	private Map<Entity,int[]> entityTimings;
	
	private static final ForgeTimeTracker INSTANCE = new ForgeTimeTracker();

	private WeakReference<TileEntity> tile;
	private WeakReference<Entity> entity;
	
	private long timing;
	
	private ForgeTimeTracker()
	{
		MapMaker mm = new MapMaker();
		mm.weakKeys();
		tileEntityTimings = mm.makeMap();
		entityTimings = mm.makeMap();
	}
	

	private void trackTileStart(TileEntity tileEntity, long nanoTime)
	{
		if (tileEntityTrackingTime == 0)
		{
			tileEntityTrackingTime = nanoTime;
		}
		else if (tileEntityTrackingTime + tileEntityTrackingDuration < nanoTime)
		{
			tileEntityTracking = false;
			tileEntityTrackingTime = 0;
			
			return;
		}
		tile = new WeakReference<TileEntity>(tileEntity);
		timing = nanoTime;
	}


	private void trackTileEnd(TileEntity tileEntity, long nanoTime)
	{
		if (tile == null || tile.get() != tileEntity)
		{
			tile = null;
			// race, exit
			return;
		}
		int[] timings = tileEntityTimings.get(tileEntity);
		if (timings == null)
		{
			timings = new int[101];
			tileEntityTimings.put(tileEntity, timings);
		}
		int idx = timings[100] = (timings[100] + 1) % 100;
		timings[idx] = (int) (nanoTime - timing);
	}

	public static ImmutableMap<TileEntity,int[]> getTileTimings()
	{
		return INSTANCE.buildImmutableTileEntityTimingMap();
	}
	
	private ImmutableMap<TileEntity, int[]> buildImmutableTileEntityTimingMap()
	{
		Builder<TileEntity, int[]> builder = ImmutableMap.<TileEntity,int[]>builder();
		for (Entry<TileEntity, int[]> entry : tileEntityTimings.entrySet())
		{
			builder.put(entry.getKey(), Arrays.copyOfRange(entry.getValue(), 0, 100));
		}
		return builder.build();
	}


	public static void trackStart(TileEntity tileEntity)
	{
		if (!tileEntityTracking) return;
		INSTANCE.trackTileStart(tileEntity, System.nanoTime());
	}

	public static void trackEnd(TileEntity tileEntity)
	{
		if (!tileEntityTracking) return;
		INSTANCE.trackTileEnd(tileEntity, System.nanoTime());
	}

	public static void trackStart(Entity par1Entity)
	{
		
	}

	public static void trackEnd(Entity par1Entity)
	{
		
	}

}
