class GenerateUtil {

  static void generateCode(ServiceConfig service, String contractLocation,
      String codeOutput, Map<String, Object> externalConfig, String type) throws IOException {
    CodeGenerator codeGenerator = GeneratorFactory.getGenerator(CodeGenerator.class, type);
    if (codeGenerator == null) {
      throw new RuntimeException("Cannot found code generator's implementation");
    }

    File contractFile = new File(contractLocation);
    if (contractFile.isDirectory()) {

      List<CodegenConfigurator> configurators = new ArrayList<>();
      Files.walkFileTree(Paths.get(contractFile.toURI()), new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
          if (Files.isDirectory(file)) {
            return super.visitFile(file, attrs);
          }

          CodegenConfigurator configurator = new CodegenConfigurator();
          commonConfig(configurator, service);
          configurator.setOutputDir(codeOutput)
              .addAdditionalProperty(GeneratorExternalConfigConstant.PROVIDER_PROJECT_NAME,
                  file.getParent().getFileName() + providerProjectNameSuffix)
              .addAdditionalProperty(GeneratorExternalConfigConstant.CONSUMER_PROJECT_NAME,
                  file.getParent().getFileName() + consumerProjectNameSuffix)
              .addAdditionalProperty(GeneratorExternalConfigConstant.MODEL_PROJECT_NAME,
                  file.getParent().getFileName() + modelProjectNameSuffix)
              .addAdditionalProperty("apiName", file.toFile().getName().split("\\.")[0])
              .addAdditionalProperty("microserviceName", file.getParent().getFileName().toString());

          configurator.setInputSpec(file.toFile().getCanonicalPath());
          configurators.add(configurator);
          return super.visitFile(file, attrs);
        }
      });

      Objects.requireNonNull(codeGenerator).configure(Collections.singletonMap("configurators", configurators));
      codeGenerator.generate();
    } else {

      CodegenConfigurator configurator = new CodegenConfigurator();
      commonConfig(configurator, service);
      configurator.setOutputDir(codeOutput)
          .addAdditionalProperty(GeneratorExternalConfigConstant.PROVIDER_PROJECT_NAME,
              contractFile.getParentFile().getName() + providerProjectNameSuffix)
          .addAdditionalProperty(GeneratorExternalConfigConstant.CONSUMER_PROJECT_NAME,
              contractFile.getParentFile().getName() + consumerProjectNameSuffix)
          .addAdditionalProperty(GeneratorExternalConfigConstant.MODEL_PROJECT_NAME,
              contractFile.getParentFile().getName() + modelProjectNameSuffix)
          .addAdditionalProperty("apiName", contractFile.getName().split("\\.")[0])
          .addAdditionalProperty("microserviceName", contractFile.getParentFile().getName());

      configurator.setInputSpec(contractLocation);
      Objects.requireNonNull(codeGenerator)
          .configure(Collections.singletonMap("configurators", Collections.singletonList(configurator)));
      codeGenerator.generate();
    }
  }

}