package speiger.src.coreengine.assets.impl;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Function;

import javax.imageio.ImageIO;

import com.google.gson.JsonObject;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.assets.IAssetParser;
import speiger.src.coreengine.utils.helpers.JsonUtil;

public class FolderAsset implements IAsset
{
	Function<Class<?>, IAssetParser<?>> parsers;
	AssetLocation location;
	Path path;
	List<Closeable> closeable;
	
	public FolderAsset(AssetLocation location, Path path, Function<Class<?>, IAssetParser<?>> parsers)
	{
		this(location, path, parsers, new ObjectArrayList<>());
	}
	
	public FolderAsset(AssetLocation location, Path path, Function<Class<?>, IAssetParser<?>> parsers, List<Closeable> closeable)
	{
		this.location = location;
		this.path = path;
		this.parsers = parsers;
		this.closeable = closeable;
	}
	
	@Override
	public void close() throws IOException
	{
		for(Closeable close : closeable)
		{
			try
			{
				close.close();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		closeable.clear();
	}
	
	@Override
	public IAsset subAsset(String alternative)
	{
		Path newPath = path.resolveSibling(path.getFileName().toString()+"."+alternative);
		return Files.exists(newPath) ? new FolderAsset(location.alternate(alternative), newPath, parsers, closeable) : null;
	}
	
	@Override
	public AssetLocation getLocation()
	{
		return location;
	}
	
	@Override
	public InputStream getStream() throws IOException
	{
		return markClosed(Files.newInputStream(path));
	}
	
	@Override
	public ByteBuffer getBytes() throws IOException
	{
		return ByteBuffer.wrap(Files.readAllBytes(path));
	}
	
	@Override
	public BufferedImage getTexture() throws Exception
	{
		return ImageIO.read(getStream());
	}
	
	@Override
	public BufferedReader getStringReader() throws IOException
	{
		return markClosed(Files.newBufferedReader(path));
	}
	
	@Override
	public JsonObject getJsonObject() throws IOException
	{
		return JsonUtil.loadFile(path);
	}
	
	@Override
	public <T> T getCustom(Class<T> clz) throws IOException
	{
		return clz.cast(parsers.apply(clz).parseAsset(path, closeable::add));
	}
	
	protected <T extends Closeable> T markClosed(T value)
	{
		closeable.add(value);
		return value;
	}
}
