package net.teamfruit.factorioforge;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;

import net.teamfruit.factorioforge.factorioapi.FactorioAPI;
import net.teamfruit.factorioforge.factorioapi.data.IModList;
import net.teamfruit.factorioforge.factorioapi.data.IRelease;

public class RepositoryManager {
	public static RepositoryManager instance = new RepositoryManager();

	public final ExecutorService executor = Executors.newFixedThreadPool(2, (r) -> new Thread(r, "FactorioForge-communication-thread"));
	private final List<IRelease> releases = new ArrayList<>();
	private final Deque<Consumer<IModList>> thenAccepts = new ArrayDeque<>();
	private int count;
	private int pageCount;

	private RepositoryManager() {
	}

	public void init() {
		requestModList(1, 1).whenComplete((result1, t1) -> {
			this.count = result1.getPagination().getCount();
			this.pageCount = result1.getPagination().getPageCount();
			final CompletableFuture<IModList> future = requestModList(1, this.count);
			future.whenComplete((result2, t2) -> result2.getResults().stream().forEach(r -> this.releases.add(r.getShortResult().getLatestRelease())));
			future.thenAccept(result2 -> this.thenAccepts.stream().forEach(c -> c.accept(result2)));
		});
	}

	public boolean isComplete() {
		return this.releases.size()>=this.pageCount;
	}

	public List<IRelease> getReleases() {
		return this.releases;
	}

	public int getCount() {
		if (!isComplete())
			return -1;
		return this.count;
	}

	public int getPageCount() {
		if (!isComplete())
			return -1;
		return this.pageCount;
	}

	public void thenAccept(final Consumer<IModList> consumer) {
		this.thenAccepts.offer(consumer);
	}

	public Optional<IRelease> getReleaseById(final int id) {
		return this.releases.stream().filter(r -> r.getID()==id).findAny();
	}

	private CompletableFuture<IModList> requestModList(final int page, final int pageSize) {
		return CompletableFuture.supplyAsync(() -> {
			try {
				final IModList modList = FactorioAPI.getModList(page, pageSize);
				return modList;
			} catch (final IOException e) {
				throw new UncheckedIOException(e);
			}
		}, this.executor);
	}

}

@@ -146,91 +146,13 @@
 til.
-ArrayList;%0Aimport java.util.Deque;%0Aimport java.util.List;%0Aimport java.util.Optional
+Deque
 ;%0Aim
@@ -442,70 +442,8 @@
 ist;
-%0Aimport net.teamfruit.factorioforge.factorioapi.data.IRelease;
 %0A%0Apu
@@ -690,57 +690,24 @@
 ate 
-final List%3CIRelease%3E releases = new ArrayList%3C%3E()
+IModList modList
 ;%0A%09p
@@ -1139,138 +1139,52 @@
 ure.
-whenComplete((result2, t2) -%3E result2.getResults().stream().forEach(r -%3E this.releases.add(r.getShortResult().getLatestRelease()))
+thenAccept(result2 -%3E this.modList = result2
 );%0A%09
@@ -1333,79 +1333,54 @@
 his.
-releases.size()%3E=this.pageCount;%0A%09%7D%0A%0A%09public List%3CIRelease%3E getReleases
+modList!=null;%0A%09%7D%0A%0A%09public IModList getModList
 () %7B
@@ -1394,24 +1394,23 @@
 rn this.
-releases
+modList
 ;%0A%09%7D%0A%0A%09p
@@ -1652,171 +1652,93 @@
 %7B%0A%09%09
-this.thenAccepts.offer(consumer);%0A%09%7D%0A%0A%09public Optional%3CIRelease%3E getReleaseById(final int id) %7B%0A%09%09return this.releases.stream().filter(r -%3E r.getID()==id).findAny(
+if (isComplete())%0A%09%09%09consumer.accept(this.modList);%0A%09%09this.thenAccepts.offer(consumer
 );%0A%09

complete accept