package fi.evident.apina.model;

import fi.evident.apina.model.parameters.EndpointParameter;
import fi.evident.apina.model.parameters.EndpointRequestBodyParameter;
import fi.evident.apina.model.type.ApiType;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static fi.evident.apina.utils.CollectionUtils.join;
import static java.util.Collections.unmodifiableList;
import static java.util.Objects.requireNonNull;

/**
 * API endpoint reachable at an URL using given method and parameters. An example
 * of an endpoint is a single method on a controller.
 * Represents an single endpoint (e.g. a method in a controller)
 */
public final class Endpoint {

    /** Name of the original source element that specifies this endpoint */
    private final String name;

    /** URI template for the endpoint */
    private final URITemplate uriTemplate;

    private final List<EndpointParameter> parameters = new ArrayList<>();

    private final Optional<ApiType> responseBody;

    /** HTTP method for accessing the endpoint */
    private HTTPMethod method = HTTPMethod.GET;

    public Endpoint(String name, URITemplate uriTemplate, Optional<ApiType> responseBody) {
        this.name = requireNonNull(name);
        this.uriTemplate = requireNonNull(uriTemplate);
        this.responseBody = requireNonNull(responseBody);
    }

    public void addParameter(EndpointParameter parameter) {
        parameters.add(requireNonNull(parameter));
    }

    public Optional<ApiType> getRequestBody() {
        for (EndpointParameter parameter : parameters)
            if (parameter instanceof EndpointRequestBodyParameter)
                return Optional.of(parameter.getType());

        return Optional.empty();
    }

    public List<EndpointParameter> getParameters() {
        return unmodifiableList(parameters);
    }

    public Optional<ApiType> getResponseBody() {
        return responseBody;
    }

    public URITemplate getUriTemplate() {
        return uriTemplate;
    }

    public String getName() {
        return name;
    }

    public HTTPMethod getMethod() {
        return method;
    }

    public void setMethod(HTTPMethod method) {
        this.method = requireNonNull(method);
    }

    @Override
    public String toString() {
        return String.format("%s %s(%s): %s %s",
                responseBody.map(ApiType::toString).orElse("void"),
                name,
                join(parameters, ", "),
                method,
                uriTemplate);
    }
}

@@ -131,35 +131,179 @@
 ers.Endpoint
-RequestBody
+PathVariableParameter;%0Aimport fi.evident.apina.model.parameters.EndpointRequestBodyParameter;%0Aimport fi.evident.apina.model.parameters.EndpointRequestParam
 Parameter;%0Ai
@@ -421,24 +421,91 @@
 .Optional;%0A%0A
+import static fi.evident.apina.utils.CollectionUtils.filterByType;%0A
 import stati
@@ -1677,32 +1677,33 @@
 meter));%0A    %7D%0A%0A
+%0A
     public Optio
@@ -1702,31 +1702,52 @@
 ic Optional%3C
-ApiType
+EndpointRequestBodyParameter
 %3E getRequest
@@ -1916,61 +1916,392 @@
 .of(
-parameter.getType());%0A%0A        return Optional.empty(
+(EndpointRequestBodyParameter) parameter);%0A%0A        return Optional.empty();%0A    %7D%0A%0A    public List%3CEndpointPathVariableParameter%3E getPathVariables() %7B%0A        return filterByType(parameters, EndpointPathVariableParameter.class);%0A    %7D%0A%0A    public List%3CEndpointRequestParamParameter%3E getRequestParameters() %7B%0A        return filterByType(parameters, EndpointRequestParamParameter.class
 );%0A 

Add convenience accessors to Endpoint for different parameters