<filename>pipnest/project.py
import os, json


class ProjectMetadata:
    """
        Description of a metadatum required to fill out a project proposal.
    """

    def __init__(self, name, label, help=None, choices=None, default=None):
        self.name = name
        self.label = label
        self.help = help
        self.choices = choices
        self.default = default
        self.value = None


class ProjectFile:
    """
        Description of a file that is created as part of a project proposal.
    """

    def __init__(self, template):
        self.template = template

    def create(self, proposal, path):
        if os.path.exists(path) and not proposal.overwrite:
            raise FileExistsError("Could not create project. '{}' already exists.".format(path))
        with open(path, "w") as f:
            f.write(self.parse_template(proposal))

    def parse_template(self, proposal):
        with open(os.path.join(os.path.dirname(__file__), "templates", self.template + ".t"), "r") as f:
            template = f.read()
        template = template.replace("%%NAME%%", proposal.name)
        template = template.replace("%%AUTHOR%%", proposal.author)
        template = template.replace("%%EMAIL%%", proposal.email)
        template = template.replace("%%README%%", "README.md")
        template = template.replace("%%REPO%%", "https://github.com/Helveg/pipnest")
        template = template.replace("%%VERSION%%", "0.0.1")
        template = template.replace("%%DESCRIPTION%%", "pip installable NEST extension module, generated by pipnest.")
        template = template.replace("%%LICENSE%%", "MIT")
        if self.template == "setup.py":
            template = template.replace("%%MODULES%%", repr(proposal.get_module_list()))
            template = template.replace("%%PKG_DATA%%", repr(proposal.get_package_data()))
            template = template.replace("%%CMAKE_EXTENSIONS%%", "[" + ", ".join(["cmake_extension(\"" + m + "\")" for m in proposal.get_module_list()]) + "]")
        return template

_project_meta = [
    ProjectMetadata(
        name="author",
        label="Author",
        help="Name of the primary author"
    ),
    ProjectMetadata(
        name="email",
        label="Email",
        help="Email address of the primary author"
    ),
]


_project_structure = {
    "setup.py": ProjectFile("setup.py"),
    "README.md": ProjectFile("README.md"),
    "MANIFEST.in": ProjectFile("MANIFEST.in"),
    ".gitignore": ProjectFile(".gitignore"),
    ".pipnest": {"settings": ProjectFile("settings")},
}


class ProjectProposal:
    """
        A project proposal describes a project before it is created.
    """
    def __init__(self, dir, author, email, overwrite=False):
        self.dir = dir
        self.name = self._get_project_name(dir)
        self.author = author
        self.email = email
        self.overwrite = overwrite

    def _get_project_name(self, dir):
        return (os.getcwd() if dir == "." else dir).split(os.path.sep)[-1]

    @classmethod
    def from_args(cls, args):
        kwargs = {"dir": args.directory, "overwrite": args.force}
        meta_kwargs = {m.name: args.__dict__[m.name] for m in _project_meta}
        kwargs.update(meta_kwargs)
        return cls(**kwargs)

    def create(self):
        folder = lambda *x: os.path.join(*x)

        def rec(f, s, root=False):
            if isinstance(s, ProjectFile):
                s.create(self, f)
            else:
                try:
                    os.mkdir(f)
                except FileExistsError:
                    pass
                for sf, ss in s.items():
                    rec(folder(f, sf), ss)

        rec(self.dir, _project_structure, root=True)

    def get_module_list(self):
        modules = []
        for f in os.listdir(self.dir):
            if os.path.isdir(f):
                for c in os.listdir(os.path.join(self.dir, f)):
                    if c.endswith(".cpp"):
                        modules.append(f)
                        break
        return modules

    def get_package_data(self):
        modules = self.get_module_list()
        return {m: ["*", "sli/*", "doc/*"] for m in modules}
