package com.janosgyerik.dupfinder.dupfinder;

import java.io.*;
import java.util.*;

public class DuplicateFileFinderImpl implements DuplicateFileFinder {

    private static class ContentComparator implements Comparator<File> {

        private static final int BUFSIZE = 4096;

        private final DuplicateTracker tracker;

        public ContentComparator(DuplicateTracker tracker) {
            this.tracker = tracker;
        }

        @Override
        public int compare(File file1, File file2) {
            int compareFileSize = Long.compare(file1.length(), file2.length());
            if (compareFileSize != 0) {
                return compareFileSize;
            }

            if (file1.length() == 0) {
                tracker.add(file1, file2);
                return 0;
            }

            byte[] buffer1 = new byte[BUFSIZE];
            byte[] buffer2 = new byte[BUFSIZE];

            try (BufferedInputStream stream1 = new BufferedInputStream(new FileInputStream(file1));
                 BufferedInputStream stream2 = new BufferedInputStream(new FileInputStream(file2))) {
                int bytesRead1;
                int bytesRead2;

                while (true) {
                    bytesRead1 = stream1.read(buffer1);
                    bytesRead2 = stream2.read(buffer2);

                    assert bytesRead1 == bytesRead2;

                    if (bytesRead1 == -1) {
                        break;
                    }

                    int compareBuffers = compareBuffers(buffer1, buffer2, bytesRead1);
                    if (compareBuffers != 0) {
                        return compareBuffers;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                return file1.compareTo(file2);
            }

            tracker.add(file1, file2);
            return 0;
        }

        private int compareBuffers(byte[] buffer1, byte[] buffer2, int num) {
            for (int i = 0; i < num; ++i) {
                int compare = Byte.compare(buffer1[i], buffer2[i]);
                if (compare != 0) {
                    return compare;
                }
            }
            return 0;
        }
    }

    private static class DuplicateTracker {
        Map<File, Set<File>> pools = new HashMap<>();

        public void add(File file1, File file2) {
            Set<File> pool1 = pools.get(file1);
            Set<File> pool2 = pools.get(file2);

            final Set<File> pool;

            if (pool1 == null && pool2 == null) {
                pool = new HashSet<>();
                pool.add(file1);
                pool.add(file2);
            } else if (pool1 == null) {
                pool = pool2;
                pool.add(file1);
            } else if (pool2 == null) {
                pool = pool1;
                pool.add(file2);
            } else if (pool1 == pool2) {
                return;
            } else {
                pool = pool1;
                pool.addAll(pool2);
                for (File file : pool2) {
                    pools.put(file, pool);
                }
            }
            pools.put(file1, pool);
            pools.put(file2, pool);
        }

        public Set<Set<File>> getDuplicates() {
            Set<Set<File>> duplicates = new HashSet<>();
            duplicates.addAll(pools.values());
            return duplicates;
        }
    }

    @Override
    public Set<Set<File>> findDuplicates(List<File> files) {
        DuplicateTracker tracker = new DuplicateTracker();
        Collections.sort(files, new ContentComparator(tracker));
        return tracker.getDuplicates();
    }
}

@@ -2472,43 +2472,8 @@
 );%0A%0A
-            final Set%3CFile%3E pool;%0A%0A
     
@@ -2538,16 +2538,17 @@
     pool
+1
  = new H
@@ -2571,32 +2571,33 @@
             pool
+1
 .add(file1);%0A   
@@ -2605,32 +2605,33 @@
             pool
+1
 .add(file2);%0A   
@@ -2643,64 +2643,35 @@
     
-%7D else if (pool1 == null) %7B%0A                pool =
+    pools.put(file1,
  pool
-2
+1)
 ;%0A  
@@ -2688,25 +2688,33 @@
     pool
-.add(file
+s.put(file2, pool
 1);%0A    
@@ -2732,25 +2732,25 @@
 lse if (pool
-2
+1
  == null) %7B%0A
@@ -2765,32 +2765,36 @@
         pool
- = pool1
+2.add(file1)
 ;%0A          
@@ -2803,25 +2803,33 @@
     pool
-.add(file
+s.put(file1, pool
 2);%0A    
@@ -2855,18 +2855,17 @@
 pool
-1
+2
  == 
-pool2
+null
 ) %7B%0A
@@ -2884,36 +2884,66 @@
     
-return;%0A            %7D else %7B
+pool1.add(file2);%0A                pools.put(file2, pool1);
 %0A   
@@ -2955,25 +2955,36 @@
     
-    
+%7D else if (
 pool
- 
+1 !
 = pool
-1;
+2) %7B
 %0A   
@@ -3000,16 +3000,17 @@
     pool
+1
 .addAll(
@@ -3095,24 +3095,25 @@
 t(file, pool
+1
 );%0A         
@@ -3139,80 +3139,8 @@
   %7D%0A
-            pools.put(file1, pool);%0A            pools.put(file2, pool);%0A
     

cut out a pointless intermediary var and reduced pointless statements