package me.nallar.reporting;

import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import me.nallar.tickthreading.Log;
import me.nallar.unsafe.UnsafeUtil;

public class LeakDetector {
	private final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(0);
	private final Timer timer = new Timer("Leak Detector", true);
	private final long waitTimeSeconds;
	private final Map<Long, LeakCheckEntry> scheduledObjects = new ConcurrentHashMap<Long, LeakCheckEntry>();

	public LeakDetector(final long waitTimeSeconds) {
		this.waitTimeSeconds = waitTimeSeconds;
	}

	public synchronized void scheduleLeakCheck(Object o, String oDescription_, final boolean clean) {
		try {
			if (clean) {
				timer.schedule(new CleanerTask(o), Math.min(waitTimeSeconds / 2, 20000));
			}
			final long id = UnsafeUtil.addressOf(o);
			final String oDescription = (oDescription_ == null ? "" : oDescription_ + " : ") + o.getClass() + '@' + System.identityHashCode(o) + ':' + id;
			scheduledObjects.put(id, new LeakCheckEntry(o, oDescription));
			scheduledThreadPoolExecutor.schedule(new Runnable() {
				@Override
				public void run() {
					LeakCheckEntry leakCheckEntry = scheduledObjects.remove(id);
					Object o = leakCheckEntry.o.get();
					if (o == null) {
						Log.fine("Object " + leakCheckEntry.description + " has been removed normally.");
					} else {
						String warning = "Probable memory leak detected. \"" + leakCheckEntry.description + "\" has not been garbage collected after " + waitTimeSeconds / 1000 + "s.";
						if (clean && !Log.debug) {
							Log.fine(warning);
						} else {
							Log.warning(warning);
						}
					}
				}
			}, waitTimeSeconds, TimeUnit.SECONDS);
		} catch (Throwable t) {
			Log.severe("Failed to schedule leak check for " + oDescription_, t);
		}
	}

	private static class CleanerTask extends TimerTask {
		final Object toClean;

		CleanerTask(final Object toClean) {
			this.toClean = toClean;
		}

		@Override
		public void run() {
			UnsafeUtil.clean(toClean);
		}
	}

	private static class LeakCheckEntry {
		public final WeakReference<Object> o;
		public final String description;

		LeakCheckEntry(final Object o, final String description) {
			this.o = new WeakReference<Object>(o);
			this.description = description;
		}
	}
}

@@ -89,33 +89,8 @@
 p;%0D%0A
-import java.util.Timer;%0D%0A
 impo
@@ -114,16 +114,16 @@
 rTask;%0D%0A
+
 import j
@@ -480,72 +480,8 @@
 );%0D%0A
-%09private final Timer timer = new Timer(%22Leak Detector%22, true);%0D%0A
 %09pri
@@ -859,12 +859,34 @@
 %09%09%09%09
-time
+scheduledThreadPoolExecuto
 r.sc
@@ -948,12 +948,27 @@
 , 20
-000)
+), TimeUnit.SECONDS
 );%0D%0A

Fix incorrect use of old timer which should be scheduler.