#!python

import os
import re
import argparse


__version__ = "0.1"


class DirTree:
    def __init__(self, name, parent=None):
        self.parent = parent
        self.name = name
        self.children = []

    @staticmethod
    def load(description):
        """Builds the directory tree from the given description.

        Args:
            description (str): The tree string description. (e.g "foo/bar,baz.quux".)

        Returns:
            The directory tree.
        """
        root = DirTree(os.getcwd())
        current = root
        for token in re.split("([,./])", description):
            if not token or token == ",":
                continue
            elif token == "/":
                if current.children:
                    current = current.children[-1]
            elif token == ".":
                if current.parent:
                    current = current.parent
            else:
                node = DirTree(token, parent=current)
                current.children.append(node)
        return root

    def __iter__(self):
        """Returns all the directory tree paths (leaves). """
        unvisited = list(self.children)
        while unvisited:
            current = unvisited.pop(0)
            if not current.children:
                yield current.path()
            unvisited.extend(current.children)

    def path(self):
        """Returns the path of the current directory.

        Returns:
            The directory path relative to the root node.
        """
        elements = []
        current = self
        while current.parent:
            elements.insert(0, current.name)
            current = current.parent
        return os.path.join(*elements)

    def pprint(self):
        """Pretty-print the directory tree."""

        def _pprint(dir, padding, last_child):

            curr_padding = ""
            next_padding = padding

            if dir.parent:
                curr_padding = padding + ("└─ " if last_child else "├─ ")
                next_padding = padding + ("   " if last_child else "│  ")
                print(curr_padding + dir.name)
            elif dir.children:
                print(".")

            for i, child in enumerate(dir.children):
                _pprint(child, next_padding, i == len(dir.children) - 1)

        _pprint(self, "", 0)

    def __str__(self):
        return f"<{self.__class__.__name__} {self.name}>"

    def __repr__(self):
        return f"{self.__class__.__name__}(name={self.name!r})"


def parse_args():
    parser = argparse.ArgumentParser(allow_abbrev=False, add_help=False)
    parser.add_argument("-h", action="help", help="Print help information.")
    parser.add_argument(
        "-V",
        action="version",
        version=f"%(prog)s {__version__}",
        help="Print version information.",
    )
    parser.add_argument(
        "-v", action="store_true", help="Print a message for each created directory."
    )
    parser.add_argument(
        "-p",
        action="store_true",
        help="Preview the directory tree as a list of directories.",
    )
    parser.add_argument("-P", action="store_true", help="Preview the directory tree.")
    parser.add_argument(
        "-i",
        action="store_true",
        help="Ask before creating the directory tree. Implies -p.",
    )
    parser.add_argument(
        "tree_description",
        metavar="TREE_DESCRIPTION",
        nargs="?",
        default="",
        help="The directory tree descrtiption.",
    )
    return parser.parse_args()


def print_tree(tree, pretty=False):
    if pretty:
        tree.pprint()
    else:
        for path in tree:
            print(path)


def make_tree(tree, verbose=False):
    for path in tree:
        try:
            os.makedirs(path)
            if verbose:
                print(f"created directory {path!r}")
        except FileExistsError:
            pass


def main():

    args = parse_args()
    tree = DirTree.load(args.tree_description)

    if args.i:
        print_tree(tree, pretty=args.P)

        try:
            resp = input("\nAre you sure? [Yn] ")
            if re.match("^(|y|yes|yep)$", resp, flags=re.IGNORECASE):
                make_tree(tree, verbose=args.v)
        except KeyboardInterrupt:
            raise SystemExit

    elif args.p:
        print_tree(tree)

    elif args.P:
        print_tree(tree, pretty=True)

    else:
        make_tree(tree, verbose=args.v)


if __name__ == "__main__":
    main()
