package ee.shy.core.diff;

import ee.shy.core.Tree;
import ee.shy.core.TreeItem;
import ee.shy.storage.DataStorage;

import java.io.IOException;
import java.util.*;
import java.util.function.BiFunction;

public class TreeDiffer implements Differ<Tree> {

    private final DataStorage storage;

    public TreeDiffer(DataStorage storage) {
        this.storage = storage;
    }

    @Override
    public List<String> diff(Tree original, Tree revised) throws IOException {
        List<String> diffStrings = new ArrayList<>();
        Map<String, TreeItem> originalItems = original.getItems();
        Map<String, TreeItem> revisedItems = revised.getItems();

        Set<String> unionTreeKeySet = new HashSet<>();
        unionTreeKeySet.addAll(originalItems.keySet());
        unionTreeKeySet.addAll(revisedItems.keySet());

        Map<ItemCase, BiFunction<TreeItem, TreeItem, List<String>>> itemCases = new HashMap<>();

        itemCases.put(new ItemCase(true, true, TreeItem.Type.FILE, TreeItem.Type.FILE),
                (originalItem, revisedItem) -> {
                    try {
                        return new InputStreamDiffer().diff(
                                storage.get(originalItem.getHash()),
                                storage.get(revisedItem.getHash())
                        );
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });

        for (String name : unionTreeKeySet) {
            ItemCase itemCase = new ItemCase(
                    originalItems.containsKey(name),
                    revisedItems.containsKey(name),
                    originalItems.get(name).getType(),
                    revisedItems.get(name).getType()
            );
            BiFunction<TreeItem, TreeItem, List<String>> treeItemTreeItemListBiFunction = itemCases.get(itemCase);
            if (treeItemTreeItemListBiFunction != null) {
                List<String> singleDiffStrings = treeItemTreeItemListBiFunction.apply(originalItems.get(name), revisedItems.get(name));
                diffStrings.addAll(singleDiffStrings);
            }
        }
        return diffStrings;
    }

    private static class ItemCase {
        private final boolean originalContains;
        private final boolean revisedContains;
        private final TreeItem.Type originalType;
        private final TreeItem.Type revisedType;

        private ItemCase(boolean originalContains, boolean revisedContains, TreeItem.Type originalType, TreeItem.Type revisedType) {
            this.originalContains = originalContains;
            this.revisedContains = revisedContains;
            this.originalType = originalType;
            this.revisedType = revisedType;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            ItemCase itemCase = (ItemCase) o;

            if (originalContains != itemCase.originalContains)
                return false;
            if (revisedContains != itemCase.revisedContains)
                return false;
            if (originalType != itemCase.originalType)
                return false;
            return revisedType == itemCase.revisedType;

        }

        @Override
        public int hashCode() {
            int result = (originalContains ? 1 : 0);
            result = 31 * result + (revisedContains ? 1 : 0);
            result = 31 * result + originalType.hashCode();
            result = 31 * result + revisedType.hashCode();
            return result;
        }
    }

}

@@ -161,46 +161,8 @@
 l.*;
-%0Aimport java.util.function.BiFunction;
 %0A%0Apu
@@ -807,52 +807,23 @@
 se, 
-BiFunction%3CTreeItem, TreeItem, List%3CString%3E%3E
+ItemCaseHandler
 %3E it
@@ -889,20 +889,8 @@
 ase(
-true, true, 
 Tree
@@ -972,18 +972,16 @@
 Item) -%3E
- %7B
 %0A       
@@ -997,107 +997,41 @@
     
-try %7B%0A                        return new InputStreamDiffer().diff(%0A                                
+    new InputStreamDiffer().diff(
 stor
@@ -1066,40 +1066,8 @@
 ()),
-%0A                               
  sto
@@ -1101,324 +1101,178 @@
 h())
-%0A                        );%0A                    %7D catch (IOException e) %7B%0A                        throw new RuntimeException(e);%0A                    %7D%0A                %7D);%0A%0A        for (String name : unionTreeKeySet) %7B%0A            ItemCase itemCase = new ItemCase(%0A                    originalItems.containsKey
+));%0A%0A        for (String name : unionTreeKeySet) %7B%0A            TreeItem originalItem = originalItems.get(name);%0A            TreeItem revisedItem = revisedItems.get
 (name)
-,
+;
 %0A   
@@ -1284,47 +1284,41 @@
     
-        revisedItems.containsKey(name),
+ItemCase itemCase = new ItemCase(
 %0A   
@@ -1342,35 +1342,47 @@
 originalItem
-s.get(name)
+ != null ? originalItem
 .getType(),%0A
@@ -1379,16 +1379,23 @@
 etType()
+ : null
 ,%0A      
@@ -1419,27 +1419,38 @@
 isedItem
-s.get(name)
+ != null ? revisedItem
 .getType
@@ -1451,16 +1451,23 @@
 etType()
+ : null
 %0A       
@@ -1490,52 +1490,23 @@
     
-BiFunction%3CTreeItem, TreeItem, List%3CString%3E%3E
+ItemCaseHandler
  tre
@@ -1702,13 +1702,14 @@
 ion.
-apply
+handle
 (ori
@@ -1717,27 +1717,16 @@
 inalItem
-s.get(name)
 , revise
@@ -1730,27 +1730,16 @@
 isedItem
-s.get(name)
 );%0A     
@@ -1887,103 +1887,8 @@
 e %7B%0A
-        private final boolean originalContains;%0A        private final boolean revisedContains;%0A
     
@@ -2012,59 +2012,8 @@
 ase(
-boolean originalContains, boolean revisedContains, 
 Tree
@@ -2069,114 +2069,8 @@
 ) %7B%0A
-            this.originalContains = originalContains;%0A            this.revisedContains = revisedContains;%0A
     
@@ -2421,192 +2421,8 @@
 o;%0A%0A
-            if (originalContains != itemCase.originalContains)%0A                return false;%0A            if (revisedContains != itemCase.revisedContains)%0A                return false;%0A
     
@@ -2645,25 +2645,24 @@
 esult = 
-(
 original
 Contains
@@ -2653,33 +2653,58 @@
 original
-Contains ? 1
+Type != null ? originalType.hashCode()
  : 0
-)
 ;%0A      
@@ -2744,85 +2744,77 @@
 ised
-Contains ? 1 : 0);%0A            result = 31 * result + originalType.hashCode()
+Type != null ? revisedType.hashCode() : 0);%0A            return result
 ;%0A  
@@ -2823,95 +2823,141 @@
     
+%7D%0A
     
-result = 31 * result + revisedType.hashCode();%0A            return result;%0A        %7D
+%7D%0A%0A    private interface ItemCaseHandler %7B%0A        List%3CString%3E handle(TreeItem original, TreeItem revised) throws IOException;
 %0A   

Replace Bifunction with ItemCaseHandler