/**
   * Converts a method body into a request json schema and a mime type. TODO refactor this code
   * structure
   *
   * @param method The method to be used to get the request object
   * @param parameterComments Associated JavaDoc for Parameters (if any)
   * @param comment Main Method Javadoc Comment (if any)
   * @param apiParameters The Parameters identifed from this method
   * @return The Request Body as a schema and the associated mime type
   */
  protected Pair<String, RamlMimeType> extractRequestBody(
      Method method,
      Map<String, String> parameterComments,
      String comment,
      List<ApiParameterMetadata> apiParameters) {
    String schema;
    RamlMimeType mimeType =
        RamlModelFactoryOfFactories.createRamlModelFactory().createRamlMimeType();
    if (apiParameters.size() == 1) {
      if (parameterComments != null && parameterComments.size() == 1) {
        comment = parameterComments.values().iterator().next();
      }
      ApiParameterMetadata ajaxParameter = apiParameters.get(0);
      schema =
          SchemaHelper.convertClassToJsonSchema(
              ajaxParameter, comment, javaDocs.getJavaDoc(ajaxParameter.getType()));
      if (StringUtils.hasText(ajaxParameter.getExample())) {
        mimeType.setExample(ajaxParameter.getExample());
      }
    } else {
      schema =
          "{ \"type\": \"object\", \n \"properties\": {\n"; // change to object where key = param
                                                            // name
      boolean first = true;
      for (ApiParameterMetadata param : apiParameters) {
        if (!first) {
          schema += ",\n";
        } else {
          first = false;
        }
        schema += "\"" + param.getName() + "\" : ";
        comment = "";
        if (parameterComments != null) {
          if (StringUtils.hasText(comment)
              && StringUtils.hasText(parameterComments.get(param.getJavaName()))) {
            comment = parameterComments.get(param.getJavaName());
          }
        }
        schema +=
            SchemaHelper.convertClassToJsonSchema(
                param, comment, javaDocs.getJavaDoc(param.getType()));
      }

      schema += "}\n}";
    }
    mimeType.setSchema(schema);
    return new Pair<>(extractExpectedMimeTypeFromMethod(method), mimeType);
  }
  /**
   * Extracts parameters from a method call and attaches these with the comments extracted from the
   * javadoc
   *
   * @param apiAction The Verb of the action containing these parametes
   * @param method The method to inspect
   * @param parameterComments The parameter comments associated with these parameters
   * @return A collection of parameters keyed by name
   */
  protected Map<String, RamlQueryParameter> extractQueryParameters(
      RamlActionType apiAction, Method method, Map<String, String> parameterComments) {
    // Since POST requests have a body we choose to keep all request data in one place as much as
    // possible
    if (apiAction.equals(RamlActionType.POST) || method.getParameterCount() == 0) {
      return Collections.emptyMap();
    }
    Map<String, RamlQueryParameter> queryParams = new LinkedHashMap<>();

    for (Parameter param : method.getParameters()) {
      if (isQueryParameter(
          param)) { // Lets skip resourceIds since these are going to be going in the URL
        RamlParamType simpleType = SchemaHelper.mapSimpleType(param.getType());

        if (simpleType == null) {
          queryParams.putAll(
              SchemaHelper.convertClassToQueryParameters(
                  param, javaDocs.getJavaDoc(param.getType())));
        } else {
          // Check if we have comments
          String paramComment = parameterComments.get(param.getName());
          queryParams.putAll(SchemaHelper.convertParameterToQueryParameter(param, paramComment));
        }
      }
    }
    return queryParams;
  }
  /**
   * Extracts class information from a (believe it or not) java class as well as the contained
   * methods.
   *
   * @param clazz The Class to be inspected
   * @return The RAML Resource model for this class
   */
  public RamlResource extractResourceInfo(Class<?> clazz) {
    logger.info("Parsing resource: " + clazz.getSimpleName() + " ");
    RamlResource resource =
        RamlModelFactoryOfFactories.createRamlModelFactory().createRamlResource();
    resource.setRelativeUri("/" + getResourceName(clazz));
    resource.setDisplayName(clazz.getSimpleName()); // TODO allow the Api annotation to specify
    // this stuff :)
    JavaDocStore javaDoc = javaDocs.getJavaDoc(clazz);
    String comment = javaDoc.getJavaDocComment(clazz);
    if (comment != null) {
      resource.setDescription(comment);
    }

    // Append stuff to the parent resource
    getMethodsFromService(clazz, javaDoc, resource);

    return resource;
  }
  /**
   * Extracts the Response Body from a method in JsonSchema Format and embeds it into a response
   * object based on the defaultMediaType
   *
   * @param method The method to inspect
   * @param responseComment The JavaDoc (if any) for this response
   * @return The response RAML model for this method (success only)
   */
  protected RamlResponse extractResponseFromMethod(Method method, String responseComment) {
    RamlModelFactory ramlModelFactory = RamlModelFactoryOfFactories.createRamlModelFactory();
    RamlResponse response = ramlModelFactory.createRamlResponse();
    String mime = extractMimeTypeFromMethod(method);
    RamlMimeType jsonType =
        ramlModelFactory.createRamlMimeTypeWithMime(mime); // TODO this would be coolto annotate
    // TO/VO/DO/weO with the mime type
    // they represent and chuck it in here
    Class<?> returnType = method.getReturnType();
    Type genericReturnType = method.getGenericReturnType();
    Type inferGenericType = TypeHelper.inferGenericType(genericReturnType);
    if (returnType != null
        && (returnType.equals(DeferredResult.class)
            || returnType.equals(
                ResponseEntity.class))) { // unwrap spring classes from response body
      if (inferGenericType == null) {
        inferGenericType = Object.class;
      }

      if (inferGenericType instanceof Class) {
        returnType = (Class<?>) inferGenericType;
      }
      genericReturnType = inferGenericType;
    }

    jsonType.setSchema(
        SchemaHelper.convertClassToJsonSchema(
            genericReturnType, responseComment, javaDocs.getJavaDoc(returnType)));

    LinkedHashMap<String, RamlMimeType> body = new LinkedHashMap<>();
    body.put(mime, jsonType);
    response.setBody(body);
    if (StringUtils.hasText(responseComment)) {
      response.setDescription(responseComment);
    } else {
      response.setDescription("Successful Response");
    }
    return response;
  }