package speiger.src.coreengine.assets.base;

import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.sets.ObjectOpenHashSet;
import speiger.src.coreengine.assets.base.IReloadableAsset.IReloadSyncer;

public class PackReloadingTask {
	public static CompletableFuture<?> reload(IAssetProvider provider, List<IReloadableAsset> assets, Executor offthreadTask, Executor mainThreadTask) {
		CompletableFuture<Object> syncStep = new CompletableFuture<>();
		List<CompletableFuture<?>> results = new ObjectArrayList<>();
		CompletableFuture<?> currentStep = CompletableFuture.completedFuture("");
		Set<IReloadableAsset> toComplete = new ObjectOpenHashSet<>(assets);
		for(IReloadableAsset asset : assets) {
			CompletableFuture<?> next = asset.reloadAssets(provider, new Syncer(mainThreadTask, currentStep, syncStep, asset, toComplete), offthreadTask, mainThreadTask);
			results.add(next);
			currentStep = next;
		}
		return CompletableFuture.allOf(results.toArray(CompletableFuture[]::new));		
	}
	
	private static class Syncer implements IReloadSyncer {
		Executor mainExecutor;
		CompletableFuture<?> currentStep;
		CompletableFuture<Object> syncStep;
		IReloadableAsset currentAsset;
		Set<IReloadableAsset> toComplete;
		
		public Syncer(Executor mainExecutor, CompletableFuture<?> currentStep, CompletableFuture<Object> syncStep, IReloadableAsset currentAsset, Set<IReloadableAsset> toComplete) {
			this.mainExecutor = mainExecutor;
			this.currentStep = currentStep;
			this.syncStep = syncStep;
			this.currentAsset = currentAsset;
			this.toComplete = toComplete;
		}
		
		@Override
		public <T> CompletableFuture<T> sync(T value) {
			mainExecutor.execute(() -> {
				if(toComplete.remove(currentAsset) && toComplete.isEmpty()) {
					syncStep.complete(new Object());
				}
			});
			return syncStep.thenCombine(currentStep, (_, _) -> value);
		}
	}
}
