package com.github.to2mbn.jmccc.mcdownloader.download.concurrent;

import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class AsyncFuture<T> implements Future<T>, AsyncCallback<T> {

	private static final int RUNNING = 0;
	private static final int DONE = 1;
	private static final int FAILED = 2;
	private static final int CANCELLED = 3;

	private volatile int state = RUNNING;
	private volatile Throwable e;
	private volatile T result;
	private CountDownLatch latch = new CountDownLatch(1);
	private Cancellable cancellable;

	public AsyncFuture() {
		this(null);
	}

	public AsyncFuture(Cancellable cancellable) {
		this.cancellable = cancellable;
	}

	@Override
	public boolean cancel(boolean mayInterruptIfRunning) {
		if (cancellable != null && state == RUNNING) {
			return cancellable.cancel(mayInterruptIfRunning);
		}
		return false;
	}

	@Override
	public boolean isCancelled() {
		return state == CANCELLED;
	}

	@Override
	public boolean isDone() {
		return state == DONE;
	}

	@Override
	public T get() throws InterruptedException, ExecutionException {
		if (state == RUNNING) {
			latch.await();
		}
		return getResult();
	}

	@Override
	public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
		if (state == RUNNING) {
			if (!latch.await(timeout, unit)) {
				throw new TimeoutException();
			}
		}
		return getResult();
	}

	@Override
	public void done(T result) {
		checkUpdateState();
		this.result = result;
		state = DONE;
		terminated();
	}

	@Override
	public void failed(Throwable e) {
		checkUpdateState();
		this.e = e;
		state = FAILED;
		terminated();
	}

	@Override
	public void cancelled() {
		checkUpdateState();
		state = CANCELLED;
		terminated();
	}

	private void checkUpdateState() {
		if (state != RUNNING) {
			throw new IllegalStateException("task already terminated");
		}
	}

	private void terminated() {
		latch.countDown();
	}

	private T getResult() throws ExecutionException {
		switch (state) {
			case DONE:
				return result;

			case FAILED:
				throw new ExecutionException(e);

			case CANCELLED:
				throw new CancellationException();

			default:
				throw new IllegalStateException("not in a completed state");
		}
	}

}

@@ -735,16 +735,58 @@
 ellable;
+%0A%09private Object stateLock = new Object();
 %0A%0A%09publi
@@ -1684,24 +1684,54 @@
 T result) %7B%0A
+%09%09synchronized (stateLock) %7B%0A%09
 %09%09checkUpdat
@@ -1736,24 +1736,25 @@
 ateState();%0A
+%09
 %09%09this.resul
@@ -1763,24 +1763,25 @@
 = result;%0A%09%09
+%09
 state = DONE
@@ -1782,16 +1782,20 @@
 = DONE;%0A
+%09%09%7D%0A
 %09%09termin
@@ -1848,24 +1848,54 @@
 owable e) %7B%0A
+%09%09synchronized (stateLock) %7B%0A%09
 %09%09checkUpdat
@@ -1906,16 +1906,17 @@
 te();%0A%09%09
+%09
 this.e =
@@ -1919,16 +1919,17 @@
 .e = e;%0A
+%09
 %09%09state 
@@ -1934,24 +1934,28 @@
 e = FAILED;%0A
+%09%09%7D%0A
 %09%09terminated
@@ -2000,16 +2000,46 @@
 led() %7B%0A
+%09%09synchronized (stateLock) %7B%0A%09
 %09%09checkU
@@ -2052,16 +2052,17 @@
 tate();%0A
+%09
 %09%09state 
@@ -2074,16 +2074,20 @@
 CELLED;%0A
+%09%09%7D%0A
 %09%09termin

add stateLock