// Path: src/main/java/com/superzanti/serversync/files/FileHash.java
// public class FileHash {
//     public static String hashFile(Path file) {
//         try {
//             InputStream stream = null;
//             if( FileHash.isBinaryFile(file) ){
//                 stream = Files.newInputStream(file);
//             }else{
//                 stream = new ByteArrayInputStream(String.join("", Files.readAllLines(file, StandardCharsets.UTF_8)).getBytes(StandardCharsets.UTF_8));
//             }
// 
//             DigestInputStream in = new DigestInputStream(
//                 new BufferedInputStream(stream),
//                 MessageDigest.getInstance("SHA-256")
//             );
// 
//             byte[] buffer = new byte[8192];
//             while (in.read(buffer) > -1) { }
//             return String.format("%064x", new BigInteger(1, in.getMessageDigest().digest()));
//         } catch (Exception e) {
//             Logger.debug(String.format("Failed to hash file: %s", file));
//             Logger.debug(e);
//         }
//         return "";
//     }
// 
//     private static boolean isBinaryFile(Path f) throws IOException {
//         String[] textMime = {"text", "application/xml", "application/json", "application/javascript", "application/vnd.ms-excel"};
// 
//         String type = Files.probeContentType(f);
//         //type isn't text
//         if (type == null) {
//             //type couldn't be determined, guess via first 8192 bytes
//             try (InputStream stream = new BufferedInputStream(Files.newInputStream(f))) {
//                 byte[] buffer = new byte[8192];
//                 int read = stream.read(buffer);
//                 for( int i = 0; i < read; i++ ){
//                     if(buffer[i] == 0x00) return true;
//                 }
//                 return false;
//             }
//         } else return Arrays.stream(textMime).noneMatch(type::startsWith);
//     }
// }
// 
// Path: src/main/java/com/superzanti/serversync/util/Logger.java
// public class Logger {
//     public static LoggerInstance instance = null;
//     private static final Object mutex = new Object();
//     private static Handler uiHandler;
// 
//     // Probably a heinous implementation of debounce but whatever
//     private static final long dbTimeMS = 2000L;
//     private static final ScheduledExecutorService dbRunner = Executors.newSingleThreadScheduledExecutor();
//     private static ScheduledFuture<?> waitingFlush;
// 
//     public static String getContext() {
//         return ServerSync.MODE == null ? "undefined" : ServerSync.MODE.toString();
//     }
// 
//     public static LoggerInstance getInstance() {
//         LoggerInstance result = instance;
//         if (result == null) {
//             //synchronized block to remove overhead
//             synchronized (mutex) {
//                 result = instance;
//                 if (result == null) {
//                     // if instance is null, initialize
//                     instance = result = new LoggerInstance(getContext());
//                 }
//             }
//         }
//         return result;
//     }
// 
//     public static void instantiate(String context) {
//         instance = new LoggerInstance(context);
//     }
// 
//     public static synchronized void setSystemOutput(boolean output) {
//         // enable/disable System.out logging
//         getInstance().javaLogger.setUseParentHandlers(output);
//     }
// 
//     public static synchronized void log(String s) {
//         getInstance().log(s);
//     }
// 
//     public static synchronized void error(String s) {
//         getInstance().error(s);
//     }
// 
//     public static synchronized void debug(String s) {
//         getInstance().debug(s);
//     }
// 
//     public static synchronized void debug(Exception e) {
//         getInstance().debug(Arrays.toString(e.getStackTrace()));
//     }
// 
//     public static synchronized void outputError(Object object) {
//         getInstance().debug("Failed to write object (" + object + ") to output stream");
//     }
// 
//     public static synchronized void attachUIHandler(Handler handler) {
//         if (uiHandler != null) {
//             uiHandler.close();
//             getInstance().javaLogger.removeHandler(uiHandler);
//         }
//         uiHandler = handler;
//         getInstance().javaLogger.addHandler(uiHandler);
//     }
// 
//     public static synchronized void flush() {
//         if (uiHandler != null) {
//             if (waitingFlush == null || waitingFlush.isDone()) {
//                 waitingFlush = dbRunner.schedule(() -> {
//                     uiHandler.flush();
//                 }, dbTimeMS, TimeUnit.MILLISECONDS);
//             }
//         }
//     }
// }


import com.superzanti.serversync.files.FileHash;
import com.superzanti.serversync.util.Logger;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.nio.file.Path;
import java.nio.file.Paths;
package com.superzanti.serversync;



class LineFeedTest {

    public LineFeedTest() {
        Logger.instantiate("test");
    }


    @Test
    @DisplayName("Should hash text files ignoring line feeds")
    void textHash() {
        // We know these resource files will not be null
        Path crlf = Paths.get(getClass().getResource("/hash_crlf.txt").getPath().substring(1));
        Path lf = Paths.get(getClass().getResource("/hash_lf.txt").getPath().substring(1));

        String hashLF = FileHash.hashFile(lf);
// Path: src/main/java/com/superzanti/serversync/files/FileHash.java
// public class FileHash {
//     public static String hashFile(Path file) {
//         try {
//             InputStream stream = null;
//             if( FileHash.isBinaryFile(file) ){
//                 stream = Files.newInputStream(file);
//             }else{
//                 stream = new ByteArrayInputStream(String.join("", Files.readAllLines(file, StandardCharsets.UTF_8)).getBytes(StandardCharsets.UTF_8));
//             }
// 
//             DigestInputStream in = new DigestInputStream(
//                 new BufferedInputStream(stream),
//                 MessageDigest.getInstance("SHA-256")
//             );
// 
//             byte[] buffer = new byte[8192];
//             while (in.read(buffer) > -1) { }
//             return String.format("%064x", new BigInteger(1, in.getMessageDigest().digest()));
//         } catch (Exception e) {
//             Logger.debug(String.format("Failed to hash file: %s", file));
//             Logger.debug(e);
//         }
//         return "";
//     }
// 
//     private static boolean isBinaryFile(Path f) throws IOException {
//         String[] textMime = {"text", "application/xml", "application/json", "application/javascript", "application/vnd.ms-excel"};
// 
//         String type = Files.probeContentType(f);
//         //type isn't text
//         if (type == null) {
//             //type couldn't be determined, guess via first 8192 bytes
//             try (InputStream stream = new BufferedInputStream(Files.newInputStream(f))) {
//                 byte[] buffer = new byte[8192];
//                 int read = stream.read(buffer);
//                 for( int i = 0; i < read; i++ ){
//                     if(buffer[i] == 0x00) return true;
//                 }
//                 return false;
//             }
//         } else return Arrays.stream(textMime).noneMatch(type::startsWith);
//     }
// }
// 
// Path: src/main/java/com/superzanti/serversync/util/Logger.java
// public class Logger {
//     public static LoggerInstance instance = null;
//     private static final Object mutex = new Object();
//     private static Handler uiHandler;
// 
//     // Probably a heinous implementation of debounce but whatever
//     private static final long dbTimeMS = 2000L;
//     private static final ScheduledExecutorService dbRunner = Executors.newSingleThreadScheduledExecutor();
//     private static ScheduledFuture<?> waitingFlush;
// 
//     public static String getContext() {
//         return ServerSync.MODE == null ? "undefined" : ServerSync.MODE.toString();
//     }
// 
//     public static LoggerInstance getInstance() {
//         LoggerInstance result = instance;
//         if (result == null) {
//             //synchronized block to remove overhead
//             synchronized (mutex) {
//                 result = instance;
//                 if (result == null) {
//                     // if instance is null, initialize
//                     instance = result = new LoggerInstance(getContext());
//                 }
//             }
//         }
//         return result;
//     }
// 
//     public static void instantiate(String context) {
//         instance = new LoggerInstance(context);
//     }
// 
//     public static synchronized void setSystemOutput(boolean output) {
//         // enable/disable System.out logging
//         getInstance().javaLogger.setUseParentHandlers(output);
//     }
// 
//     public static synchronized void log(String s) {
//         getInstance().log(s);
//     }
// 
//     public static synchronized void error(String s) {
//         getInstance().error(s);
//     }
// 
//     public static synchronized void debug(String s) {
//         getInstance().debug(s);
//     }
// 
//     public static synchronized void debug(Exception e) {
//         getInstance().debug(Arrays.toString(e.getStackTrace()));
//     }
// 
//     public static synchronized void outputError(Object object) {
//         getInstance().debug("Failed to write object (" + object + ") to output stream");
//     }
// 
//     public static synchronized void attachUIHandler(Handler handler) {
//         if (uiHandler != null) {
//             uiHandler.close();
//             getInstance().javaLogger.removeHandler(uiHandler);
//         }
//         uiHandler = handler;
//         getInstance().javaLogger.addHandler(uiHandler);
//     }
// 
//     public static synchronized void flush() {
//         if (uiHandler != null) {
//             if (waitingFlush == null || waitingFlush.isDone()) {
//                 waitingFlush = dbRunner.schedule(() -> {
//                     uiHandler.flush();
//                 }, dbTimeMS, TimeUnit.MILLISECONDS);
//             }
//         }
//     }
// }


// Path: src/test/java/com/superzanti/serversync/LineFeedTest.java
import com.superzanti.serversync.files.FileHash;
import com.superzanti.serversync.util.Logger;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.nio.file.Path;
import java.nio.file.Paths;

package com.superzanti.serversync;



class LineFeedTest {

    public LineFeedTest() {
        Logger.instantiate("test");
    }


    @Test
    @DisplayName("Should hash text files ignoring line feeds")
    void textHash() {
        // We know these resource files will not be null
        Path crlf = Paths.get(getClass().getResource("/hash_crlf.txt").getPath().substring(1));
        Path lf = Paths.get(getClass().getResource("/hash_lf.txt").getPath().substring(1));

        String hashLF = FileHash.hashFile(lf);
        String hashCRLF = FileHash.hashFile(crlf);