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

package org.bouncycastle.tsp.ers;

import org.bouncycastle.asn1.tsp.PartialHashtree;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.cms.SignerInformationVerifier;
import java.util.Collection;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.Selector;
import org.bouncycastle.cert.X509CertificateHolder;
import java.util.Date;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.operator.OperatorCreationException;
import java.io.IOException;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.tsp.TimeStampToken;
import org.bouncycastle.operator.DigestCalculator;
import org.bouncycastle.asn1.tsp.ArchiveTimeStamp;

public class ERSArchiveTimeStamp
{
    private final ArchiveTimeStamp archiveTimeStamp;
    private final DigestCalculator digCalc;
    private final TimeStampToken timeStampToken;
    private final byte[] previousChainsDigest;
    private ERSRootNodeCalculator rootNodeCalculator;
    
    public ERSArchiveTimeStamp(final byte[] array, final DigestCalculatorProvider digestCalculatorProvider) throws TSPException, ERSException {
        this(ArchiveTimeStamp.getInstance(array), digestCalculatorProvider);
    }
    
    public ERSArchiveTimeStamp(final ArchiveTimeStamp archiveTimeStamp, final DigestCalculatorProvider digestCalculatorProvider) throws TSPException, ERSException {
        this.rootNodeCalculator = new BinaryTreeRootCalculator();
        this.previousChainsDigest = null;
        try {
            this.archiveTimeStamp = archiveTimeStamp;
            this.timeStampToken = new TimeStampToken(archiveTimeStamp.getTimeStamp());
            this.digCalc = digestCalculatorProvider.get(archiveTimeStamp.getDigestAlgorithmIdentifier());
        }
        catch (final IOException ex) {
            throw new ERSException(ex.getMessage(), ex);
        }
        catch (final OperatorCreationException ex2) {
            throw new ERSException(ex2.getMessage(), ex2);
        }
    }
    
    ERSArchiveTimeStamp(final ArchiveTimeStamp archiveTimeStamp, final DigestCalculator digCalc) throws TSPException, ERSException {
        this.rootNodeCalculator = new BinaryTreeRootCalculator();
        this.previousChainsDigest = null;
        try {
            this.archiveTimeStamp = archiveTimeStamp;
            this.timeStampToken = new TimeStampToken(archiveTimeStamp.getTimeStamp());
            this.digCalc = digCalc;
        }
        catch (final IOException ex) {
            throw new ERSException(ex.getMessage(), ex);
        }
    }
    
    ERSArchiveTimeStamp(final byte[] previousChainsDigest, final ArchiveTimeStamp archiveTimeStamp, final DigestCalculatorProvider digestCalculatorProvider) throws TSPException, ERSException {
        this.rootNodeCalculator = new BinaryTreeRootCalculator();
        this.previousChainsDigest = previousChainsDigest;
        try {
            this.archiveTimeStamp = archiveTimeStamp;
            this.timeStampToken = new TimeStampToken(archiveTimeStamp.getTimeStamp());
            this.digCalc = digestCalculatorProvider.get(archiveTimeStamp.getDigestAlgorithmIdentifier());
        }
        catch (final IOException ex) {
            throw new ERSException(ex.getMessage(), ex);
        }
        catch (final OperatorCreationException ex2) {
            throw new ERSException(ex2.getMessage(), ex2);
        }
    }
    
    public AlgorithmIdentifier getDigestAlgorithmIdentifier() {
        return this.archiveTimeStamp.getDigestAlgorithmIdentifier();
    }
    
    public void validatePresent(final ERSData ersData, final Date date) throws ERSException {
        this.validatePresent(ersData instanceof ERSDataGroup, ersData.getHash(this.digCalc, this.previousChainsDigest), date);
    }
    
    public boolean isContaining(final ERSData ersData, final Date when) throws ERSException {
        if (this.timeStampToken.getTimeStampInfo().getGenTime().after(when)) {
            throw new ArchiveTimeStampValidationException("timestamp generation time is in the future");
        }
        try {
            this.validatePresent(ersData, when);
            return true;
        }
        catch (final Exception ex) {
            return false;
        }
    }
    
    public void validatePresent(final boolean b, final byte[] array, final Date when) throws ERSException {
        if (this.timeStampToken.getTimeStampInfo().getGenTime().after(when)) {
            throw new ArchiveTimeStampValidationException("timestamp generation time is in the future");
        }
        this.checkContainsHashValue(b, array, this.digCalc);
        byte[] recoverRootHash;
        if (this.archiveTimeStamp.getReducedHashTree() != null) {
            recoverRootHash = this.rootNodeCalculator.recoverRootHash(this.digCalc, this.archiveTimeStamp.getReducedHashTree());
        }
        else {
            recoverRootHash = array;
        }
        this.checkTimeStampValid(this.timeStampToken, recoverRootHash);
    }
    
    public TimeStampToken getTimeStampToken() {
        return this.timeStampToken;
    }
    
    public X509CertificateHolder getSigningCertificate() {
        final Store<X509CertificateHolder> certificates = this.timeStampToken.getCertificates();
        if (certificates != null) {
            final Collection<X509CertificateHolder> matches = certificates.getMatches(this.timeStampToken.getSID());
            if (!matches.isEmpty()) {
                return matches.iterator().next();
            }
        }
        return null;
    }
    
    public void validate(final SignerInformationVerifier signerInformationVerifier) throws TSPException {
        this.timeStampToken.validate(signerInformationVerifier);
    }
    
    void checkContainsHashValue(final boolean b, final byte[] array, final DigestCalculator digestCalculator) throws ArchiveTimeStampValidationException {
        final PartialHashtree[] reducedHashTree = this.archiveTimeStamp.getReducedHashTree();
        if (reducedHashTree != null) {
            final PartialHashtree partialHashtree = reducedHashTree[0];
            if (!b && partialHashtree.containsHash(array)) {
                return;
            }
            if (partialHashtree.getValueCount() > 1 && Arrays.areEqual(array, ERSUtil.calculateBranchHash(digestCalculator, partialHashtree.getValues()))) {
                return;
            }
            throw new ArchiveTimeStampValidationException("object hash not found");
        }
        else if (!Arrays.areEqual(array, this.timeStampToken.getTimeStampInfo().getMessageImprintDigest())) {
            throw new ArchiveTimeStampValidationException("object hash not found in wrapped timestamp");
        }
    }
    
    void checkTimeStampValid(final TimeStampToken timeStampToken, final byte[] array) throws ArchiveTimeStampValidationException {
        if (array != null && !Arrays.areEqual(array, timeStampToken.getTimeStampInfo().getMessageImprintDigest())) {
            throw new ArchiveTimeStampValidationException("timestamp hash does not match root");
        }
    }
    
    public Date getGenTime() {
        return this.timeStampToken.getTimeStampInfo().getGenTime();
    }
    
    public Date getExpiryTime() {
        final X509CertificateHolder signingCertificate = this.getSigningCertificate();
        if (signingCertificate != null) {
            return signingCertificate.getNotAfter();
        }
        return null;
    }
    
    public ArchiveTimeStamp toASN1Structure() {
        return this.archiveTimeStamp;
    }
    
    public byte[] getEncoded() throws IOException {
        return this.archiveTimeStamp.getEncoded();
    }
    
    public static ERSArchiveTimeStamp fromTimeStampToken(final TimeStampToken timeStampToken, final DigestCalculatorProvider digestCalculatorProvider) throws TSPException, ERSException {
        return new ERSArchiveTimeStamp(new ArchiveTimeStamp(timeStampToken.toCMSSignedData().toASN1Structure()), digestCalculatorProvider);
    }
}
