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

package com.nimbusds.jose;

import java.util.concurrent.atomic.AtomicBoolean;
import com.nimbusds.jose.shaded.jcip.Immutable;
import com.nimbusds.jose.util.Base64URL;
import java.text.ParseException;
import com.nimbusds.jose.util.JSONArrayUtils;
import com.nimbusds.jose.util.JSONObjectUtils;
import java.util.Map;
import java.util.Iterator;
import java.util.Collections;
import java.util.Collection;
import java.util.Objects;
import java.util.LinkedList;
import java.util.List;
import com.nimbusds.jose.shaded.jcip.ThreadSafe;

@ThreadSafe
public class JWSObjectJSON extends JOSEObjectJSON
{
    private static final long serialVersionUID = 1L;
    private final List<Signature> signatures;
    
    public JWSObjectJSON(final Payload payload) {
        super(payload);
        this.signatures = new LinkedList<Signature>();
        Objects.requireNonNull(payload, "The payload must not be null");
    }
    
    private JWSObjectJSON(final Payload payload, final List<Signature> signatures) {
        super(Objects.requireNonNull(payload, "The payload must not be null"));
        this.signatures = new LinkedList<Signature>();
        if (signatures.isEmpty()) {
            throw new IllegalArgumentException("At least one signature required");
        }
        this.signatures.addAll(signatures);
    }
    
    public List<Signature> getSignatures() {
        return Collections.unmodifiableList((List<? extends Signature>)this.signatures);
    }
    
    public synchronized void sign(final JWSHeader jwsHeader, final JWSSigner signer) throws JOSEException {
        this.sign(jwsHeader, null, signer);
    }
    
    public synchronized void sign(final JWSHeader jwsHeader, final UnprotectedHeader unprotectedHeader, final JWSSigner signer) throws JOSEException {
        try {
            HeaderValidation.ensureDisjoint(jwsHeader, unprotectedHeader);
        }
        catch (final IllegalHeaderException e) {
            throw new IllegalArgumentException(e.getMessage(), e);
        }
        final JWSObject jwsObject = new JWSObject(jwsHeader, this.getPayload());
        jwsObject.sign(signer);
        this.signatures.add(new Signature(this.getPayload(), jwsHeader, unprotectedHeader, jwsObject.getSignature()));
    }
    
    public State getState() {
        if (this.getSignatures().isEmpty()) {
            return State.UNSIGNED;
        }
        for (final Signature sig : this.getSignatures()) {
            if (!sig.isVerified()) {
                return State.SIGNED;
            }
        }
        return State.VERIFIED;
    }
    
    @Override
    public Map<String, Object> toGeneralJSONObject() {
        if (this.signatures.size() < 1) {
            throw new IllegalStateException("The general JWS JSON serialization requires at least one signature");
        }
        final Map<String, Object> jsonObject = JSONObjectUtils.newJSONObject();
        jsonObject.put("payload", this.getPayload().toBase64URL().toString());
        final List<Object> signaturesJSONArray = JSONArrayUtils.newJSONArray();
        for (final Signature signature : this.getSignatures()) {
            final Map<String, Object> signatureJSONObject = signature.toJSONObject();
            signaturesJSONArray.add(signatureJSONObject);
        }
        jsonObject.put("signatures", signaturesJSONArray);
        return jsonObject;
    }
    
    @Override
    public Map<String, Object> toFlattenedJSONObject() {
        if (this.signatures.size() != 1) {
            throw new IllegalStateException("The flattened JWS JSON serialization requires exactly one signature");
        }
        final Map<String, Object> jsonObject = JSONObjectUtils.newJSONObject();
        jsonObject.put("payload", this.getPayload().toBase64URL().toString());
        jsonObject.putAll(this.getSignatures().get(0).toJSONObject());
        return jsonObject;
    }
    
    @Override
    public String serializeGeneral() {
        return JSONObjectUtils.toJSONString(this.toGeneralJSONObject());
    }
    
    @Override
    public String serializeFlattened() {
        return JSONObjectUtils.toJSONString(this.toFlattenedJSONObject());
    }
    
    private static JWSHeader parseJWSHeader(final Map<String, Object> jsonObject) throws ParseException {
        final Base64URL protectedHeader = JSONObjectUtils.getBase64URL(jsonObject, "protected");
        if (protectedHeader == null) {
            throw new ParseException("Missing protected header (required by this library)", 0);
        }
        try {
            return JWSHeader.parse(protectedHeader);
        }
        catch (final ParseException e) {
            if ("Not a JWS header".equals(e.getMessage())) {
                throw new ParseException("Missing JWS \"alg\" parameter in protected header (required by this library)", 0);
            }
            throw e;
        }
    }
    
    public static JWSObjectJSON parse(final Map<String, Object> jsonObject) throws ParseException {
        final Base64URL payloadB64URL = JSONObjectUtils.getBase64URL(jsonObject, "payload");
        if (payloadB64URL == null) {
            throw new ParseException("Missing payload", 0);
        }
        final Payload payload = new Payload(payloadB64URL);
        final Base64URL topLevelSignatureB64 = JSONObjectUtils.getBase64URL(jsonObject, "signature");
        final boolean flattened = topLevelSignatureB64 != null;
        final List<Signature> signatureList = new LinkedList<Signature>();
        if (flattened) {
            final JWSHeader jwsHeader = parseJWSHeader(jsonObject);
            final UnprotectedHeader unprotectedHeader = UnprotectedHeader.parse(JSONObjectUtils.getJSONObject(jsonObject, "header"));
            if (jsonObject.get("signatures") != null) {
                throw new ParseException("The \"signatures\" member must not be present in flattened JWS JSON serialization", 0);
            }
            try {
                HeaderValidation.ensureDisjoint(jwsHeader, unprotectedHeader);
            }
            catch (final IllegalHeaderException e) {
                throw new ParseException(e.getMessage(), 0);
            }
            signatureList.add(new Signature(payload, jwsHeader, unprotectedHeader, topLevelSignatureB64));
        }
        else {
            final Map<String, Object>[] signatures = JSONObjectUtils.getJSONObjectArray(jsonObject, "signatures");
            if (signatures == null || signatures.length == 0) {
                throw new ParseException("The \"signatures\" member must be present in general JSON Serialization", 0);
            }
            for (final Map<String, Object> signatureJSONObject : signatures) {
                final JWSHeader jwsHeader2 = parseJWSHeader(signatureJSONObject);
                final UnprotectedHeader unprotectedHeader2 = UnprotectedHeader.parse(JSONObjectUtils.getJSONObject(signatureJSONObject, "header"));
                try {
                    HeaderValidation.ensureDisjoint(jwsHeader2, unprotectedHeader2);
                }
                catch (final IllegalHeaderException e2) {
                    throw new ParseException(e2.getMessage(), 0);
                }
                final Base64URL signatureB64 = JSONObjectUtils.getBase64URL(signatureJSONObject, "signature");
                if (signatureB64 == null) {
                    throw new ParseException("Missing \"signature\" member", 0);
                }
                signatureList.add(new Signature(payload, jwsHeader2, unprotectedHeader2, signatureB64));
            }
        }
        return new JWSObjectJSON(payload, signatureList);
    }
    
    public static JWSObjectJSON parse(final String json) throws ParseException {
        return parse(JSONObjectUtils.parse(json));
    }
    
    @Immutable
    public static final class Signature
    {
        private final Payload payload;
        private final JWSHeader header;
        private final UnprotectedHeader unprotectedHeader;
        private final Base64URL signature;
        private final AtomicBoolean verified;
        
        private Signature(final Payload payload, final JWSHeader header, final UnprotectedHeader unprotectedHeader, final Base64URL signature) {
            this.verified = new AtomicBoolean(false);
            Objects.requireNonNull(payload);
            this.payload = payload;
            this.header = header;
            this.unprotectedHeader = unprotectedHeader;
            Objects.requireNonNull(signature);
            this.signature = signature;
        }
        
        public JWSHeader getHeader() {
            return this.header;
        }
        
        public UnprotectedHeader getUnprotectedHeader() {
            return this.unprotectedHeader;
        }
        
        public Base64URL getSignature() {
            return this.signature;
        }
        
        private Map<String, Object> toJSONObject() {
            final Map<String, Object> jsonObject = JSONObjectUtils.newJSONObject();
            if (this.header != null) {
                jsonObject.put("protected", this.header.toBase64URL().toString());
            }
            if (this.unprotectedHeader != null && !this.unprotectedHeader.getIncludedParams().isEmpty()) {
                jsonObject.put("header", this.unprotectedHeader.toJSONObject());
            }
            jsonObject.put("signature", this.signature.toString());
            return jsonObject;
        }
        
        public JWSObject toJWSObject() {
            try {
                return new JWSObject(this.header.toBase64URL(), this.payload.toBase64URL(), this.signature);
            }
            catch (final ParseException e) {
                throw new IllegalStateException();
            }
        }
        
        public boolean isVerified() {
            return this.verified.get();
        }
        
        public synchronized boolean verify(final JWSVerifier verifier) throws JOSEException {
            try {
                this.verified.set(this.toJWSObject().verify(verifier));
            }
            catch (final JOSEException e) {
                throw e;
            }
            catch (final Exception e2) {
                throw new JOSEException(e2.getMessage(), e2);
            }
            return this.verified.get();
        }
    }
    
    public enum State
    {
        UNSIGNED, 
        SIGNED, 
        VERIFIED;
    }
}
