package be.iminds.ilabt.jfed.lowlevel.api;

import be.iminds.ilabt.jfed.lowlevel.*;
import be.iminds.ilabt.jfed.lowlevel.connection.HttpConnection;
import be.iminds.ilabt.jfed.preferences.JFedPreferences;
import com.google.common.base.Joiner;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.StringBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * GtsRest
 */
public class GtsRest extends RestApi {
    private static final Logger LOG = LoggerFactory.getLogger(GtsRest.class);

    private static ContentType defaultGtsContentType = ContentType.MULTIPART_FORM_DATA;

    private static final String userManagementPrefix = "";
    private static final String projectManagementPrefix = "";
    private static final String infrastructureManagementPrefix = "";
    private static final String typeManagementPrefix = "";
    private static final String resourceManagementPrefix = "";

    @Override
    public String getName() {
        return getApiName();
    }

    /**
     * A human readable name for the implemented API
     *
     * @return "GTS REST API";
     */
    static public String getApiName() {
        return "GTS REST API";
    }

    @Override
    protected boolean isBusyReply(XMLRPCCallDetails res) {
        return false;
    }

    public static class GtsRestReply<T> implements ApiCallReply<T> {
        private final T value;
        private final HttpCallDetails httpCallDetails;
        private final int httpCode;
        private final String httpCodeDescription;

        public GtsRestReply(HttpCallDetails httpCallDetails, T value) {
            this.httpCallDetails = httpCallDetails;
            this.httpCode = httpCallDetails.getResultHttpStatusCode();
            this.httpCodeDescription = httpCallDetails.getResultHttpStatusLine();
            this.value = value;
        }

        @Override
        public GeniResponseCode getGeniResponseCode() {
            return new GeniResponseCode() {
                @Override
                public boolean isSuccess() {
                    return httpCode >= 200 && httpCode < 300;
                }

                @Override
                public boolean isBusy() {
                    return /*httpCode == 500 &&*/ httpCode == 503;
                } //NOTE: These codes CAN be busy, but are not always!

                @Override
                public int getCode() {
                    return httpCode;
                }

                @Override
                public String getDescription() {
                    return httpCodeDescription;
                }
            };
        }

        @Override
        public T getValue() {
            return value;
        }

        @Override
        public String getOutput() {
            return null;
        }

        @Override
        public Object getRawResult() {
            return null;
        }

        @Override
        public Object getRawValue() {
            return value;
        }

        public HttpCallDetails getHttpCallDetails() {
            return httpCallDetails;
        }

        private boolean busy;
    }

    /**
     * @param logger the logger to use. May be null if no logger is used.
     */
    @Inject
    public GtsRest(@Nonnull be.iminds.ilabt.jfed.log.Logger logger, @Nonnull JFedPreferences jFedPreferences) {
        super(logger, new ApiInfo.Api(ApiInfo.ApiName.GTS_API, 1), jFedPreferences);
    }

    @ApiMethod(order = 1, hint = "GET /session/login/")
    public RestReply<String> login(@Nonnull HttpConnection con) throws JFedException {
        String javaName = "login";
        String relUrl = userManagementPrefix + "/session/login";
        Map<String, Object> methodParams = makeMethodParameters();
        Map<String, Object> urlParams = makeMethodParameters();

        con.enablePreemptiveAuthentication(true);
        RestApi.RestReply<String> r = internalGet(con, javaName, relUrl, methodParams, urlParams);
        con.enablePreemptiveAuthentication(false);
        return r;
    }

    private Map<String, String> addGtsAuthenticationToken(String gtsAuthenticationToken) {
        if (gtsAuthenticationToken != null) {
            return Collections.singletonMap("X-gts-token", gtsAuthenticationToken);
        }
        return null;
    }

    @ApiMethod(order = 1, hint = "GET /query/taasUser/{login}")
    public RestReply<String> queryUser(@Nonnull HttpConnection con,
                                       @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                       String gtsAuthenticationToken,
                                       @ApiMethodParameter(name = "login", parameterType = ApiMethodParameterType.STRING, hint = "Login identifier of the user")
                                       String login) throws JFedException {
        String javaName = "queryUsers";
        String relUrl = userManagementPrefix + "/query/taasUser";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "login", login);
        Map<String, Object> urlParams = makeMethodParameters("login", login);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 2, hint = "GET /query/taasUsers")
    public RestReply<String> queryUsers(@Nonnull HttpConnection con,
                                        @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                        String gtsAuthenticationToken) throws JFedException {
        String javaName = "queryUsers";
        String relUrl = userManagementPrefix + "/query/taasUsers";
        Map<String, Object> methodParams = makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken);
        Map<String, Object> urlParams = makeMethodParameters();

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }
    //TODO addUser
//    @ApiMethod(order = 4, hint = "POST /query/taasUsers")
//    public RestReply<String> addUser(@Nonnull HttpConnection con,
//                                       @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
//                                       String gtsAuthenticationToken) throws JFedException {
//        String javaName = "queryUsers";
//        String relUrl = "/add/taasUser";
//        Map<String, Object> methodParams = makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken);
//        Map<String, Object> urlParams = makeMethodParameters();
//
//        return internalPost(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
//    }

    //TODO updateUser

    //TODO removeUser


    @ApiMethod(order = 10, hint = "GET /query/taasProject/{id}")
    public RestReply<String> queryProject(@Nonnull HttpConnection con,
                                          @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                          String gtsAuthenticationToken,
                                          @ApiMethodParameter(name = "id", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                          String id) throws JFedException {
        String javaName = "queryProject";
        String relUrl = projectManagementPrefix + "/query/taasProject/" + id;
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "id", id);
        Map<String, Object> urlParams = makeMethodParameters("id", id);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 11, hint = "GET /query/taasProject")
    public RestReply<String> queryProjects(@Nonnull HttpConnection con,
                                           @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                           String gtsAuthenticationToken) throws JFedException {
        String javaName = "queryProjects";
        String relUrl = projectManagementPrefix + "/query/taasProjects";
        Map<String, Object> methodParams = makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken);
        Map<String, Object> urlParams = makeMethodParameters();

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    //add project
    @ApiMethod(order = 12, hint = "POST /add/taasProject")
    public RestReply<String> addProject(@Nonnull HttpConnection con,
                                        @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                        String gtsAuthenticationToken,
                                        @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                        String projectName,
                                        @ApiMethodParameter(name = "VPNUserName", parameterType = ApiMethodParameterType.STRING, hint = "VPN user name (for Host types only)", required = false)
                                        String vpnUserName,
                                        @ApiMethodParameter(name = "VPNPassword", parameterType = ApiMethodParameterType.STRING, hint = "VPN user name (for Host types only)", required = false)
                                        String vpnPassword,
                                        @ApiMethodParameter(name = "users", parameterType = ApiMethodParameterType.LIST_OF_STRING, hint = "Users", required = false)
                                        List<String> users,
                                        @ApiMethodParameter(name = "icon", parameterType = ApiMethodParameterType.URL, hint = "Users", required = false)
                                        String icon) throws JFedException {
        String javaName = "addProject";
        String relUrl = typeManagementPrefix + "/add/taasProject";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken,
                        "projectName", projectName,
                        "VPNUserName", vpnUserName,
                        "VPNPassword", vpnPassword,
                        "users", users,
                        "icon", icon);
        Map<String, Object> urlParams = makeMethodParameters("projectName", projectName,
                "VPNUserName", vpnUserName,
                "VPNPassword", vpnPassword,
                "users", users,
                "icon", icon);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("projectName", new StringBody(projectName));
            if (vpnUserName != null)
                reqEntity.addPart("VPNUserName", new StringBody(vpnUserName));
            if (vpnPassword != null)
                reqEntity.addPart("VPNPassword", new StringBody(vpnPassword));
            if (users != null)
                reqEntity.addPart("users", new StringBody(Joiner.on("\n").join(users)));
            if (icon != null)
                reqEntity.addPart("icon", new StringBody(icon));

        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }


    //update project
    @ApiMethod(order = 12, hint = "POST /update/taasProject/{projectName}")
    public RestReply<String> updateProject(@Nonnull HttpConnection con,
                                        @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                        String gtsAuthenticationToken,
                                        @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                        String projectName,
                                        @ApiMethodParameter(name = "VPNUserName", parameterType = ApiMethodParameterType.STRING, hint = "VPN user name (for Host types only)", required = false)
                                        String vpnUserName,
                                        @ApiMethodParameter(name = "VPNPassword", parameterType = ApiMethodParameterType.STRING, hint = "VPN user name (for Host types only)", required = false)
                                        String vpnPassword,
                                        @ApiMethodParameter(name = "users", parameterType = ApiMethodParameterType.LIST_OF_STRING, hint = "Users", required = false)
                                        List<String> users,
                                        @ApiMethodParameter(name = "icon", parameterType = ApiMethodParameterType.URL, hint = "Users", required = false)
                                        String icon) throws JFedException {
        String javaName = "updateProject";
        String relUrl;
        try {
            relUrl = typeManagementPrefix + "/update/taasProject/" + URLEncoder.encode(projectName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unable to encode project id", e);
        }
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken,
                        "projectName", projectName,
                        "VPNUserName", vpnUserName,
                        "VPNPassword", vpnPassword,
                        "users", users,
                        "icon", icon);
        Map<String, Object> urlParams = makeMethodParameters("projectName", projectName,
                "VPNUserName", vpnUserName,
                "VPNPassword", vpnPassword,
                "users", users,
                "icon", icon);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("projectName", new StringBody(projectName));
            if (vpnUserName != null)
                reqEntity.addPart("VPNUserName", new StringBody(vpnUserName));
            if (vpnPassword != null)
                reqEntity.addPart("VPNPassword", new StringBody(vpnPassword));
            if (users != null)
                reqEntity.addPart("users", new StringBody(Joiner.on("\n").join(users)));
            if (icon != null)
                reqEntity.addPart("icon", new StringBody(icon));

        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }
    //remove project
    @ApiMethod(order = 14, hint = "DELETE /remove/taasProject/{id}")
    public RestReply<String> removeProject(@Nonnull HttpConnection con,
                                           @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                           String gtsAuthenticationToken,
                                           @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                           String project) throws JFedException {
        String javaName = "removeProject";
        String relUrl;
        try {
            relUrl = typeManagementPrefix + "/remove/taasProject/" + URLEncoder.encode(project, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unable to encode project id", e);
        }
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project, "id", project);
        Map<String, Object> urlParams = makeMethodParameters("id", project);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("id", new StringBody(project));
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalDelete(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }


    @ApiMethod(order = 20, hint = "GET /query/infrastructure/{id}")
    public RestReply<String> queryRCA(@Nonnull HttpConnection con,
                                      @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                      String gtsAuthenticationToken,
                                      @ApiMethodParameter(name = "id", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the infrastructure")
                                      String id) throws JFedException {
        String javaName = "queryRCA";
        String relUrl;
        try {
            relUrl = infrastructureManagementPrefix + "/query/infrastructure/" + URLEncoder.encode(id, "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            throw new JFedException("Could not encode url", ex);
        }
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "id", id);
        Map<String, Object> urlParams = makeMethodParameters("id", id);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 21, hint = "GET /query/infrastructures")
    public RestReply<String> queryRCAs(@Nonnull HttpConnection con,
                                       @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                       String gtsAuthenticationToken) throws JFedException {
        String javaName = "queryRCAs";
        String relUrl = infrastructureManagementPrefix + "/query/infrastructures";
        Map<String, Object> methodParams = makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken);
        Map<String, Object> urlParams = makeMethodParameters();

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }


    @ApiMethod(order = 30, hint = "GET /query/types/{type}/{project}")
    public RestReply<String> queryType(@Nonnull HttpConnection con,
                                       @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                       String gtsAuthenticationToken,
                                       @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                       String project,
                                       @ApiMethodParameter(name = "type", parameterType = ApiMethodParameterType.STRING, hint = "Name of the type (DSL)")
                                       String type) throws JFedException {
        String javaName = "queryType";
        String relUrl;
        try {
            relUrl = typeManagementPrefix + "/query/types/"
                    + URLEncoder.encode(type, "UTF-8") + "/"
                    + URLEncoder.encode(project, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Could not encode request url", e);
        }
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project, "type", type);
        Map<String, Object> urlParams = makeMethodParameters("project", project, "type", type);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 31, hint = "GET /query/types/{project}")
    public RestReply<String> queryTypes(@Nonnull HttpConnection con,
                                        @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                        String gtsAuthenticationToken,
                                        @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                        String project) throws JFedException {
        String javaName = "queryTypes";
        String relUrl;
        try {
            relUrl = typeManagementPrefix + "/query/types/" + URLEncoder.encode(project, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Could not encode request url", e);
        }
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project);
        Map<String, Object> urlParams = makeMethodParameters("project", project);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 32, hint = "POST /define")
    public RestReply<String> addType(@Nonnull HttpConnection con,
                                     @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                     String gtsAuthenticationToken,
                                     @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                     String project,
                                     @ApiMethodParameter(name = "script", parameterType = ApiMethodParameterType.STRING_MULTILINE, hint = "DSL script")
                                     String script) throws JFedException {
        String javaName = "addType";
        String relUrl = typeManagementPrefix + "/define";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project, "script", script);
        Map<String, Object> urlParams = makeMethodParameters("project", project, "script", script);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("script", new StringBody(script));
            reqEntity.addPart("project", new StringBody(project));
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 33, hint = "POST /undefine")
    public RestReply<String> removeType(@Nonnull HttpConnection con,
                                        @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                        String gtsAuthenticationToken,
                                        @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                        String project,
                                        @ApiMethodParameter(name = "type", parameterType = ApiMethodParameterType.STRING, hint = "Name of the type (DSL)")
                                        String type) throws JFedException {
        String javaName = "removeType";
        String relUrl = typeManagementPrefix + "/undefine";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project, "type", type);
        Map<String, Object> urlParams = makeMethodParameters("project", project, "type", type);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("type", new StringBody(type));
            reqEntity.addPart("project", new StringBody(project));
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }


    @ApiMethod(order = 40, hint = "GET /query/{ldap}/{project}")
    public RestReply<String> queryLdapResources(@Nonnull HttpConnection con,
                                                @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                                String gtsAuthenticationToken,
                                                @ApiMethodParameter(name = "ldap", parameterType = ApiMethodParameterType.STRING, hint = "Structured LDAP query to identify required resources")
                                                String ldap,
                                                @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                                String project) throws JFedException {
        String javaName = "queryLdapResources";
        String relUrl = resourceManagementPrefix + "/query/" + ldap + "/" + project;
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project, "ldap", ldap);
        Map<String, Object> urlParams = makeMethodParameters("project", project, "ldap", ldap);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 41, hint = "GET /query/reservations/{project}")
    public RestReply<String> queryReservations(@Nonnull HttpConnection con,
                                               @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                               String gtsAuthenticationToken,
                                               @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                               String project) throws JFedException {
        String javaName = "queryReservations";
        String relUrl = resourceManagementPrefix + "/query/reservations/" + project;
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project);
        Map<String, Object> urlParams = makeMethodParameters("project", project);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 42, hint = "GET /query/resources/{project}")
    public RestReply<String> queryProjectResources(@Nonnull HttpConnection con,
                                                   @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                                   String gtsAuthenticationToken,
                                                   @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                                   String project) throws JFedException {
        String javaName = "queryProjectResources";
        String relUrl = resourceManagementPrefix + "/query/resources/" + project;
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project);
        Map<String, Object> urlParams = makeMethodParameters("project", project);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 43, hint = "GET /query/all-resources")
    public RestReply<String> queryAllResources(@Nonnull HttpConnection con,
                                               @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                               String gtsAuthenticationToken) throws JFedException {
        String javaName = "queryAllResources";
        String relUrl = resourceManagementPrefix + "/query/all-resources";
        Map<String, Object> methodParams = makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken);
        Map<String, Object> urlParams = makeMethodParameters();

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 44, hint = "GET /query/resource/{id}")
    public RestReply<String> queryResource(@Nonnull HttpConnection con,
                                           @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                           String gtsAuthenticationToken,
                                           @ApiMethodParameter(name = "id", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the resource")
                                           String id) throws JFedException {
        String javaName = "queryResource";
        String relUrl = resourceManagementPrefix + "/query/resource/" + id;
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "id", id);
        Map<String, Object> urlParams = makeMethodParameters("id", id);

        return internalGet(con, javaName, relUrl, methodParams, urlParams, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 45, hint = "POST /reserve/resource")
    public RestReply<String> reserveResource(@Nonnull HttpConnection con,
                                             @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                             String gtsAuthenticationToken,
                                             @ApiMethodParameter(name = "id", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the resource")
                                             String id,
                                             @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                             String project) throws JFedException {
        String javaName = "reserveResource";
        String relUrl = resourceManagementPrefix + "/reserve/resource";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project, "id", id);
        Map<String, Object> urlParams = makeMethodParameters("project", project, "id", id);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("id", new StringBody(id));
            reqEntity.addPart("project", new StringBody(project));
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 50, hint = "POST /reserve/type")
    public RestReply<String> reserveType(@Nonnull HttpConnection con,
                                         @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                         String gtsAuthenticationToken,
                                         @ApiMethodParameter(name = "type", parameterType = ApiMethodParameterType.STRING, hint = "Type name")
                                         String type,
                                         @ApiMethodParameter(name = "project", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the project")
                                         String project) throws JFedException {
        String javaName = "reserveType";
        String relUrl = resourceManagementPrefix + "/reserve/type";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "project", project, "type", type);
        Map<String, Object> urlParams = makeMethodParameters("project", project, "type", type);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("type", new StringBody(type));
            reqEntity.addPart("project", new StringBody(project));
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 51, hint = "POST /activate/reservation")
    public RestReply<String> activateReservation(@Nonnull HttpConnection con,
                                                 @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                                 String gtsAuthenticationToken,
                                                 @ApiMethodParameter(name = "id", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the reservation")
                                                 String id) throws JFedException {
        String javaName = "activateReservation";
        String relUrl = resourceManagementPrefix + "/activate/reservation";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "id", id);
        Map<String, Object> urlParams = makeMethodParameters("id", id);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("id", new StringBody(id));
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 52, hint = "POST /deactivate/reservation")
    public RestReply<String> deactivateReservation(@Nonnull HttpConnection con,
                                                   @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                                   String gtsAuthenticationToken,
                                                   @ApiMethodParameter(name = "id", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the reservation")
                                                   String id) throws JFedException {
        String javaName = "deactivateReservation";
        String relUrl = resourceManagementPrefix + "/deactivate/reservation";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "id", id);
        Map<String, Object> urlParams = makeMethodParameters("id", id);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("id", new StringBody(id));
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }

    @ApiMethod(order = 53, hint = "POST /release/reservation")
    public RestReply<String> releaseReservation(@Nonnull HttpConnection con,
                                                @ApiMethodParameter(name = "gtsAuthenticationToken", parameterType = ApiMethodParameterType.STRING, hint = "GTS Authentication token")
                                                String gtsAuthenticationToken,
                                                @ApiMethodParameter(name = "id", parameterType = ApiMethodParameterType.STRING, hint = "Unique identifier of the reservation")
                                                String id) throws JFedException {
        String javaName = "releaseReservation";
        String relUrl = resourceManagementPrefix + "/release/reservation";
        Map<String, Object> methodParams =
                makeMethodParameters("gtsAuthenticationToken", gtsAuthenticationToken, "id", id);
        Map<String, Object> urlParams = makeMethodParameters("id", id);

        MultipartEntity reqEntity = new MultipartEntity();
        try {
            reqEntity.addPart("id", new StringBody(id));
        } catch (UnsupportedEncodingException e) {
            throw new JFedException("Unexpected exception creating MultipartEntity", e);
        }

        return internalPost(con, javaName, relUrl, methodParams, urlParams, reqEntity, addGtsAuthenticationToken(gtsAuthenticationToken));
    }
}
