// 
// Decompiled by Procyon v0.6.0
// 

package com.nimbusds.jose;

import java.security.Signature;
import com.nimbusds.jose.util.StandardCharset;
import java.text.ParseException;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jose.shaded.jcip.ThreadSafe;

@ThreadSafe
public class JWSObject extends JOSEObject
{
    private static final long serialVersionUID = 1L;
    private final JWSHeader header;
    private final String signingInputString;
    private Base64URL signature;
    private final AtomicReference<State> state;
    
    public JWSObject(final JWSHeader header, final Payload payload) {
        this.state = new AtomicReference<State>();
        this.header = Objects.requireNonNull(header);
        this.setPayload(Objects.requireNonNull(payload));
        this.signingInputString = this.composeSigningInput();
        this.signature = null;
        this.state.set(State.UNSIGNED);
    }
    
    public JWSObject(final Base64URL firstPart, final Base64URL secondPart, final Base64URL thirdPart) throws ParseException {
        this(firstPart, new Payload(secondPart), thirdPart);
    }
    
    public JWSObject(final Base64URL firstPart, final Payload payload, final Base64URL thirdPart) throws ParseException {
        this.state = new AtomicReference<State>();
        try {
            this.header = JWSHeader.parse(firstPart);
        }
        catch (final ParseException e) {
            throw new ParseException("Invalid JWS header: " + e.getMessage(), 0);
        }
        this.setPayload(Objects.requireNonNull(payload));
        this.signingInputString = this.composeSigningInput();
        if (thirdPart.toString().trim().isEmpty()) {
            throw new ParseException("The signature must not be empty", 0);
        }
        this.signature = thirdPart;
        this.state.set(State.SIGNED);
        if (this.getHeader().isBase64URLEncodePayload()) {
            this.setParsedParts(firstPart, payload.toBase64URL(), thirdPart);
        }
        else {
            this.setParsedParts(firstPart, new Base64URL(""), thirdPart);
        }
    }
    
    @Override
    public JWSHeader getHeader() {
        return this.header;
    }
    
    private String composeSigningInput() {
        if (this.header.isBase64URLEncodePayload()) {
            return this.getHeader().toBase64URL().toString() + '.' + this.getPayload().toBase64URL().toString();
        }
        return this.getHeader().toBase64URL().toString() + '.' + this.getPayload().toString();
    }
    
    public byte[] getSigningInput() {
        return this.signingInputString.getBytes(StandardCharset.UTF_8);
    }
    
    public Base64URL getSignature() {
        return this.signature;
    }
    
    public State getState() {
        return this.state.get();
    }
    
    private void ensureUnsignedState() {
        if (this.state.get() != State.UNSIGNED) {
            throw new IllegalStateException("The JWS object must be in an unsigned state");
        }
    }
    
    private void ensureSignedOrVerifiedState() {
        if (this.state.get() != State.SIGNED && this.state.get() != State.VERIFIED) {
            throw new IllegalStateException("The JWS object must be in a signed or verified state");
        }
    }
    
    private void ensureJWSSignerSupport(final JWSSigner signer) throws JOSEException {
        if (!signer.supportedJWSAlgorithms().contains(this.getHeader().getAlgorithm())) {
            throw new JOSEException("The " + this.getHeader().getAlgorithm() + " algorithm is not allowed or supported by the JWS signer: Supported algorithms: " + signer.supportedJWSAlgorithms());
        }
    }
    
    public synchronized void sign(final JWSSigner signer) throws JOSEException {
        this.ensureUnsignedState();
        this.ensureJWSSignerSupport(signer);
        try {
            this.signature = signer.sign(this.getHeader(), this.getSigningInput());
        }
        catch (final ActionRequiredForJWSCompletionException e) {
            throw new ActionRequiredForJWSCompletionException(e.getMessage(), e.getTriggeringOption(), new CompletableJWSObjectSigning() {
                @Override
                public Signature getInitializedSignature() {
                    return e.getCompletableJWSObjectSigning().getInitializedSignature();
                }
                
                @Override
                public Base64URL complete() throws JOSEException {
                    JWSObject.this.signature = e.getCompletableJWSObjectSigning().complete();
                    JWSObject.this.state.set(State.SIGNED);
                    return JWSObject.this.signature;
                }
            });
        }
        catch (final JOSEException e2) {
            throw e2;
        }
        catch (final Exception e3) {
            throw new JOSEException(e3.getMessage(), e3);
        }
        this.state.set(State.SIGNED);
    }
    
    public synchronized boolean verify(final JWSVerifier verifier) throws JOSEException {
        this.ensureSignedOrVerifiedState();
        boolean verified;
        try {
            verified = verifier.verify(this.getHeader(), this.getSigningInput(), this.getSignature());
        }
        catch (final JOSEException e) {
            throw e;
        }
        catch (final Exception e2) {
            throw new JOSEException(e2.getMessage(), e2);
        }
        if (verified) {
            this.state.set(State.VERIFIED);
        }
        return verified;
    }
    
    @Override
    public String serialize() {
        return this.serialize(false);
    }
    
    public String serialize(final boolean detachedPayload) {
        this.ensureSignedOrVerifiedState();
        if (detachedPayload) {
            return this.header.toBase64URL().toString() + '.' + '.' + this.signature.toString();
        }
        return this.signingInputString + '.' + this.signature.toString();
    }
    
    public static JWSObject parse(final String s) throws ParseException {
        final Base64URL[] parts = JOSEObject.split(s);
        if (parts.length != 3) {
            throw new ParseException("Unexpected number of Base64URL parts, must be three", 0);
        }
        return new JWSObject(parts[0], parts[1], parts[2]);
    }
    
    public static JWSObject parse(final String s, final Payload detachedPayload) throws ParseException {
        final Base64URL[] parts = JOSEObject.split(s);
        if (parts.length != 3) {
            throw new ParseException("Unexpected number of Base64URL parts, must be three", 0);
        }
        if (!parts[1].toString().isEmpty()) {
            throw new ParseException("The payload Base64URL part must be empty", 0);
        }
        return new JWSObject(parts[0], detachedPayload, parts[2]);
    }
    
    public enum State
    {
        UNSIGNED, 
        SIGNED, 
        VERIFIED;
    }
}
