package jp.agentec.adf.util;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by jang on 2017/06/09.
 */

public class TreeUtil {

    private static final String TAG = "TreeUtil";

    private static final String L = "  └-";
    private static final String T = "  ├-";
    private static final String SPACE = "  ";
    private static final String PIPE = "  | ";
    private static StringBuilder sb;

    /**
     * 入力したファイル（フォルダ）パスをルートにして、配下のファイル/フォルダ構造を作成する
     * @param path String
     * @return 構造 String
     */
    public static final String getTreePrint(String path) {
        sb = new StringBuilder();
        Node root = getNode(new File(path));
        paint(root);
        return sb.toString();
    }

    private static final Node getNode(File rootFile) {
        Node node;
        if (rootFile.isDirectory()) {
            Directory dir = new Directory(rootFile.getName());

            // 子要素を作成
            List<Node> children = new ArrayList();
            File[] childfiles = rootFile.listFiles();
            if (childfiles != null && childfiles.length > 0) {
                java.util.Arrays.sort(childfiles, new java.util.Comparator<File>() {
                    @Override
                    public int compare(File file1, File file2){
                        return file1.getName().compareTo(file2.getName());
                    }
                });
                for (File child : childfiles) {
                    Node childNode = getNode(child);
                    children.add(childNode); // 再帰呼び出し
                }
                dir.setChildren(children);
            }
            node = dir;
        } else {
            node = new LocalFile(rootFile.getName(), DateTimeUtil.toString(new Date(rootFile.lastModified()), DateTimeFormat.yyyyMMddHHmmss000_slash));
        }
        return node;
    }

    private static final void paint(Node root) {
        // ディレクトリ内で最後の要素かを表す真偽値のリスト。要素数で深さも表す。
        List<Boolean> isLasts = new ArrayList();
        paintNode(root, isLasts);
    }

    private static final void paintNode(Node node, List<Boolean> isLasts) {
        // 線を表示
        for (int i = 0; i < isLasts.size(); i++) {
            if (i == isLasts.size() - 1) {
                sb.append(isLasts.get(i) ? L : T);

            } else {
                sb.append(isLasts.get(i) ? SPACE : PIPE);
            }
        }

        if (node != null) {
            // 要素を表示
            sb.append(node.getPrint());

            // ディレクトリの場合、再帰的に呼び出し子要素を表示
            if (node instanceof Directory) {
                List<Node> children = ((Directory) node).getChildren();
                if (children != null) {
                    for (int i = 0; i < children.size(); i++) {
                        Node child = children.get(i);
                        isLasts.add(i == children.size() - 1); // 最後の要素かどうか
                        paintNode(child, isLasts); // 再帰呼び出し
                        isLasts.remove(isLasts.size() - 1);
                    }
                }
            }
        } else {
//            Logger.w("TAG", "[paintNode]: node is null");
        }
    }


    static class Directory extends Node {
        private List<Node> children;

        Directory(String name) {
            super(name);
        }

        List<Node> getChildren() {
            return children;
        }

        void setChildren(List<Node> children) {
            this.children = children;
        }
    }

    static class LocalFile extends Node {
        LocalFile(String name) {
            super(name);
        }
        LocalFile(String name, String date) {
            super(name, date);
        }
    }

    static class Node {
        private String name;
        private String date;

        Node(String name) {
            this.name = name;
        }

        Node(String name, String date) {
            this.name = name;
            this.date = date;
        }

        String getName() {
            return name;
        }

        String getPrint() {
            StringBuilder print = new StringBuilder(name);
            if (this instanceof Directory) {
                Directory dir = (Directory)this;
                print.append(" [");
                int size = 0;
                if (dir.getChildren() != null) {
                    size = dir.getChildren().size();
                }
                print.append(size + "]");
            } else {
                // File
                if (date != null && date.length() > 0) {
                    print.append(" (");
                    print.append(date);
                    print.append(")");
                }
            }
            print.append("\n");
            return print.toString();
        }
    }
}
