package speiger.src.coreengine.assets;

import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Predicate;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
import speiger.src.coreengine.assets.oldImpl.LayeredAssetProvider;
import speiger.src.coreengine.assets.base.IManagedAsset;
import speiger.src.coreengine.assets.base.IReloadableAsset;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.assets.base.PackReloadingTask;

public class AssetManager implements ICloseableAssetProvider
{
	ObjectList<IReloadableAsset> listeners = new ObjectArrayList<>();
	LayeredAssetProvider provider;
	
	public AssetManager(List<IAssetPackage> packages) {
		provider = new LayeredAssetProvider(packages);
	}
	
	public void addListener(IReloadableAsset listener) {
		listeners.add(listener);
		if(listener instanceof IManagedAsset managed) {
			managed.setProvider(this);
		}
	}
	
	public ObjectList<IReloadableAsset> listeners() {
		return ObjectLists.unmodifiable(listeners);
	}
	
	public AssetManager reload(Executor offthread, Executor syncer, List<IAssetPackage> packages) {
		return reloadAssets(packages).reloadSelective(offthread, syncer, listeners);
	}
	
	public AssetManager reload() {
		return reload(Runnable::run, Runnable::run);
	}
	
	public AssetManager reload(Executor offthread, Executor syncer) {
		return reloadSelective(offthread, syncer, listeners);
	}
	
	public AssetManager reloadSelective(List<IReloadableAsset> listeners) {
		return reloadSelective(Runnable::run, Runnable::run, listeners);
	}
	
	public AssetManager reloadSelective(Executor offthread, Executor syncer, List<IReloadableAsset> listeners) {
		PackReloadingTask.reload(provider, listeners, offthread, syncer).join();
		return this;
	}
	
	public AssetManager reloadAssets(List<IAssetPackage> packages) {
		provider.close();
		provider = new LayeredAssetProvider(packages);
		return this;
	}
	
	@Override
	public void close() {
		provider.close();
		listeners.forEach(IReloadableAsset::destroy);
	}
	
	@Override
	public FileTime getModifiedTime(AssetLocation location) {
		return provider.getModifiedTime(location);
	}
	
	@Override
	public FileTime getLatestTime(AssetLocation... locations) {
		return provider.getLatestTime(locations);
	}
	
	@Override
	public IAsset getAsset(AssetLocation location) {
		return provider.getAsset(location);
	}

	@Override
	public MultiAsset getAllAssets(AssetLocation location) {
		return provider.getAllAssets(location);
	}

	@Override
	public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
		return provider.listAssets(folder, filter);
	}

	@Override
	public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
		return provider.listAllAssets(folder, filter);
	}
}
