package electrosphere.util;

import com.google.gson.Gson;
import electrosphere.main.Main;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FileUtils {
    
    
    
    static final int maxReadFails = 3;
    static final int READ_TIMEOUT_DURATION = 5;
    public static String readFileToString(File f){
        String rVal = "";
        BufferedReader reader;
        try {
            reader = Files.newBufferedReader(f.toPath());
            int failCounter = 0;
            boolean reading = true;
            StringBuilder builder = new StringBuilder("");
            while(reading){
                if(reader.ready()){
                    failCounter = 0;
                    int nextValue = reader.read();
                    if(nextValue == -1){
                        reading = false;
                    } else {
                        builder.append((char)nextValue);
                    }
                } else {
                    failCounter++;
                    if(failCounter > maxReadFails){
                        reading = false;
                    } else {
                        try {
                            TimeUnit.MILLISECONDS.sleep(READ_TIMEOUT_DURATION);
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
            rVal = builder.toString();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return rVal;
    }
    
    
    public static String readStreamToString(InputStream resourceInputStream){
        String rVal = "";
        BufferedReader reader;
        try {
            reader = new BufferedReader(new InputStreamReader(resourceInputStream));
            int failCounter = 0;
            boolean reading = true;
            StringBuilder builder = new StringBuilder("");
            while(reading){
                if(reader.ready()){
                    failCounter = 0;
                    int nextValue = reader.read();
                    if(nextValue == -1){
                        reading = false;
                    } else {
                        builder.append((char)nextValue);
                    }
                } else {
                    failCounter++;
                    if(failCounter > maxReadFails){
                        reading = false;
                    } else {
                        try {
                            TimeUnit.MILLISECONDS.sleep(READ_TIMEOUT_DURATION);
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
            rVal = builder.toString();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return rVal;
    }
    
    
    
//    public static String sanitizeBakedFilePath(String filePath){
//        String rVal = new String(filePath);
//        rVal = rVal.trim();
//        if(!rVal.startsWith("/")){
//            rVal = "/" + rVal;
//        }
//        return rVal;
//    }
    
    public static String sanitizeFilePath(String filePath){
        String rVal = new String(filePath);
        rVal = rVal.trim();
        if(rVal.startsWith("./")){
            return rVal;
        } else if(!rVal.startsWith("/")){
            rVal = "/" + rVal;
        }
        return rVal;
    }
    
//    public static String readStringFromBakedFile(String bakedFilePath){
//        String rVal = "";
//        String sanitizedFilePath = sanitizeBakedFilePath(bakedFilePath);
//        rVal = readStreamToString(Main.class.getResourceAsStream(sanitizedFilePath));
//        return rVal;
//    }
    
    
    public static void serializeObjectToFilePath(String filePath, Object object){
        Path path = new File(filePath).toPath();
        Gson gson = new Gson();
        try {
            Files.write(path, gson.toJson(object).getBytes());
        } catch (IOException ex) {
            ex.printStackTrace();
            System.exit(1);
        }
    }
    
    public static File getAssetFile(String pathName){
        String sanitizedFilePath = sanitizeFilePath(pathName);
        File targetFile = new File("./assets" + sanitizedFilePath);
        return targetFile;
    }
    
    public static File getSaveFile(String saveName, String pathName){
        String sanitizedFilePath = sanitizeFilePath(pathName);
        String fullPath = "./saves/" + saveName + "/" + sanitizedFilePath;
        System.out.println(fullPath);
        File targetFile = new File(fullPath);
        return targetFile;
    }
    
    public static InputStream getAssetFileAsStream(String pathName) throws IOException{
        String sanitizedFilePath = sanitizeFilePath(pathName);
        File targetFile = new File("./assets" + sanitizedFilePath);
        return Files.newInputStream(targetFile.toPath());
    }
    
    public static String getAssetFileAsString(String pathName) throws IOException{
        String sanitizedFilePath = sanitizeFilePath(pathName);
        File targetFile = new File("./assets" + sanitizedFilePath);
        return Files.readString(targetFile.toPath());
    }
    
    public static <T>T loadObjectFromAssetPath(String pathName, Class<T> className){
        T rVal = null;
        String sanitizedFilePath = sanitizeFilePath(pathName);
        Gson gson = new Gson();
        try {
            rVal = gson.fromJson(Files.newBufferedReader(getAssetFile(sanitizedFilePath).toPath()), className);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return rVal;
    }
    
    public static String getSQLScriptFileAsString(String pathName) throws IOException {
        String sanitizedFilePath = sanitizeFilePath(pathName);
        File targetFile = new File("./Scripts" + sanitizedFilePath);
        return Files.readString(targetFile.toPath());
    }
    
    public static <T>T loadObjectFromSavePath(String saveName, String pathName, Class<T> className){
        T rVal = null;
        String sanitizedFilePath = sanitizeFilePath(pathName);
        Gson gson = new Gson();
        try {
            rVal = gson.fromJson(Files.newBufferedReader(getSaveFile(saveName,sanitizedFilePath).toPath()), className);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return rVal;
    }
    
    /**
     * Checks if a directory exists
     * @param directoryName
     * @return true if directory exists, false otherwise
     */
    public static boolean checkFileExists(String directoryName){
        File targetDir = new File(sanitizeFilePath(directoryName));
        if(targetDir.exists()){
            return true;
        } else {
            return false;
        }
    }
    
    
    /**
     * Trys to create a directory
     * @param directoryName
     * @return true if directory was created, false if it was not
     */
    public static boolean createDirectory(String directoryName){
        String sanitizedPath = "." + sanitizeFilePath(directoryName);
        File targetDir = new File(sanitizedPath);
        if(targetDir.exists()){
            return false;
        } else {
            return targetDir.mkdirs();
        }
    }
    
    
    public static List<String> listDirectory(String directoryName){
        List<String> rVal = new LinkedList();
        String sanitizedPath = sanitizeFilePath(directoryName);
        File targetDir = new File(sanitizedPath);
        String[] files = targetDir.list();
        for(String name : files){
            rVal.add(name);
        }
        return rVal;
    }
    
    
    
    
    
//    public static <T>T loadModelObjectFromBakedJsonFile(String fileName, Class<T> className){
//        T rVal = null;
//        String sanitizedFilePath = sanitizeBakedFilePath(fileName);
//        String rawJSON = readStreamToString(Main.class.getResourceAsStream(sanitizedFilePath));
//        Gson gson = new Gson();
//        rVal = gson.fromJson(rawJSON, className);
//        return rVal;
//    }
//    
//    public static File unpackBakedFileToFilePath(String bakedFilePath){
//        String sanitizedFilePath = sanitizeBakedFilePath(bakedFilePath);
//        if(!Files.exists(new File("./Models").toPath())){
//            try {
//                Files.createDirectory(new File("./Models").toPath());
//            } catch (IOException ex) {
//                ex.printStackTrace();
//            }
//        }
//        File targetFile = new File("." + sanitizedFilePath);
//        try {
//            Files.write(targetFile.toPath(), Main.class.getResourceAsStream(sanitizedFilePath).readAllBytes(),StandardOpenOption.CREATE,StandardOpenOption.WRITE);
//        } catch (IOException ex) {
//            ex.printStackTrace();
//        }
//        return targetFile;
//    }
    
}
