/**
   * Generates assembler classes if the API returns more than one object.
   *
   * @param resources
   * @param templateGroup
   */
  private void generateModelClassesForInput(
      List<Resource> resources, StringTemplateGroup templateGroup) {
    List<String> generatedClasses = new ArrayList<String>();
    for (Resource resource : resources) {
      if (resource.getEndPoints() != null) {
        for (Endpoint endpoint : resource.getEndPoints()) {
          if (endpoint.getOperations() != null) {
            for (EndpointOperation operation : endpoint.getOperations()) {
              ResourceMethod method =
                  operation.generateMethod(
                      endpoint, resource, dataTypeMappingProvider, nameGenerator);
              if (method.getInputModel() != null) {
                Model model = method.getInputModel();
                if (model != null) {
                  if (!generatedClasses.contains(model.getName())) {
                    List<String> imports = new ArrayList<String>();
                    imports.addAll(this.config.getDefaultModelImports());
                    for (ModelField param : model.getFields()) {
                      param.setName(reservedWordMapper.translate(param.getName()));
                      for (String importDef :
                          param
                              .getFieldDefinition(
                                  this.getDataTypeMappingProvider(), config, nameGenerator)
                              .getImportDefinitions()) {
                        if (!imports.contains(importDef)) {
                          imports.add(importDef);
                        }
                      }
                    }
                    StringTemplate template = templateGroup.getInstanceOf(MODEL_OBJECT_TEMPLATE);

                    template.setAttribute("fields", model.getFields());
                    template.setAttribute("imports", imports);
                    template.setAttribute("extends", config.getDefaultModelBaseClass());
                    template.setAttribute(
                        "annotationPackageName", languageConfig.getAnnotationPackageName());
                    template.setAttribute("className", model.getGenratedClassName());
                    template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
                    File aFile =
                        new File(
                            languageConfig.getModelClassLocation()
                                + model.getGenratedClassName()
                                + languageConfig.getClassFileExtension());
                    writeFile(aFile, template.toString(), "Input model class");
                    generatedClasses.add(model.getName());
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  /**
   * Generates one API class for each resource and each end point in the resource is translated as
   * method.
   *
   * @param resources
   * @param templateGroup
   */
  private void generateAPIClasses(List<Resource> resources, StringTemplateGroup templateGroup) {

    for (Resource resource : resources) {
      try {
        List<ResourceMethod> methods = new ArrayList<ResourceMethod>();
        List<String> imports = new ArrayList<String>();
        imports.addAll(this.config.getDefaultServiceImports());
        methods =
            resource.generateMethods(
                resource, dataTypeMappingProvider, nameGenerator, languageConfig);
        StringTemplate template = templateGroup.getInstanceOf(API_OBJECT_TEMPLATE);
        String className = resource.generateClassName(nameGenerator);

        if (className != null) {
          List<ResourceMethod> filteredMethods = new ArrayList<ResourceMethod>();
          for (ResourceMethod method : methods) {
            if (!this.getCodeGenRulesProvider().isMethodIgnored(className, method.getName())) {
              filteredMethods.add(method);
            }
          }
          template.setAttribute("imports", imports);
          template.setAttribute(PACKAGE_NAME, config.getApiPackageName());
          template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
          template.setAttribute("modelPackageName", config.getModelPackageName());
          template.setAttribute("exceptionPackageName", languageConfig.getExceptionPackageName());
          template.setAttribute("resource", className);
          template.setAttribute("methods", filteredMethods);
          template.setAttribute("extends", config.getServiceBaseClass(className));

          File aFile =
              new File(
                  languageConfig.getResourceClassLocation()
                      + resource.generateClassName(nameGenerator)
                      + languageConfig.getClassFileExtension());
          writeFile(aFile, template.toString(), "API Classes");
        }
      } catch (RuntimeException t) {
        System.out.println(
            "Failed generating api class for the resource : " + resource.getResourcePath());
        throw t;
      }
    }
  }
  /**
   * Creates a wrapper model class that contains all model classes as list of objects. This class is
   * used for storing test data
   */
  private void generateWrapperClassForTestData(
      List<String> generatedClassNames, StringTemplateGroup templateGroup) {
    Model model = new Model();
    model.setName("TestData");
    model.setDescription(
        "Class used to store all the test data. This should not be used for any development");
    List<ModelField> modelFields = new ArrayList<ModelField>();
    model.setFields(modelFields);
    for (String className : generatedClassNames) {
      ModelField aParam = new ModelField();
      aParam.setName(this.getNameGenerator().applyMethodNamingPolicy(className) + "List");
      aParam.setParamType(this.getDataTypeMappingProvider().getListReturnTypeSignature(className));
      modelFields.add(aParam);
    }

    List<String> imports = new ArrayList<String>();
    imports.addAll(this.config.getDefaultModelImports());
    imports.addAll(this.getDataTypeMappingProvider().getListIncludes());
    for (ModelField param : model.getFields()) {
      for (String importDef :
          param
              .getFieldDefinition(this.getDataTypeMappingProvider(), config, nameGenerator)
              .getImportDefinitions()) {
        if (!imports.contains(importDef)) {
          imports.add(importDef);
        }
      }
    }
    StringTemplate template = templateGroup.getInstanceOf(MODEL_OBJECT_TEMPLATE);
    template.setAttribute("fields", model.getFields());
    template.setAttribute("imports", imports);
    template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
    template.setAttribute("extends", config.getDefaultModelBaseClass());
    template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
    template.setAttribute("className", model.getGenratedClassName());
    File aFile =
        new File(
            languageConfig.getModelClassLocation()
                + model.getGenratedClassName()
                + languageConfig.getClassFileExtension());
    writeFile(aFile, template.toString(), "Wrapper class for test data file");
  }
 /**
  * Generates version file based on the version number received from the doc calls. This version
  * file is used while making the API calls to make sure Client and back end are compatible.
  *
  * @param version
  */
 private void generateVersionHelper(String version, StringTemplateGroup templateGroup) {
   StringTemplate template = templateGroup.getInstanceOf(VERSION_OBJECT_TEMPLATE);
   template.setAttribute("apiVersion", version);
   template.setAttribute(PACKAGE_NAME, config.getApiPackageName());
   File aFile =
       new File(
           languageConfig.getResourceClassLocation()
               + this.getNameGenerator().getVersionCheckerClassName()
               + languageConfig.getClassFileExtension());
   writeFile(aFile, template.toString(), "Version checker class");
 }
  /** Generates model classes. If the class is already generated then ignores the same. */
  private void generateModelClasses(List<Resource> resources, StringTemplateGroup templateGroup) {
    List<String> generatedClassNames = new ArrayList();

    for (Resource resource : resources) {
      for (Model model : resource.getModels()) {
        if (!generatedClassNames.contains(model.getName())
            && !this.getCodeGenRulesProvider().isModelIgnored(model.getName())) {
          List<String> imports = new ArrayList<String>();
          imports.addAll(this.config.getDefaultModelImports());
          for (ModelField param : model.getFields()) {
            for (String importDef :
                param
                    .getFieldDefinition(this.getDataTypeMappingProvider(), config, nameGenerator)
                    .getImportDefinitions()) {
              if (!imports.contains(importDef)) {
                imports.add(importDef);
              }
            }
          }
          StringTemplate template = templateGroup.getInstanceOf(MODEL_OBJECT_TEMPLATE);
          template.setAttribute("model", model);
          template.setAttribute("fields", model.getFields());
          template.setAttribute("imports", imports);
          template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
          template.setAttribute("extends", config.getDefaultModelBaseClass());
          template.setAttribute("className", model.getGenratedClassName());
          template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
          File aFile =
              new File(
                  languageConfig.getModelClassLocation()
                      + model.getGenratedClassName()
                      + languageConfig.getClassFileExtension());
          writeFile(aFile, template.toString(), "Model class");
          generatedClassNames.add(model.getName());
        }
      }
    }

    generateWrapperClassForTestData(generatedClassNames, templateGroup);
  }
 protected void initialize(
     String apiServerURL,
     String apiKey,
     String modelPackageName,
     String apiPackageName,
     String classOutputDir,
     String libraryHome) {
   final ObjectMapper mapper = new ObjectMapper();
   mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
   ApiConfiguration aApiConfiguration = new ApiConfiguration();
   aApiConfiguration.setApiKey(apiKey);
   aApiConfiguration.setApiPackageName(apiPackageName);
   aApiConfiguration.setModelPackageName(modelPackageName);
   aApiConfiguration.setApiUrl(apiServerURL);
   this.setApiConfig(aApiConfiguration);
   CodeGenRulesProvider codeGenRules = new CodeGenRulesProvider();
   this.setCodeGenRulesProvider(codeGenRules);
   LanguageConfiguration aLanguageConfiguration = new LanguageConfiguration();
   aLanguageConfiguration.setOutputDirectory(classOutputDir);
   aLanguageConfiguration.setLibraryHome(libraryHome);
   initializeLangConfig(aLanguageConfiguration);
   this.setLanguageConfig(aLanguageConfiguration);
 }
  private void generateOutputWrappers(List<Resource> resources, StringTemplateGroup templateGroup) {
    List<String> generatedClasses = new ArrayList<String>();
    StringTemplate template = templateGroup.getInstanceOf(WRAPPER_OBJECT_TEMPLATE);
    if (template == null) {
      System.out.println("WrapperObject template not found to generate output wrappers");
      return;
    }

    for (Resource resource : resources) {
      if (resource.getEndPoints() != null) {
        for (Endpoint endpoint : resource.getEndPoints()) {
          if (endpoint.getOperations() != null) {
            for (EndpointOperation operation : endpoint.getOperations()) {
              ResourceMethod method =
                  operation.generateMethod(
                      endpoint, resource, dataTypeMappingProvider, nameGenerator);
              if (codeGenRulesProvider.isModelIgnored(
                  nameGenerator.applyMethodNamingPolicy(method.getReturnClassName()))) {
                continue;
              }
              if (method.getListWrapperModel() != null) {
                Model model = method.getListWrapperModel();
                method.setReturnClassName(model.getName());
                if (model != null) {
                  if (!generatedClasses.contains(model.getName())) {
                    List<String> imports = new ArrayList<String>();
                    imports.addAll(this.config.getDefaultModelImports());
                    for (ModelField param : model.getFields()) {
                      for (String importDef :
                          param
                              .getFieldDefinition(
                                  this.getDataTypeMappingProvider(), config, nameGenerator)
                              .getImportDefinitions()) {
                        if (!imports.contains(importDef)) {
                          imports.add(importDef);
                        }
                      }
                    }
                    template = templateGroup.getInstanceOf(WRAPPER_OBJECT_TEMPLATE);

                    template.setAttribute("fields", model.getFields());
                    template.setAttribute("imports", imports);
                    template.setAttribute("extends", config.getDefaultModelBaseClass());
                    template.setAttribute(
                        "annotationPackageName", languageConfig.getAnnotationPackageName());
                    template.setAttribute("className", model.getGenratedClassName());
                    template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
                    File aFile =
                        new File(
                            languageConfig.getModelClassLocation()
                                + model.getGenratedClassName()
                                + languageConfig.getClassFileExtension());
                    writeFile(aFile, template.toString(), "List wrapper model class");
                    generatedClasses.add(model.getName());
                  }
                }
              }
            }
          }
        }
      }
    }
  }
 /**
  * Generates an Enum class for method params that have an allowed values list.
  *
  * @param resources
  * @param templateGroup
  */
 private void generateEnumForAllowedValues(
     List<Resource> resources, StringTemplateGroup templateGroup) {
   List<String> generatedEnums = new ArrayList<String>();
   StringTemplate template;
   String valuePrefix, valueSuffix = "";
   String enumName;
   for (Resource resource : resources) {
     if (resource.getEndPoints() != null) {
       for (Endpoint endpoint : resource.getEndPoints()) {
         if (endpoint.getOperations() != null) {
           for (EndpointOperation operation : endpoint.getOperations()) {
             // ResourceMethod method = operation.generateMethod(endpoint, resource, config);
             if (operation.getParameters() != null) {
               for (ModelField operationParam : operation.getParameters()) {
                 // skipping the case where there is just one item - TODO process case of
                 // allowableValue like '0 to 1000'
                 if (operationParam.getAllowableValues() != null
                     && operationParam
                         .getAllowableValues()
                         .getClass()
                         .isAssignableFrom(AllowableListValues.class)) {
                   if (!generatedEnums.contains(operationParam.getName())) {
                     // generate enum
                     template = templateGroup.getInstanceOf(ENUM_OBJECT_TEMPLATE);
                     List<String> imports = new ArrayList<String>();
                     imports.addAll(this.config.getDefaultModelImports());
                     enumName = this.getNameGenerator().getEnumName(operationParam.getName());
                     template.setAttribute("className", enumName);
                     template.setAttribute("description", operationParam.getDescription());
                     template.setAttribute(
                         "enumValueType",
                         this.getDataTypeMappingProvider()
                             .getClassType(operationParam.getDataType(), true));
                     for (String allowableValue :
                         ((AllowableListValues) operationParam.getAllowableValues()).getValues()) {
                       if (operationParam.getDataType().equalsIgnoreCase("string")) {
                         valuePrefix = valueSuffix = "\"";
                       } else {
                         valuePrefix = valueSuffix = "";
                       }
                       ;
                       String namePrefix = "";
                       if (isNameStartsWithInteger(allowableValue)
                           && !canEnumNameStartsWithNumber()) {
                         namePrefix = "ENUM_";
                       }
                       template.setAttribute(
                           "values.{name,value}",
                           namePrefix
                               + this.getNameGenerator()
                                   .applyClassNamingPolicy(allowableValue.replaceAll("-", "_")),
                           this.getNameGenerator()
                               .applyMethodNamingPolicy(
                                   valuePrefix.concat(allowableValue).concat(valueSuffix)));
                     }
                     template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
                     File aFile =
                         new File(
                             languageConfig.getModelClassLocation()
                                 + enumName
                                 + languageConfig.getClassFileExtension());
                     writeFile(aFile, template.toString(), "Enum class");
                     generatedEnums.add(operationParam.getName());
                   }
                 }
               }
             }
           }
         }
       }
     }
   }
 }