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

package com.nimbusds.jwt;

import java.util.HashSet;
import java.util.Objects;
import java.util.ArrayList;
import java.util.Collection;
import com.nimbusds.jose.util.JSONArrayUtils;
import com.nimbusds.jose.Payload;
import java.util.Iterator;
import com.nimbusds.jose.util.JSONObjectUtils;
import com.nimbusds.jwt.util.DateUtils;
import java.net.URISyntaxException;
import java.net.URI;
import java.util.Arrays;
import java.util.Date;
import java.util.Collections;
import java.util.List;
import java.text.ParseException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import com.nimbusds.jose.shaded.jcip.Immutable;
import java.io.Serializable;

@Immutable
public final class JWTClaimsSet implements Serializable
{
    private static final long serialVersionUID = 1L;
    private static final Set<String> REGISTERED_CLAIM_NAMES;
    private final Map<String, Object> claims;
    private final boolean serializeNullClaims;
    
    private JWTClaimsSet(final Map<String, Object> claims, final boolean serializeNullClaims) {
        (this.claims = new LinkedHashMap<String, Object>()).putAll(claims);
        this.serializeNullClaims = serializeNullClaims;
    }
    
    public static Set<String> getRegisteredNames() {
        return JWTClaimsSet.REGISTERED_CLAIM_NAMES;
    }
    
    public String getIssuer() {
        try {
            return this.getStringClaim("iss");
        }
        catch (final ParseException e) {
            return null;
        }
    }
    
    public String getSubject() {
        try {
            return this.getStringClaim("sub");
        }
        catch (final ParseException e) {
            return null;
        }
    }
    
    public List<String> getAudience() {
        final Object audValue = this.getClaim("aud");
        if (audValue instanceof String) {
            return Collections.singletonList(audValue);
        }
        List<String> aud;
        try {
            aud = this.getStringListClaim("aud");
        }
        catch (final ParseException e) {
            return Collections.emptyList();
        }
        return (aud != null) ? aud : Collections.emptyList();
    }
    
    public Date getExpirationTime() {
        try {
            return this.getDateClaim("exp");
        }
        catch (final ParseException e) {
            return null;
        }
    }
    
    public Date getNotBeforeTime() {
        try {
            return this.getDateClaim("nbf");
        }
        catch (final ParseException e) {
            return null;
        }
    }
    
    public Date getIssueTime() {
        try {
            return this.getDateClaim("iat");
        }
        catch (final ParseException e) {
            return null;
        }
    }
    
    public String getJWTID() {
        try {
            return this.getStringClaim("jti");
        }
        catch (final ParseException e) {
            return null;
        }
    }
    
    public Object getClaim(final String name) {
        return this.claims.get(name);
    }
    
    public String getStringClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null || value instanceof String) {
            return (String)value;
        }
        throw new ParseException("The " + name + " claim is not a String", 0);
    }
    
    public String getClaimAsString(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null || value instanceof String) {
            return (String)value;
        }
        final Class<?> clazz;
        if ((clazz = value.getClass()).isPrimitive() || isWrapper(clazz)) {
            return String.valueOf(value);
        }
        throw new ParseException("The " + name + " claim is not and cannot be converted to a String", 0);
    }
    
    private static boolean isWrapper(final Class<?> clazz) {
        return clazz == Integer.class || clazz == Double.class || clazz == Float.class || clazz == Long.class || clazz == Short.class || clazz == Byte.class || clazz == Character.class || clazz == Boolean.class;
    }
    
    public List<Object> getListClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null) {
            return null;
        }
        try {
            return (List)this.getClaim(name);
        }
        catch (final ClassCastException e) {
            throw new ParseException("The " + name + " claim is not a list / JSON array", 0);
        }
    }
    
    public String[] getStringArrayClaim(final String name) throws ParseException {
        final List<?> list = this.getListClaim(name);
        if (list == null) {
            return null;
        }
        final String[] stringArray = new String[list.size()];
        for (int i = 0; i < stringArray.length; ++i) {
            try {
                stringArray[i] = (String)list.get(i);
            }
            catch (final ClassCastException e) {
                throw new ParseException("The " + name + " claim is not a list / JSON array of strings", 0);
            }
        }
        return stringArray;
    }
    
    public List<String> getStringListClaim(final String name) throws ParseException {
        final String[] stringArray = this.getStringArrayClaim(name);
        if (stringArray == null) {
            return null;
        }
        return Collections.unmodifiableList((List<? extends String>)Arrays.asList((T[])stringArray));
    }
    
    public URI getURIClaim(final String name) throws ParseException {
        final String uriString = this.getStringClaim(name);
        if (uriString == null) {
            return null;
        }
        try {
            return new URI(uriString);
        }
        catch (final URISyntaxException e) {
            throw new ParseException("The \"" + name + "\" claim is not a URI: " + e.getMessage(), 0);
        }
    }
    
    public Boolean getBooleanClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null || value instanceof Boolean) {
            return (Boolean)value;
        }
        throw new ParseException("The \"" + name + "\" claim is not a Boolean", 0);
    }
    
    public Integer getIntegerClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number)value).intValue();
        }
        throw new ParseException("The \"" + name + "\" claim is not an Integer", 0);
    }
    
    public Long getLongClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number)value).longValue();
        }
        throw new ParseException("The \"" + name + "\" claim is not a Number", 0);
    }
    
    public Date getDateClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null) {
            return null;
        }
        if (value instanceof Date) {
            return (Date)value;
        }
        if (value instanceof Number) {
            return DateUtils.fromSecondsSinceEpoch(((Number)value).longValue());
        }
        throw new ParseException("The \"" + name + "\" claim is not a Date", 0);
    }
    
    public Float getFloatClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number)value).floatValue();
        }
        throw new ParseException("The \"" + name + "\" claim is not a Float", 0);
    }
    
    public Double getDoubleClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number)value).doubleValue();
        }
        throw new ParseException("The \"" + name + "\" claim is not a Double", 0);
    }
    
    public Map<String, Object> getJSONObjectClaim(final String name) throws ParseException {
        final Object value = this.getClaim(name);
        if (value == null) {
            return null;
        }
        if (value instanceof Map) {
            final Map<String, Object> jsonObject = JSONObjectUtils.newJSONObject();
            final Map<?, ?> map = (Map<?, ?>)value;
            for (final Map.Entry<?, ?> entry : map.entrySet()) {
                if (entry.getKey() instanceof String) {
                    jsonObject.put((String)entry.getKey(), entry.getValue());
                }
            }
            return jsonObject;
        }
        throw new ParseException("The \"" + name + "\" claim is not a JSON object or Map", 0);
    }
    
    public Map<String, Object> getClaims() {
        return Collections.unmodifiableMap((Map<? extends String, ?>)this.claims);
    }
    
    public Payload toPayload() {
        return new Payload(this.toJSONObject(this.serializeNullClaims));
    }
    
    public Payload toPayload(final boolean serializeNullClaims) {
        return new Payload(this.toJSONObject(serializeNullClaims));
    }
    
    public Map<String, Object> toJSONObject() {
        return this.toJSONObject(this.serializeNullClaims);
    }
    
    public Map<String, Object> toJSONObject(final boolean serializeNullClaims) {
        final Map<String, Object> o = JSONObjectUtils.newJSONObject();
        for (final Map.Entry<String, Object> claim : this.claims.entrySet()) {
            if (claim.getValue() instanceof Date) {
                final Date dateValue = claim.getValue();
                o.put(claim.getKey(), DateUtils.toSecondsSinceEpoch(dateValue));
            }
            else if ("aud".equals(claim.getKey())) {
                final List<String> audList = this.getAudience();
                if (audList != null && !audList.isEmpty()) {
                    if (audList.size() == 1) {
                        o.put("aud", audList.get(0));
                    }
                    else {
                        final List<Object> audArray = JSONArrayUtils.newJSONArray();
                        audArray.addAll(audList);
                        o.put("aud", audArray);
                    }
                }
                else {
                    if (!serializeNullClaims) {
                        continue;
                    }
                    o.put("aud", null);
                }
            }
            else if (claim.getValue() != null) {
                o.put(claim.getKey(), claim.getValue());
            }
            else {
                if (!serializeNullClaims) {
                    continue;
                }
                o.put(claim.getKey(), null);
            }
        }
        return o;
    }
    
    @Override
    public String toString() {
        return JSONObjectUtils.toJSONString(this.toJSONObject());
    }
    
    public String toString(final boolean serializeNullClaims) {
        return JSONObjectUtils.toJSONString(this.toJSONObject(serializeNullClaims));
    }
    
    public <T> T toType(final JWTClaimsSetTransformer<T> transformer) {
        return transformer.transform(this);
    }
    
    public static JWTClaimsSet parse(final Map<String, Object> json) throws ParseException {
        final Builder builder = new Builder();
        for (final String s : json.keySet()) {
            final String name = s;
            switch (s) {
                case "iss": {
                    builder.issuer(JSONObjectUtils.getString(json, "iss"));
                    continue;
                }
                case "sub": {
                    final Object subValue = json.get("sub");
                    if (subValue instanceof String) {
                        builder.subject(JSONObjectUtils.getString(json, "sub"));
                        continue;
                    }
                    if (subValue instanceof Number) {
                        builder.subject(String.valueOf(subValue));
                        continue;
                    }
                    if (subValue == null) {
                        builder.subject(null);
                        continue;
                    }
                    throw new ParseException("Illegal sub claim", 0);
                }
                case "aud": {
                    final Object audValue = json.get("aud");
                    if (audValue instanceof String) {
                        final List<String> singleAud = new ArrayList<String>();
                        singleAud.add(JSONObjectUtils.getString(json, "aud"));
                        builder.audience(singleAud);
                        continue;
                    }
                    if (audValue instanceof List) {
                        builder.audience(JSONObjectUtils.getStringList(json, "aud"));
                        continue;
                    }
                    if (audValue == null) {
                        builder.audience((String)null);
                        continue;
                    }
                    throw new ParseException("Illegal aud claim", 0);
                }
                case "exp": {
                    builder.expirationTime(JSONObjectUtils.getEpochSecondAsDate(json, "exp"));
                    continue;
                }
                case "nbf": {
                    builder.notBeforeTime(JSONObjectUtils.getEpochSecondAsDate(json, "nbf"));
                    continue;
                }
                case "iat": {
                    builder.issueTime(JSONObjectUtils.getEpochSecondAsDate(json, "iat"));
                    continue;
                }
                case "jti": {
                    builder.jwtID(JSONObjectUtils.getString(json, "jti"));
                    continue;
                }
                default: {
                    builder.claim(name, json.get(name));
                    continue;
                }
            }
        }
        return builder.build();
    }
    
    public static JWTClaimsSet parse(final String s) throws ParseException {
        return parse(JSONObjectUtils.parse(s));
    }
    
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof JWTClaimsSet)) {
            return false;
        }
        final JWTClaimsSet that = (JWTClaimsSet)o;
        return Objects.equals(this.claims, that.claims);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(this.claims);
    }
    
    static {
        final Set<String> n = new HashSet<String>();
        n.add("iss");
        n.add("sub");
        n.add("aud");
        n.add("exp");
        n.add("nbf");
        n.add("iat");
        n.add("jti");
        REGISTERED_CLAIM_NAMES = Collections.unmodifiableSet((Set<? extends String>)n);
    }
    
    public static class Builder
    {
        private final Map<String, Object> claims;
        private boolean serializeNullClaims;
        
        public Builder() {
            this.claims = new LinkedHashMap<String, Object>();
            this.serializeNullClaims = false;
        }
        
        public Builder(final JWTClaimsSet jwtClaimsSet) {
            this.claims = new LinkedHashMap<String, Object>();
            this.serializeNullClaims = false;
            this.claims.putAll(jwtClaimsSet.claims);
        }
        
        public Builder serializeNullClaims(final boolean enable) {
            this.serializeNullClaims = enable;
            return this;
        }
        
        public Builder issuer(final String iss) {
            this.claims.put("iss", iss);
            return this;
        }
        
        public Builder subject(final String sub) {
            this.claims.put("sub", sub);
            return this;
        }
        
        public Builder audience(final List<String> aud) {
            this.claims.put("aud", aud);
            return this;
        }
        
        public Builder audience(final String aud) {
            if (aud == null) {
                this.claims.put("aud", null);
            }
            else {
                this.claims.put("aud", Collections.singletonList(aud));
            }
            return this;
        }
        
        public Builder expirationTime(final Date exp) {
            this.claims.put("exp", exp);
            return this;
        }
        
        public Builder notBeforeTime(final Date nbf) {
            this.claims.put("nbf", nbf);
            return this;
        }
        
        public Builder issueTime(final Date iat) {
            this.claims.put("iat", iat);
            return this;
        }
        
        public Builder jwtID(final String jti) {
            this.claims.put("jti", jti);
            return this;
        }
        
        public Builder claim(final String name, final Object value) {
            this.claims.put(name, value);
            return this;
        }
        
        public Map<String, Object> getClaims() {
            return Collections.unmodifiableMap((Map<? extends String, ?>)this.claims);
        }
        
        public JWTClaimsSet build() {
            return new JWTClaimsSet(this.claims, this.serializeNullClaims, null);
        }
    }
}
