package com.kodcu.service.extension;

import com.kodcu.other.IOHelper;
import org.springframework.stereotype.Component;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Optional;

/**
 * Created by usta on 16.03.2015.
 */
@Component
public class AsciiTreeGenerator {

    public String generate(Path path) {
        return this.printDirectoryTree(path);
    }

    private String printDirectoryTree(Path folder) {
        int indent = 0;
        Tree root = createInitialTree(folder, indent, new Tree());
        root.setSiblingAndParent();

        StringBuilder sb = new StringBuilder();
        root.generateTree(sb);

        return sb.toString();
    }

    private Tree createInitialTree(Path folder, int indent, Tree tree) {
        tree.setDepth(indent);
        tree.setName(folder.getFileName().toString());

        IOHelper.list(folder).forEach(p -> {
            if (IOHelper.isHidden(p))
                return;

            if (Files.isDirectory(p))
                tree.getChildren().add(createInitialTree(p, indent + 1, new Tree()));
            else
                createChild(p, indent + 1, tree);
        });
        return tree;
    }

    private void createChild(Path file, int indent, Tree parent) {
        final Tree child = new Tree();
        child.setName(file.getFileName().toString());
        child.setDepth(indent);
        parent.getChildren().add(child);
    }

    private class Tree {

        private int depth;
        private String name;
        private Tree parent;
        private Tree sibling;
        private ArrayList<Tree> children;

        private Tree getNextSibling() {
            return sibling;
        }

        private void setNextSibling(Tree sibling) {
            this.sibling = sibling;
        }

        private ArrayList<Tree> getChildren() {
            if (Objects.isNull(children))
                children = new ArrayList<>();

            return children;
        }

        private void setChildren(ArrayList<Tree> children) {
            this.children = children;
        }

        private int getDepth() {
            return depth;
        }

        private void setDepth(int depth) {
            this.depth = depth;
        }

        private String getName() {
            return name;
        }

        private void setName(String name) {
            this.name = name;
        }

        private Tree getParent() {
            return parent;
        }

        private void setParent(Tree next) {
            this.parent = next;
        }

        private void setSiblingAndParent() {
            this.setSiblingAndParent(this);
        }

        private void setSiblingAndParent(Tree item) {
            ArrayList<Tree> children = item.getChildren();
            for (int index = 0; index < children.size(); index++) {
                Tree currentChild = children.get(index);
                currentChild.setParent(item);
                if (index != children.size() - 1) {
                    currentChild.setNextSibling(children.get(index + 1));
                }
                setSiblingAndParent(currentChild);
            }
        }

        private void generateTree(StringBuilder sb) {
            generateTree(this, sb);
        }

        private void generateTree(Tree tree, StringBuilder sb) {
            printFile(sb, tree);

            if (Objects.nonNull(tree.getChildren())) {
                for (int index = 0; index < tree.getChildren().size(); index++) {
                    generateTree(tree.getChildren().get(index), sb);
                }
            }
        }

        private void printFile(StringBuilder sb, Tree leaf) {
            sb.append(getIndentString(leaf));

            if (Objects.nonNull(leaf.getParent())) {
                if (Objects.isNull(leaf.getNextSibling()))
                    sb.append("`--");
                else
                    sb.append("|--");
            }

            sb.append(leaf.getName());
            sb.append("\n");
        }

        private String getIndentString(Tree leaf) {
            StringBuilder sb = new StringBuilder();
            Optional<Tree> localTree = Optional.of(leaf);

            for (int index = 1; index < leaf.getDepth(); index++) {
                localTree = Optional.ofNullable(localTree.get().getParent());
                localTree.ifPresent(p -> {
                    if (Objects.nonNull(p.getNextSibling()))
                        sb.append("  |");
                    else
                        sb.append("   ");
                });
            }
            return sb.reverse().toString();
        }
    }
}

@@ -1630,33 +1630,253 @@
 ate 
-ArrayList%3CTree%3E children;
+boolean lastChild;%0A        private ArrayList%3CTree%3E children;%0A%0A        public boolean isLastChild() %7B%0A            return lastChild;%0A        %7D%0A%0A        public void setLastChild(boolean lastChild) %7B%0A            this.lastChild = lastChild;%0A        %7D
 %0A%0A  
@@ -2232,118 +2232,8 @@
  %7D%0A%0A
-        private void setChildren(ArrayList%3CTree%3E children) %7B%0A            this.children = children;%0A        %7D%0A%0A
     
@@ -2789,16 +2789,54 @@
 (this);%0A
+            this.findLastChild(this);%0A
         
@@ -3334,32 +3334,382 @@
    %7D%0A        %7D%0A%0A
+        private void findLastChild(Tree currentChild) %7B%0A            if (currentChild.getChildren().size() == 0)%0A                currentChild.setLastChild(true);%0A            else %7B%0A                int lastIndex = currentChild.getChildren().size() - 1;%0A                findLastChild(currentChild.getChildren().get(lastIndex));%0A            %7D%0A        %7D%0A%0A
         private 
@@ -3750,32 +3750,37 @@
 ) %7B%0A            
+this.
 generateTree(thi
@@ -3913,195 +3913,80 @@
     
-if (Objects.nonNull(tree.getChildren())) %7B%0A                for (int index = 0; index %3C tree.getChildren().size(); index++) %7B%0A                    generateTree(tree.getChildren().get(index)
+tree.getChildren().forEach(child -%3E %7B%0A                generateTree(child
 , sb
@@ -4004,27 +4004,11 @@
     
- 
-   %7D%0A            %7D
+%7D);
 %0A   
@@ -4383,24 +4383,65 @@
 getName());%0A
+            if (!leaf.isLastChild())%0A    
             

Find last child of a tree