package com.graph.db.util;

import static com.graph.db.util.Constants.POISON_PILL;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.zip.GZIPInputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.io.Resources;
import com.graph.db.output.OutputFileType;

public final class FileUtil {
	
    private static final Logger LOGGER = LoggerFactory.getLogger(FileUtil.class);
    
	private FileUtil() {}
	
	public static void writeOutCsvHeader(String outputFolder, String fileTag, Collection<String> collection) {
		String pathname = createHeaderFileName(outputFolder, fileTag);
		writeFile(collection, pathname);
	}

	public static void writeOutCsvFile(String outputFolder, Class<?> c, String fileName, Collection<String> collection) {
		String pathname = outputFolder + File.separator + fileName + Constants.HYPHEN + c.getSimpleName() + ".csv";
		writeFile(collection, pathname);
	}
	
	private static void writeFile(Collection<String> collection, String pathname) {
		LOGGER.info("Writing out: {}", pathname);
		try {
			FileUtils.writeLines(new File(pathname), collection);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static List<File> getAllJsonFiles(String folder) {
		File dir = new File(folder);
		FilenameFilter filter = (directory, name) -> name.toLowerCase().contains(".json");
		File[] files = dir.listFiles(filter);
		if (ArrayUtils.isEmpty(files)) {
			throw new RuntimeException("No files in folder: " + folder);
		}
		return Arrays.asList(files);
	}
	
	public static void logLineNumber(LineNumberReader reader, int threshold) {
		if ((reader.getLineNumber() % threshold) == 0) {
			LOGGER.info("Processed {} lines", reader.getLineNumber());
		}
	}
	
	/**
	 * Consumer of the queue will terminate when it processes the "poison pill"
	 */
	public static void sendPoisonPillToQueue(BlockingQueue<String> queue) {
		try {
			queue.put(POISON_PILL);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static List<String> getLines(String fileName) {
		return getLines(new File(fileName));
	}
	
	public static List<String> getLines(File file) {
		try {
			return FileUtils.readLines(file);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static LineNumberReader getLineNumberReaderForFile(File file) {
		if(isGzipFile(file)) {
			return createLineNumberReaderForGzipFile(file);
		} else {
			try {
				File f;
				if (!file.isFile()) {
					URL resource = Resources.getResource(file.toString());
					f = new File(resource.getFile());
				} else {
					f = file;
				}
				return new LineNumberReader(new FileReader(f));
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}
	
	private static boolean isGzipFile(File fileName) {
		return StringUtils.endsWith(fileName.getName(), "gz");
	}

	private static LineNumberReader createLineNumberReaderForGzipFile(File file) {
		InputStream gzipStream;
		try {
			final InputStream fileStream;
			if (file.isFile()) {
				fileStream = new FileInputStream(file);
			} else {
				URL resource = FileUtil.class.getResource(file.getName());
				fileStream = resource.openStream();
			}
			gzipStream = new GZIPInputStream(fileStream);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		Reader decoder = new InputStreamReader(gzipStream);
		return new LineNumberReader(decoder);
	}
	
	public static String createHeaderFileName(String outputFolder, String fileTag) {
		return outputFolder + File.separator + fileTag + "-header.csv";
	}
	
	public static String createFileName(String outputFolder, Class<?> parserClass, OutputFileType outputFileType) {
		return outputFolder + File.separator + outputFileType.getFileTag() + Constants.HYPHEN + parserClass.getSimpleName() + ".csv";
	}
	
	public static String createUnionedFileName(String outputFolder, String fileTag) {
		return outputFolder + File.separator + fileTag + ".csv";
	}
	
	public static void createFolderIfNotPresent(String folder) {
		Path path = Paths.get(folder);
		if (!Files.isDirectory(path)) {
			try {
				Files.createDirectory(path);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}
}

@@ -1758,221 +1758,461 @@
 %0A%09%0A%09
-public static List%3CFile%3E getAllJsonFiles(String folder) %7B%0A%09%09File dir = new File(folder);%0A%09%09FilenameFilter filter = (directory, name) -%3E name.toLowerCase().contains(%22.json%22);%0A%09%09File%5B%5D files = dir.listFiles(filter);
+/**%0A%09 * First try to load all *.json.gz files, if none present then try to load%0A%09 * *.json files%0A%09 */%0A%09public static List%3CFile%3E getAllJsonFiles(String folder) %7B%0A%09%09File dir = new File(folder);%0A%09%09File%5B%5D filesForType = getAllFilesForType(dir, (directory, name) -%3E name.toLowerCase().endsWith(%22.json.gz%22));%0A%09%09if (ArrayUtils.isEmpty(filesForType)) %7B%0A%09%09%09filesForType = getAllFilesForType(dir, (directory, name) -%3E name.toLowerCase().endsWith(%22.json%22));%0A%09%09%7D%0A%09%09
 %0A%09%09i
@@ -2238,16 +2238,23 @@
 ty(files
+ForType
 )) %7B%0A%09%09%09
@@ -2346,16 +2346,137 @@
 st(files
+ForType);%0A%09%7D%0A%09%0A%09private static File%5B%5D getAllFilesForType(File dir, FilenameFilter filter) %7B%0A%09%09return dir.listFiles(filter
 );%0A%09%7D%0A%09%0A

fix issue where AnnotationParser was loading both .json.gz and .json files, leading to duplicates in the output