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.List;
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 boolean lastChild;
private List<Tree> children;
public boolean isLastChild() {
return lastChild;
}
public void setLastChild(boolean lastChild) {
this.lastChild = lastChild;
}
private Tree getNextSibling() {
return sibling;
}
private void setNextSibling(Tree sibling) {
this.sibling = sibling;
}
private List<Tree> getChildren() {
if (Objects.isNull(children))
children = new ArrayList<>();
return 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);
this.findLastChild(this);
}
private void setSiblingAndParent(Tree item) {
List<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 findLastChild(Tree currentChild) {
if (currentChild.getChildren().size() == 0)
currentChild.setLastChild(true);
else {
int lastIndex = currentChild.getChildren().size() - 1;
findLastChild(currentChild.getChildren().get(lastIndex));
}
}
private void generateTree(StringBuilder sb) {
this.generateTree(this, sb);
}
private void generateTree(Tree tree, StringBuilder sb) {
printFile(sb, tree);
tree.getChildren().forEach(child -> {
generateTree(child, 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());
if (!leaf.isLastChild())
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();
}
}
}