import os

def split_path(path):
    folders = []
    while True:
        path, folder = os.path.split(path)
        if folder != "":
            folders.append(folder)
        else:
            if path != "":
                folders.append(path)
            break
    folders.reverse()
    return folders

def lex_file(path):
    stream = []
    try:
        text = ""
        with open(path, 'r') as f:
            for line in f:
                for char in line:
                    if text[-3:] == "\[[":
                        text = text.replace("\[[", "[[")
                    elif text[-3:] == "\]]":
                        text = text.replace("\]]", "]]")
                    elif text[-3:] == "\{{":
                        text = text.replace("\{{", "{{")
                    elif text[-3:] == "\}}":
                        text = text.replace("\}}", "}}")
                    elif text[-2:] == "[[": # key start
                        stream.append(text[:-2])
                        stream.append("[[")
                        text = ""
                    elif text[-2:] == "]]": # key end
                        stream.append(text[:-2])
                        stream.append("]]")
                        text = ""
                    elif text[-2:] == "{{": # left macro expansion
                        stream.append(text[:-2])
                        stream.append("{{")
                        text = ""
                    elif text[-2:] == "}}": # right macro expansion
                        stream.append(text[:-2])
                        stream.append("}}")
                        text = ""
                    text = text + char
        stream.append(text)
    except IOError as error:
        pass
    return stream

class Tree:
    def __init__(self, path):
        initial_name = split_path(path)[-1]
        self.macros = {}
        self.options = {}
        self.model = {}
        self.children = []
        self.parent = None
        self.file_paths = []
        self.files = []
        self.name = initial_name

        for name in os.listdir(path):
            next_path = os.path.join(path, name)
            if os.path.isdir(next_path):
                tree = Tree(next_path)
                tree.parent = self
                self.children.append(tree)
            else:
                if name == "macros":
                    self.macros = self.parse_file(next_path, False)
                elif name == "options":
                    self.options = self.parse_file(next_path, False)
                elif name == "model":
                    self.model = self.parse_file(next_path, True)
                    if "name" not in self.model:
                        raise ValueError("Model file must specify a `name`")
                else:
                    self.file_paths.append(next_path)

    def get_full_name(self):
        result = []
        full_name = ""
        prefix_name = ""
        tree = self
        while tree.parent:
            result.append(tree.name)
            tree = tree.parent
        result.append(tree.name)
        for name in reversed(result):
            full_name = full_name + name + "::"
        for name in reversed(result):
            prefix_name = prefix_name + name + "/"

        return full_name[:-2], prefix_name

    def expand_macro(self, name):
        tree = self
        while tree.parent:
            if name in tree.macros:
                return tree.macros[name]
            tree = tree.parent
        if name in tree.macros:
            return tree.macros[name]
        return None

    def find_model(self):
        tree = self
        while tree.parent:
            if tree.model: