package org.apereo.cas.support.oauth.services;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apereo.cas.services.AbstractRegisteredService;
import org.apereo.cas.services.RegexRegisteredService;
import org.apereo.cas.services.RegisteredService;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.PostLoad;
import java.util.HashSet;
import java.util.Set;

/**
 * An extension of the {@link RegexRegisteredService} that defines the
 * OAuth client id and secret for a given registered service.
 *
 * @author Misagh Moayyed
 * @since 4.0.0
 */
@Entity
@DiscriminatorValue("oauth")
public class OAuthRegisteredService extends RegexRegisteredService {

    private static final long serialVersionUID = 5318897374067731021L;

    @Column(length = 255, updatable = true, insertable = true)
    private String clientSecret;

    @Column(length = 255, updatable = true, insertable = true)
    private String clientId;

    @Column(updatable = true, insertable = true)
    private Boolean bypassApprovalPrompt = Boolean.FALSE;

    @Column(updatable = true, insertable = true)
    private Boolean generateRefreshToken = Boolean.FALSE;

    @Column(updatable = true, insertable = true)
    private Boolean jsonFormat = Boolean.FALSE;

    @Lob
    @Column(name = "supported_grants", length = Integer.MAX_VALUE)
    private Set<String> supportedGrantTypes = new HashSet<>();

    @Lob
    @Column(name = "supported_responses", length = Integer.MAX_VALUE)
    private Set<String> supportedResponseTypes = new HashSet<>();

    public String getClientId() {
        return this.clientId;
    }

    public void setClientId(final String clientId) {
        this.clientId = clientId;
    }

    public String getClientSecret() {
        return this.clientSecret;
    }

    public void setClientSecret(final String clientSecret) {
        this.clientSecret = clientSecret;
    }

    public Boolean isBypassApprovalPrompt() {
        return this.bypassApprovalPrompt;
    }

    public void setBypassApprovalPrompt(final Boolean bypassApprovalPrompt) {
        this.bypassApprovalPrompt = bypassApprovalPrompt;
    }

    public Boolean isGenerateRefreshToken() {
        return this.generateRefreshToken;
    }

    public void setGenerateRefreshToken(final Boolean generateRefreshToken) {
        this.generateRefreshToken = generateRefreshToken;
    }

    public Boolean isJsonFormat() {
        return this.jsonFormat;
    }

    public void setJsonFormat(final Boolean jsonFormat) {
        this.jsonFormat = jsonFormat;
    }

    public Set<String> getSupportedGrantTypes() {
        return supportedGrantTypes;
    }

    public void setSupportedGrantTypes(final Set<String> supportedGrantTypes) {
        this.supportedGrantTypes = supportedGrantTypes;
    }

    public Set<String> getSupportedResponseTypes() {
        return supportedResponseTypes;
    }

    public void setSupportedResponseTypes(final Set<String> supportedResponseTypes) {
        this.supportedResponseTypes = supportedResponseTypes;
    }

    @Override
    public String toString() {
        final ToStringBuilder builder = new ToStringBuilder(this);
        builder.appendSuper(super.toString());
        builder.append("clientId", getClientId());
        builder.append("approvalPrompt", isBypassApprovalPrompt());
        builder.append("generateRefreshToken", isGenerateRefreshToken());
        builder.append("jsonFormat", isJsonFormat());
        builder.append("supportedResponseTypes", getSupportedResponseTypes());
        builder.append("supportedGrantTypes", getSupportedGrantTypes());
        
        return builder.toString();
    }

    @Override
    public void copyFrom(final RegisteredService source) {
        super.copyFrom(source);
        final OAuthRegisteredService oAuthRegisteredService = (OAuthRegisteredService) source;
        setClientId(oAuthRegisteredService.getClientId());
        setClientSecret(oAuthRegisteredService.getClientSecret());
        setBypassApprovalPrompt(oAuthRegisteredService.isBypassApprovalPrompt());
        setGenerateRefreshToken(oAuthRegisteredService.isGenerateRefreshToken());
        setJsonFormat(oAuthRegisteredService.isJsonFormat());
        setSupportedGrantTypes(oAuthRegisteredService.getSupportedGrantTypes());
        setSupportedResponseTypes(oAuthRegisteredService.getSupportedResponseTypes());
    }

    @Override
    protected AbstractRegisteredService newInstance() {
        return new OAuthRegisteredService();
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        if (obj.getClass() != getClass()) {
            return false;
        }
        final OAuthRegisteredService rhs = (OAuthRegisteredService) obj;
        return new EqualsBuilder()
                .appendSuper(super.equals(obj))
                .append(this.clientSecret, rhs.clientSecret)
                .append(this.clientId, rhs.clientId)
                .append(this.bypassApprovalPrompt, rhs.bypassApprovalPrompt)
                .append(this.generateRefreshToken, rhs.generateRefreshToken)
                .append(this.jsonFormat, rhs.jsonFormat)
                .append(this.supportedResponseTypes, rhs.supportedResponseTypes)
                .append(this.supportedGrantTypes, rhs.supportedGrantTypes)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder()
                .appendSuper(super.hashCode())
                .append(this.clientSecret)
                .append(this.clientId)
                .append(this.bypassApprovalPrompt)
                .append(this.generateRefreshToken)
                .append(this.jsonFormat)
                .append(this.supportedResponseTypes)
                .append(this.supportedGrantTypes)
                .toHashCode();
    }

    /**
     * Post load processing, once the service is located via JPA.
     */
    @PostLoad
    public void postLoad() {
        if (this.supportedGrantTypes == null) {
            this.supportedGrantTypes = new HashSet<>();
        }
        if (this.supportedResponseTypes == null) {
            this.supportedResponseTypes = new HashSet<>();
        }
    }
}

@@ -1548,32 +1548,36 @@
 UE)%0A    private 
+Hash
 Set%3CString%3E supp
@@ -1703,16 +1703,20 @@
 private 
+Hash
 Set%3CStri
@@ -2970,32 +2970,46 @@
 tedGrantTypes = 
+new HashSet%3C%3E(
 supportedGrantTy
@@ -3003,32 +3003,33 @@
 portedGrantTypes
+)
 ;%0A    %7D%0A%0A    pub
@@ -3244,16 +3244,30 @@
 Types = 
+new HashSet%3C%3E(
 supporte
@@ -3272,32 +3272,33 @@
 tedResponseTypes
+)
 ;%0A    %7D%0A%0A    @Ov
@@ -3848,24 +3848,16 @@
 pes());%0A
-        
 %0A       

Fix issue with oauth test cases and JPA service registry attempting to cast sets to blobs.