class Generator {

    public Path generateProject() throws Exception {
        Path workingDirPath = this.workingDir.toPath();
        Files.createDirectories(workingDirPath);

        // directory to store the template files to generate the java files from
        Path javaTemplateDir = workingDirPath.resolve("../java");
        Files.createDirectories(javaTemplateDir);

        // Copy template project and template java files
        String s = this.getClass().getResource("").getPath();
        if (s.contains("jar!")) {
            Generator.LOGGER.trace("we work on a jar file");
            Generator.LOGGER.trace("Location of the current class: {}", s);

            // we have a jar file
            // format: file:/location...jar!...path-in-the-jar
            // we only want to have location :)
            int excl = s.lastIndexOf("!");
            s = s.substring(0, excl);
            s = s.substring("file:".length());

            try (JarFile jf = new JarFile(s);) {
                Enumeration<JarEntry> entries = jf.entries();
                while (entries.hasMoreElements()) {
                    JarEntry je = entries.nextElement();
                    String name = je.getName();
                    if (name.startsWith(Generator.TEMPLATE_PROJECT_FOLDER + "/") && (name.length() > (Generator.TEMPLATE_PROJECT_FOLDER.length() + 1))) {
                        // strip "template/" from the beginning to have paths without "template" starting relatively from the working dir
                        name = name.substring(Generator.TEMPLATE_PROJECT_FOLDER.length() + 1);
                        if (je.isDirectory()) {
                            // directory found
                            Path dir = workingDirPath.resolve(name);
                            Files.createDirectory(dir);
                        } else {
                            Path file = workingDirPath.resolve(name);
                            try (InputStream is = jf.getInputStream(je);) {
                                Files.copy(is, file, StandardCopyOption.REPLACE_EXISTING);
                            }
                        }
                    } else if (name.startsWith(Generator.TEMPLATE_JAVA_FOLDER + "/") && (name.length() > (Generator.TEMPLATE_JAVA_FOLDER.length() + 1))) {
                        if (!je.isDirectory()) {
                            // we copy the file directly into javaTemplateDir
                            File f = new File(name);
                            Path file = javaTemplateDir.resolve(f.getName());
                            try (InputStream is = jf.getInputStream(je);) {
                                Files.copy(is, file, StandardCopyOption.REPLACE_EXISTING);
                            }
                        }
                    }
                }
            }
        } else {
            // we're running in debug mode, we can work on the plain file system
            File templateProjectDir = new File(this.getClass().getResource("/" + Generator.TEMPLATE_PROJECT_FOLDER).getFile());
            FileUtils.copyDirectory(templateProjectDir, this.workingDir);

            File javaTemplatesDir = new File(this.getClass().getResource("/" + Generator.TEMPLATE_JAVA_FOLDER).getFile());
            FileUtils.copyDirectory(javaTemplatesDir, javaTemplateDir.toFile());
        }

        // Create Java Code Folder
        String[] splitPkg = this.javaPackage.split("\\.");
        StringBuilder javaFolderString = new StringBuilder(this.workingDir.getAbsolutePath() + File.separator + "src" + File.separator + "main" + File.separator + "java");
        for (String value : splitPkg) {
            javaFolderString.append(File.separator).append(value);
        }

        // Copy and rename TEMPLATE_JAVA_TEMPLATE_SERVICE
        Path templateJavaService = javaTemplateDir.resolve(Generator.TEMPLATE_JAVA_TEMPLATE_SERVICE);
        File javaService = new File(javaFolderString + File.separator + this.name + ".java");
        Files.createDirectories(javaService.toPath().getParent());
        Files.copy(templateJavaService, javaService.toPath(), StandardCopyOption.REPLACE_EXISTING);

        this.generateJavaFile(javaService);
        this.updateFilesRecursively(this.workingDir);

        return this.workingDir.toPath();
    }

    public  Generator(TInterface tInterface, String packageAndNamespace, URL iaArtifactTemplateUploadUrl, String name, File workingDir);

}