package dynamo.manager;

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.DirectoryStream.Filter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import dynamo.backlog.BackLogProcessor;
import dynamo.backlog.TaskSubmission;
import dynamo.backlog.tasks.files.CopyFileTask;
import dynamo.backlog.tasks.files.DeleteTask;
import dynamo.backlog.tasks.files.MoveFileTask;
import dynamo.model.Downloadable;

public class FolderManager {
	
	private final static Logger LOGGER = LoggerFactory.getLogger( FolderManager.class );
	
	private Semaphore folderScanSemaphore = new Semaphore(2);
	
	DirectoryStream.Filter<Path> directoryFilter = new DirectoryStream.Filter<Path>() {
		public boolean accept(Path file) throws IOException {
			return (Files.isDirectory(file));
		}
	};

	private FolderManager() {
	}

	static class SingletonHolder {
		static FolderManager instance = new FolderManager();
	}

	public static FolderManager getInstance() {
		return SingletonHolder.instance;
	}
	
	public static TaskSubmission moveFile( Path source, Path destinationFile, Downloadable downloadable ) {
		return BackLogProcessor.getInstance().schedule( new MoveFileTask( source, destinationFile, downloadable ), false );
	}

	public static TaskSubmission copyFile( Path source, Path destinationFile, Downloadable downloadable ) {
		return BackLogProcessor.getInstance().schedule( new CopyFileTask( source, destinationFile, downloadable ), false );
	}
	
	private List<Path> internal_getContents(Path folder, Filter<Path> filter, boolean recursive) throws InterruptedException, IOException {
		List<Path> results = new ArrayList<>();
		try (DirectoryStream<Path> ds = filter != null ? Files.newDirectoryStream(folder, filter) : Files.newDirectoryStream(folder)) {
			for (Path p : ds) {
				if (Files.isDirectory(p) && recursive) {
					results.addAll( internal_getContents( folder, filter, recursive) );
				} else {
					results.add( p );
				}
			}
		}
		return results;
	}

	public List<Path> getContents(Path folder, Filter<Path> filter, boolean recursive) throws InterruptedException, IOException {
		try {
			acquire();
			return internal_getContents( folder, filter, recursive );
		} finally {
			release();
		}
	}

	private void release() {
		folderScanSemaphore.release();
	}

	private void acquire() throws InterruptedException {
		folderScanSemaphore.acquire();
	}

	public List<Path> getSubFolders(Path folder, boolean recursive) throws InterruptedException, IOException {			
		try {
			acquire();
			return internal_getSubFolders(folder, recursive);
		} finally {
			release();
		}
	}

	private List<Path> internal_getSubFolders(Path folder, boolean recursive) throws IOException {
		List<Path> subFolders = new ArrayList<>();
		try (DirectoryStream<Path> ds = Files.newDirectoryStream(folder, directoryFilter)) {
			for (Path p : ds) {
				subFolders.add( p );
				if (recursive) {
					subFolders.addAll( internal_getSubFolders( folder, recursive) );
				}
			}
		}
		return subFolders;
	}

	public List<Path> getAllFilesFrom( Path folder, boolean deleteEmptyFolders ) throws IOException, InterruptedException {
		List<Path> paths = new ArrayList<>();
		List<Path> contents = getInstance().getContents(folder, null, true);
		for (Path entry : contents) {
			if (Files.isDirectory(entry)) {
				List<Path> folderContents = getAllFilesFrom(entry, deleteEmptyFolders); 
				if (folderContents == null || folderContents.isEmpty()) {
					BackLogProcessor.getInstance().schedule( new DeleteTask( folder, false ));
				} else {
					paths.addAll( folderContents );
				}
			} else {
				paths.add(entry);
			}
		}
		return paths;
	}

}

@@ -1788,32 +1788,80 @@
  ArrayList%3C%3E();%0A
+%09%09List%3CPath%3E folderResults = new ArrayList%3C%3E();%0A
 %09%09try (Directory
@@ -1998,16 +1998,85 @@
  ds) %7B%0A%09
+%09%09%09folderResults.add( p );%0A%09%09%09%7D%0A%09%09%7D%0A%09%09for (Path p : folderResults) %7B%0A
 %09%09%09if (F
@@ -2107,25 +2107,24 @@
 ecursive) %7B%0A
-%09
 %09%09%09%09results.
@@ -2179,25 +2179,24 @@
 cursive) );%0A
-%09
 %09%09%09%7D else %7B%0A
@@ -2199,17 +2199,16 @@
 e %7B%0A%09%09%09%09
-%09
 results.
@@ -2213,30 +2213,24 @@
 s.add( p );%0A
-%09%09%09%09%7D%0A
 %09%09%09%7D%0A%09%09%7D%0A%09%09r

Fix deep iteration & too many open files