package speiger.src.coreengine.utils.io;

import java.io.File;
import java.nio.file.Path;
import java.util.List;

import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.collections.objects.sets.ObjectLinkedOpenHashSet;
import speiger.src.collections.objects.sets.ObjectOrderedSet;
import speiger.src.collections.objects.utils.ObjectIterators;
import speiger.src.coreengine.utils.io.finders.IFileFinder;
import speiger.src.coreengine.utils.io.finders.JavaFileFinder;
import speiger.src.coreengine.utils.io.finders.NativeFileFinder;

public class FileFinder
{
	public static IFileFinder DEFAULT_FINDER = NativeFileFinder.INSTANCE;
	
	protected int flags;
	protected String customPath;
	protected ObjectOrderedSet<String> fileFormats;
	protected IFileFinder finder;
	
	public FileFinder(int flags, String...fileFormats)
	{
		this.flags = flags;
		this.fileFormats = new ObjectLinkedOpenHashSet<>(fileFormats);
		finder = DEFAULT_FINDER;
	}
	
	public static FileFinder file(String...formats)
	{
		return new FileFinder(IFileFinder.FILE, formats);
	}
	
	public static FileFinder files(String...formats)
	{
		return new FileFinder(IFileFinder.MULTI_FILE, formats);
	}
	
	public static FileFinder folder()
	{
		return new FileFinder(IFileFinder.FOLDER);
	}
	
	public static FileFinder any(String...formats)
	{
		return new FileFinder(IFileFinder.ANY, formats).shell(JavaFileFinder.INSTANCE);
	}
	
	public static FileFinder save(String fileFormat)
	{
		return new FileFinder(IFileFinder.SAVE, fileFormat);
	}
	
	public static FileFinder save(String... fileFormat)
	{
		return new FileFinder(IFileFinder.SAVE, fileFormat);
	}
	
	public FileFinder path(File file)
	{
		return path(file.toString());
	}
	
	public FileFinder path(Path path)
	{
		return path(path.toString());
	}
	
	public FileFinder path(String s)
	{
		customPath = s;
		return this;
	}
	
	public FileFinder shell(IFileFinder finder) 
	{
		this.finder = finder;
		return this;
	}
	
	public File singleFile(String description)
	{
		List<File> files = buildInternal(description);
		return files.isEmpty() ? null : files.get(0);
	}
	
	public List<File> files(String description)
	{
		return buildInternal(description);
	}
	
	public Path singlePath(String description)
	{
		List<File> files = buildInternal(description);
		return files.isEmpty() ? null : files.get(0).toPath();
	}
	
	public List<Path> paths(String description)
	{
		return ObjectIterators.pour(ObjectIterators.map(buildInternal(description).iterator(), File::toPath));
	}
	
	private ObjectList<File> buildInternal(String description)
	{
		ObjectList<File> files = finder.build(flags, customPath, fileFormats, description);
		files.removeIf(this::isFileInvalid);
		return files;
	}
	
	private boolean isFileInvalid(File file)
	{
		if(file.isDirectory()) return false;
		String fileName = file.getName();
		return !fileFormats.contains(fileName.substring(fileName.lastIndexOf(".")+1));
	}
}