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

import be.iminds.ilabt.jfed.log.Logger;
import be.iminds.ilabt.jfed.lowlevel.*;
import be.iminds.ilabt.jfed.lowlevel.connection.SfaConnection;
import be.iminds.ilabt.jfed.preferences.JFedPreferences;
import be.iminds.ilabt.jfed.util.GeniUrn;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;

/**
 * FederationMemberAuthorityApi2
 */
public class FederationMemberAuthorityApi2 extends AbstractFederationApi2 {
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(FederationMemberAuthorityApi2.class);

    /**
     * A human readable name for the implemented API
     *
     * @return "Uniform Federation Member Authority API v2";
     */
    static public String getApiName() {
        return "Uniform Federation Member Authority API v2";
    }

    /**
     * A human readable name for the implemented API
     *
     * @return "Uniform Federation Member Authority API v2";
     */
    @Override
    public String getName() {
        return getApiName();
    }

    public FederationMemberAuthorityApi2(@Nonnull Logger logger, @Nonnull RetrySettings retrySettings, @Nonnull JFedPreferences jFedPreferences) {
        super(logger, retrySettings, new ApiInfo.Api(ApiInfo.ApiName.GENI_CH_MA, 2), jFedPreferences);
    }

    public FederationMemberAuthorityApi2(@Nonnull Logger logger, @Nonnull JFedPreferences jFedPreferences) {
        this(logger, jFedPreferences.getRetrySettings(), jFedPreferences);
    }

    public static final String TYPE_MEMBER = "MEMBER";
    private static final List<GetVersionResult.FieldInfo> MINIMUM_MEMBER_FIELDS =
            Collections.unmodifiableList(Arrays.asList(
                    new GetVersionResult.FieldInfo(TYPE_MEMBER, "MEMBER_URN", GetVersionResult.FieldInfo.FieldType.URN, true, GetVersionResult.FieldInfo.Protect.PUBLIC),
                    new GetVersionResult.FieldInfo(TYPE_MEMBER, "MEMBER_UID", GetVersionResult.FieldInfo.FieldType.UID, true, GetVersionResult.FieldInfo.Protect.PUBLIC),
                    new GetVersionResult.FieldInfo(TYPE_MEMBER, "MEMBER_FIRSTNAME", GetVersionResult.FieldInfo.FieldType.STRING, true, GetVersionResult.FieldInfo.Protect.IDENTIFYING),
                    new GetVersionResult.FieldInfo(TYPE_MEMBER, "MEMBER_LASTNAME", GetVersionResult.FieldInfo.FieldType.STRING, true, GetVersionResult.FieldInfo.Protect.IDENTIFYING),
                    new GetVersionResult.FieldInfo(TYPE_MEMBER, "MEMBER_USERNAME", GetVersionResult.FieldInfo.FieldType.STRING, true, GetVersionResult.FieldInfo.Protect.PUBLIC),
                    new GetVersionResult.FieldInfo(TYPE_MEMBER, "MEMBER_EMAIL", GetVersionResult.FieldInfo.FieldType.STRING, false, GetVersionResult.FieldInfo.Protect.IDENTIFYING)
            ));

    private static final String TYPE_KEY = "KEY";
    private static final List<GetVersionResult.FieldInfo> MINIMUM_KEY_FIELDS =
            Collections.unmodifiableList(Arrays.asList(new GetVersionResult.FieldInfo(TYPE_KEY, "KEY_MEMBER", GetVersionResult.FieldInfo.FieldType.URN, GetVersionResult.FieldInfo.CreationAllowed.REQUIRED, true, false),
                    new GetVersionResult.FieldInfo(TYPE_KEY, "KEY_ID", GetVersionResult.FieldInfo.FieldType.STRING, GetVersionResult.FieldInfo.CreationAllowed.NOT_ALLOWED, true, false),
                    new GetVersionResult.FieldInfo(TYPE_KEY, "KEY_TYPE", GetVersionResult.FieldInfo.FieldType.STRING, GetVersionResult.FieldInfo.CreationAllowed.REQUIRED, true, false),
                    new GetVersionResult.FieldInfo(TYPE_KEY, "KEY_PUBLIC", GetVersionResult.FieldInfo.FieldType.KEY, GetVersionResult.FieldInfo.CreationAllowed.REQUIRED, true, false),
                    new GetVersionResult.FieldInfo(TYPE_KEY, "KEY_PRIVATE", GetVersionResult.FieldInfo.FieldType.KEY, GetVersionResult.FieldInfo.CreationAllowed.ALLOWED, true, false),
                    new GetVersionResult.FieldInfo(TYPE_KEY, "KEY_DESCRIPTION", GetVersionResult.FieldInfo.FieldType.STRING, GetVersionResult.FieldInfo.CreationAllowed.ALLOWED, true, true)
            ));

    @Nonnull
    @Override
    public List<GetVersionResult.FieldInfo> getMinimumFields(String objectName) {
        if (objectName.equalsIgnoreCase(TYPE_MEMBER)) {
            return MINIMUM_MEMBER_FIELDS;

        } else if (objectName.equalsIgnoreCase(TYPE_KEY)) {
            return MINIMUM_KEY_FIELDS;
        } else
            return Collections.emptyList();
    }

    private static final List<String> API_OBJECTS = Collections.unmodifiableList(Arrays.asList(TYPE_MEMBER, TYPE_KEY));

    @Override
    public List<String> getApiObjects() {
        return API_OBJECTS;
    }

    @Override
    public List<String> getRequiredApiServices() {
        return Collections.singletonList(TYPE_MEMBER);
    }

    @Override
    public List<String> getOptionalApiServices() {
        return Collections.singletonList(TYPE_KEY);
    }


    @ApiMethod(order = 1, hint = "get_version call: Provide a structure detailing the version information as well as details of accepted options s for CH API calls.", unprotected = true)
    @Nonnull
    public FederationApiReply<GetVersionResult> getVersion(@Nonnull SfaConnection con) throws JFedException {
        return executeAndLogXmlRpcCommandGeni(null, con, "getVersion", "get_version",
                new ArrayList<>(), resultValueObject -> new GetVersionResult(resultValueObject, true));
    }


    @ApiMethod(order = 2, hint = "lookup call: Lookup information about objects matching given criteria", unprotected = true)
    @Nonnull
    public FederationApiReply<LookupResult<?>> lookup(@Nonnull SfaConnection con,
                                                     @ApiMethodParameter(name = "type", hint = "object type to lookup",
                                                             guiDefault = TYPE_MEMBER, parameterType = ApiMethodParameterType.CH_API2_OBJECT_TYPE)
                                                     @Nonnull String type,
                                                     @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                     @Nullable List<AnyCredential> credentialList,
                                                     @ApiMethodParameter(name = "match", required = false, parameterType = ApiMethodParameterType.CH_API2_MATCH)
                                                     @Nullable Map<String, ?> match,
                                                     @ApiMethodParameter(name = "filter", required = false, parameterType = ApiMethodParameterType.CH_API2_FILTER)
                                                     @Nullable List<String> filter,
                                                     @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                     @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("type", type,
                        "credentialList", credentialList,
                        "match", match,
                        "filter", filter,
                        "extraOptions", extraOptions);

        ReplyConverter replyConverter;
        switch (type) {
            case TYPE_KEY: {
                replyConverter = MemberKeyInfoList::new;
                break;
            }
            case TYPE_MEMBER: {
                replyConverter = MemberInfoList::new;
                break;
            }
            default: {
                replyConverter = HTLookupResult::new;
                break;
            }
        }

        //noinspection unchecked
        return internalLookup(methodParams, con, "lookup", type,
                credentialList, match, filter, extraOptions, null, replyConverter);
    }

    @ApiMethod(order = 3, hint = "update call: Update information about object")
    @Nonnull
    public FederationApiReply<String> update(@Nonnull SfaConnection con,
                                             @ApiMethodParameter(name = "type", hint = "object type to update",
                                                     guiDefault = TYPE_MEMBER, parameterType = ApiMethodParameterType.CH_API2_OBJECT_TYPE)
                                             @Nonnull String type,
                                             @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                             @Nonnull List<AnyCredential> credentialList,
                                             @ApiMethodParameter(name = "urn", parameterType = ApiMethodParameterType.USER_URN)
                                             @Nonnull String urn,
                                             @ApiMethodParameter(name = "fields", parameterType = ApiMethodParameterType.CH_API2_FIELDS)
                                             @Nonnull Map<String, String> fields,
                                             @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                             @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("type", type, "credentialList", credentialList, "urn", urn, "fields", fields, "extraOptions", extraOptions);
        return update_internal(methodParams, con, "update", type, credentialList, urn, null/*urntype*/, fields, extraOptions);
    }

    @ApiMethod(order = 4, hint = "create method")
    public FederationApiReply<Map<String, Object>> create(@Nonnull SfaConnection con,
                                                                @ApiMethodParameter(name = "type", hint = "object type to create",
                                                                        guiDefault = TYPE_KEY, parameterType = ApiMethodParameterType.CH_API2_OBJECT_TYPE)
                                                                @Nonnull String type,
                                                                @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                                @Nonnull List<AnyCredential> credentialList,
                                                                @ApiMethodParameter(name = "fields", parameterType = ApiMethodParameterType.CH_API2_FIELDS)
                                                                @Nonnull Map<String, String> fields,
                                                                @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                                @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("type", type,
                        "credentialList", credentialList,
                        "type", type,
                        "fields", fields,
                        "extraOptions", extraOptions);
        return create_internal(methodParams, con, "create", type, credentialList, fields, extraOptions, AbstractApi::apiSpecifiesMapStringToObject);
    }


    @ApiMethod(order = 5, hint = "delete call: delete an OBJECT")
    @Nonnull
    public FederationApiReply<Boolean> delete(@Nonnull SfaConnection con,
                                              @ApiMethodParameter(name = "type", hint = "object type to delete",
                                                      guiDefault = TYPE_KEY, parameterType = ApiMethodParameterType.CH_API2_OBJECT_TYPE)
                                              @Nonnull String type,
                                              @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                              @Nonnull List<AnyCredential> credentialList,
                                              @ApiMethodParameter(name = "urnToDelete", parameterType = ApiMethodParameterType.STRING)
                                              @Nonnull String urnToDelete,
                                              @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                              @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("type", type, "credentialList", credentialList, "urnToDelete", urnToDelete, "extraOptions", extraOptions);
        return delete_internal(methodParams, con, "delete", type, credentialList, urnToDelete, extraOptions);
    }

    @ApiMethod(order = 10, hint = "Convenience method for lookup call: Lookup information about members matching given criteria", unprotected = true, convenienceMethodFor = "lookup", convenienceMethodObjectType = TYPE_MEMBER)
    @Nonnull
    public FederationApiReply<MemberInfoList> lookupMember(@Nonnull SfaConnection con,
                                                           @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                           @Nullable List<AnyCredential> credentialList,
                                                           @ApiMethodParameter(name = "match", required = false, parameterType = ApiMethodParameterType.CH_API2_MATCH)
                                                           @Nullable Map<String, ?> match,
                                                           @ApiMethodParameter(name = "filter", required = false, parameterType = ApiMethodParameterType.CH_API2_FILTER)
                                                           @Nullable List<String> filter,
                                                           @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                           @Nullable Map<String, Object> extraOptions) throws JFedException {

        Map<String, Object> methodParams =
                makeMethodParameters("credentialList", credentialList,
                        "match", match,
                        "filter", filter,
                        "extraOptions", extraOptions);

        return internalLookup(methodParams, con, "lookupMember", TYPE_MEMBER,
                credentialList, match, filter, extraOptions, null, MemberInfoList::new);
    }


    @ApiMethod(order = 11, hint = "Convenience method for update call: Update MEMBER information", convenienceMethodFor = "update", convenienceMethodObjectType = TYPE_MEMBER)
    @Nonnull
    public FederationApiReply<String> updateMember(@Nonnull SfaConnection con,
                                                   @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                   @Nonnull List<AnyCredential> credentialList,
                                                   @ApiMethodParameter(name = "urn", parameterType = ApiMethodParameterType.USER_URN)
                                                   @Nonnull String urn,
                                                   @ApiMethodParameter(name = "fields", parameterType = ApiMethodParameterType.CH_API2_FIELDS)
                                                   @Nonnull Map<String, String> fields,
                                                   @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                   @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("credentialList", credentialList, "urn", urn, "fields", fields, "extraOptions", extraOptions);
        return update_internal(methodParams, con, "updateMember", TYPE_MEMBER, credentialList, urn, "member", fields, extraOptions);
    }


    /**  */
    @ApiMethod(order = 20, hint = "get_credentials call: Provide list of credentials (signed statements) for given member\n" +
            "This is member-specific information suitable for passing as credentials in an AM API call for aggregate authorization.")
    @Nonnull
    public FederationApiReply<List<AnyCredential>> getCredentials(@Nonnull SfaConnection con,
                                                                  @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                                  @Nonnull List<AnyCredential> credentialList,
                                                                  @ApiMethodParameter(name = "memberUrn", parameterType = ApiMethodParameterType.USER_URN)
                                                                  @Nonnull GeniUrn memberUrn,
                                                                  @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                                  @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("credentialList", credentialList,
                        "memberUrn", memberUrn,
                        "extraOptions", extraOptions);

        if (!Objects.equals(memberUrn.getEncodedResourceType(), "user"))
            LOG.warn("member URN argument to getCredentials is not a valid member urn: \"" + memberUrn + "\" (will be used anyway)");

        return getCredentials_internal(methodParams, con, "getCredentials", TYPE_MEMBER,
                credentialList, memberUrn, extraOptions);
    }


    @ApiMethod(order = 30, hint = "Convenience method for lookup call: Lookup information about KEYs matching given criteria", unprotected = true, convenienceMethodFor = "lookup", convenienceMethodObjectType = TYPE_KEY)
    @Nonnull
    public FederationApiReply<MemberKeyInfoList> lookupKey(@Nonnull SfaConnection con,
                                                           @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                           @Nullable List<AnyCredential> credentialList,
                                                           @ApiMethodParameter(name = "keyId", parameterType = ApiMethodParameterType.STRING, required = false, guiDefaultOptional = true)
                                                           @Nullable GeniUrn keyId,
                                                           @ApiMethodParameter(name = "match", required = false, parameterType = ApiMethodParameterType.CH_API2_MATCH)
                                                           @Nullable Map<String, ?> match,
                                                           @ApiMethodParameter(name = "filter", required = false, parameterType = ApiMethodParameterType.CH_API2_FILTER)
                                                           @Nullable List<String> filter,
                                                           @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                           @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("credentialList", credentialList,
                        "keyId", keyId,
                        "match", match,
                        "filter", filter,
                        "extraOptions", extraOptions);

        Map<String, Object> matchArg = match == null ? null : new HashMap<>(match);
        if (keyId != null) {
            if (matchArg == null)
                matchArg = new HashMap<>();
            matchArg.put("KEY_ID", keyId.getValue());
        }

        return internalLookup(methodParams, con, "lookupKey", TYPE_KEY,
                credentialList, matchArg, filter, extraOptions, null, MemberKeyInfoList::new);
    }

    @ApiMethod(order = 31, hint = "Convenience method for lookup call: Lookup information about KEYs matching given criteria", unprotected = true, convenienceMethodFor = "lookup", convenienceMethodObjectType = TYPE_KEY)
    @Nonnull
    public FederationApiReply<MemberKeyInfoList> lookupKeyForMember(@Nonnull SfaConnection con,
                                                                    @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                                    @Nullable List<AnyCredential> credentialList,
                                                                    @ApiMethodParameter(name = "memberUrn", parameterType = ApiMethodParameterType.USER_URN, required = false, guiDefaultOptional = true)
                                                                    @Nullable GeniUrn memberUrn,
                                                                    @ApiMethodParameter(name = "match", required = false, parameterType = ApiMethodParameterType.CH_API2_MATCH)
                                                                    @Nullable Map<String, ?> match,
                                                                    @ApiMethodParameter(name = "filter", required = false, parameterType = ApiMethodParameterType.CH_API2_FILTER)
                                                                    @Nullable List<String> filter,
                                                                    @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                                    @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("credentialList", credentialList,
                        "memberUrn", memberUrn,
                        "match", match,
                        "filter", filter,
                        "extraOptions", extraOptions);

        Map<String, Object> matchArg = match == null ? null : new HashMap<>(match);
        if (memberUrn != null) {
            if (matchArg == null)
                matchArg = new HashMap<>();
            matchArg.put("KEY_MEMBER", memberUrn.getValue());
        }

        return internalLookup(methodParams, con, "lookupKeyForMember", TYPE_KEY,
                credentialList, matchArg, filter, extraOptions, null, MemberKeyInfoList::new);
    }

    @ApiMethod(order = 32, hint = "Convenience method for update call: Update KEY information", convenienceMethodFor = "update", convenienceMethodObjectType = TYPE_KEY)
    @Nonnull
    public FederationApiReply<String> updateKey(@Nonnull SfaConnection con,
                                                @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                @Nonnull List<AnyCredential> credentialList,
                                                @ApiMethodParameter(name = "id", parameterType = ApiMethodParameterType.USER_URN)
                                                @Nonnull String id,
                                                @ApiMethodParameter(name = "fields", parameterType = ApiMethodParameterType.CH_API2_FIELDS)
                                                @Nonnull Map<String, String> fields,
                                                @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("credentialList", credentialList,
                        "id", id,
                        "fields", fields,
                        "extraOptions", extraOptions);
        return update_internal(methodParams, con, "updateKey", TYPE_KEY, credentialList, id, null, fields, extraOptions);
    }

    @ApiMethod(order = 33, hint = "Convenience method for create call: create KEY", convenienceMethodFor = "create", convenienceMethodObjectType = TYPE_KEY)
    @Nonnull
    public FederationApiReply<MemberKeyInfo> createKey(@Nonnull SfaConnection con,
                                                       @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                       @Nonnull List<AnyCredential> credentialList,
                                                       @ApiMethodParameter(name = "memberUrn", hint = "URN of the owner of this key",
                                                               parameterType = ApiMethodParameterType.USER_URN,
                                                               required = false, guiDefaultOptional = true)
                                                       @Nullable GeniUrn memberUrn,
                                                       @ApiMethodParameter(name = "fields", parameterType = ApiMethodParameterType.CH_API2_FIELDS)
                                                       @Nullable Map<String, String> fields,
                                                       @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false, parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                       @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters(
                        "credentialList", credentialList,
                        "memberUrn", memberUrn,
                        "fields", fields,
                        "extraOptions", extraOptions);

        if (fields == null) {
            fields = new HashMap<>();
        }
        if (memberUrn != null) {
            if (fields.containsKey("KEY_MEMBER")) {
                String fieldsKeyMember = fields.get("KEY_MEMBER") + "";
                if (Objects.equals(fieldsKeyMember, memberUrn.getValue()))
                    LOG.warn("Note: you specified both memberUrn and added KEY_MEMBER in fields, for createKey call." +
                            "They are equal, so no problem. Note that the createKey call only requires one of them.");
                else
                    LOG.error("WARNING: you specified both memberUrn and added KEY_MEMBER in fields for createKey call." +
                            "They are NOT equal! memberUrn='" + memberUrn + "' " +
                            "KEY_MEMBER field value='" + fieldsKeyMember + "' " +
                            "Will give preference to memberUrn parameter!");
            }
            fields.put("KEY_MEMBER", memberUrn.getValue());
        }

        return create_internal(methodParams, con, "createKey", TYPE_KEY, credentialList, fields, extraOptions,
                resultValueObject -> new MemberKeyInfo(apiSpecifiesMapStringToObject(resultValueObject)));
    }

    @ApiMethod(order = 34, hint = "Convenience method for delete call: delete a KEY", convenienceMethodFor = "delete", convenienceMethodObjectType = TYPE_KEY)
    @Nonnull
    public FederationApiReply<Boolean> deleteKey(@Nonnull SfaConnection con,
                                                 @ApiMethodParameter(name = "credentialList", parameterType = ApiMethodParameterType.LIST_OF_CREDENTIAL)
                                                 @Nonnull List<AnyCredential> credentialList,
                                                 @ApiMethodParameter(name = "keyId", parameterType = ApiMethodParameterType.STRING)
                                                 @Nonnull String keyId,
                                                 @ApiMethodParameter(name = "extraOptions", hint = "extra options", required = false,
                                                         parameterType = ApiMethodParameterType.GENI_EXTRA_OPTIONS)
                                                 @Nullable Map<String, Object> extraOptions) throws JFedException {
        Map<String, Object> methodParams =
                makeMethodParameters("credentialList", credentialList,
                        "keyId", keyId,
                        "extraOptions", extraOptions);
        return delete_internal(methodParams, con, "delete", TYPE_KEY, credentialList, keyId, extraOptions);
    }
}
