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

package org.bouncycastle.tsp.ers;

import java.util.HashSet;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.tsp.TSTInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.tsp.ArchiveTimeStamp;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.tsp.TimeStampResponse;
import java.math.BigInteger;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.asn1.tsp.PartialHashtree;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import java.io.IOException;
import java.io.OutputStream;
import org.bouncycastle.asn1.tsp.ArchiveTimeStampSequence;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.operator.DigestCalculator;

public class ERSArchiveTimeStampGenerator
{
    private final DigestCalculator digCalc;
    private List<ERSData> dataObjects;
    private ERSRootNodeCalculator rootNodeCalculator;
    private byte[] previousChainHash;
    
    public ERSArchiveTimeStampGenerator(final DigestCalculator digCalc) {
        this.dataObjects = new ArrayList<ERSData>();
        this.rootNodeCalculator = new BinaryTreeRootCalculator();
        this.digCalc = digCalc;
    }
    
    public void addData(final ERSData ersData) {
        this.dataObjects.add(ersData);
    }
    
    public void addAllData(final List<ERSData> list) {
        this.dataObjects.addAll(list);
    }
    
    void addPreviousChains(final ArchiveTimeStampSequence archiveTimeStampSequence) throws IOException {
        final OutputStream outputStream = this.digCalc.getOutputStream();
        outputStream.write(archiveTimeStampSequence.getEncoded("DER"));
        outputStream.close();
        this.previousChainHash = this.digCalc.getDigest();
    }
    
    public TimeStampRequest generateTimeStampRequest(final TimeStampRequestGenerator timeStampRequestGenerator) throws TSPException, IOException {
        return timeStampRequestGenerator.generate(this.digCalc.getAlgorithmIdentifier(), this.rootNodeCalculator.computeRootHash(this.digCalc, this.getPartialHashtrees()));
    }
    
    public TimeStampRequest generateTimeStampRequest(final TimeStampRequestGenerator timeStampRequestGenerator, final BigInteger bigInteger) throws TSPException, IOException {
        return timeStampRequestGenerator.generate(this.digCalc.getAlgorithmIdentifier(), this.rootNodeCalculator.computeRootHash(this.digCalc, this.getPartialHashtrees()), bigInteger);
    }
    
    public ERSArchiveTimeStamp generateArchiveTimeStamp(final TimeStampResponse timeStampResponse) throws TSPException, ERSException {
        final IndexedPartialHashtree[] partialHashtrees = this.getPartialHashtrees();
        if (partialHashtrees.length != 1) {
            throw new ERSException("multiple reduced hash trees found");
        }
        final byte[] computeRootHash = this.rootNodeCalculator.computeRootHash(this.digCalc, partialHashtrees);
        if (timeStampResponse.getStatus() != 0) {
            throw new TSPException("TSP response error status: " + timeStampResponse.getStatusString());
        }
        final TSTInfo asn1Structure = timeStampResponse.getTimeStampToken().getTimeStampInfo().toASN1Structure();
        if (!asn1Structure.getMessageImprint().getHashAlgorithm().equals(this.digCalc.getAlgorithmIdentifier())) {
            throw new ERSException("time stamp imprint for wrong algorithm");
        }
        if (!Arrays.areEqual(asn1Structure.getMessageImprint().getHashedMessage(), computeRootHash)) {
            throw new ERSException("time stamp imprint for wrong root hash");
        }
        if (partialHashtrees[0].getValueCount() == 1) {
            return new ERSArchiveTimeStamp(new ArchiveTimeStamp(null, null, timeStampResponse.getTimeStampToken().toCMSSignedData().toASN1Structure()), this.digCalc);
        }
        return new ERSArchiveTimeStamp(new ArchiveTimeStamp(this.digCalc.getAlgorithmIdentifier(), partialHashtrees, timeStampResponse.getTimeStampToken().toCMSSignedData().toASN1Structure()), this.digCalc);
    }
    
    public List<ERSArchiveTimeStamp> generateArchiveTimeStamps(final TimeStampResponse timeStampResponse) throws TSPException, ERSException {
        final IndexedPartialHashtree[] partialHashtrees = this.getPartialHashtrees();
        final byte[] computeRootHash = this.rootNodeCalculator.computeRootHash(this.digCalc, partialHashtrees);
        if (timeStampResponse.getStatus() != 0) {
            throw new TSPException("TSP response error status: " + timeStampResponse.getStatusString());
        }
        final TSTInfo asn1Structure = timeStampResponse.getTimeStampToken().getTimeStampInfo().toASN1Structure();
        if (!asn1Structure.getMessageImprint().getHashAlgorithm().equals(this.digCalc.getAlgorithmIdentifier())) {
            throw new ERSException("time stamp imprint for wrong algorithm");
        }
        if (!Arrays.areEqual(asn1Structure.getMessageImprint().getHashedMessage(), computeRootHash)) {
            throw new ERSException("time stamp imprint for wrong root hash");
        }
        final ContentInfo asn1Structure2 = timeStampResponse.getTimeStampToken().toCMSSignedData().toASN1Structure();
        final ArrayList list = new ArrayList();
        if (partialHashtrees.length == 1 && partialHashtrees[0].getValueCount() == 1) {
            list.add(new ERSArchiveTimeStamp(new ArchiveTimeStamp(null, null, asn1Structure2), this.digCalc));
        }
        else {
            final ERSArchiveTimeStamp[] array = new ERSArchiveTimeStamp[partialHashtrees.length];
            for (int i = 0; i != partialHashtrees.length; ++i) {
                array[partialHashtrees[i].order] = new ERSArchiveTimeStamp(new ArchiveTimeStamp(this.digCalc.getAlgorithmIdentifier(), this.rootNodeCalculator.computePathToRoot(this.digCalc, partialHashtrees[i], i), asn1Structure2), this.digCalc);
            }
            for (int j = 0; j != partialHashtrees.length; ++j) {
                list.add(array[j]);
            }
        }
        return list;
    }
    
    private IndexedPartialHashtree[] getPartialHashtrees() {
        final List<IndexedHash> buildIndexedHashList = ERSUtil.buildIndexedHashList(this.digCalc, this.dataObjects, this.previousChainHash);
        final IndexedPartialHashtree[] array = new IndexedPartialHashtree[buildIndexedHashList.size()];
        final HashSet set = new HashSet();
        for (int i = 0; i != this.dataObjects.size(); ++i) {
            if (this.dataObjects.get(i) instanceof ERSDataGroup) {
                set.add(this.dataObjects.get(i));
            }
        }
        for (int j = 0; j != buildIndexedHashList.size(); ++j) {
            final byte[] digest = buildIndexedHashList.get(j).digest;
            final ERSData ersData = this.dataObjects.get(buildIndexedHashList.get(j).order);
            if (ersData instanceof ERSDataGroup) {
                final List<byte[]> hashes = ((ERSDataGroup)ersData).getHashes(this.digCalc, this.previousChainHash);
                array[j] = new IndexedPartialHashtree(buildIndexedHashList.get(j).order, (byte[][])hashes.toArray(new byte[hashes.size()][]));
            }
            else {
                array[j] = new IndexedPartialHashtree(buildIndexedHashList.get(j).order, digest);
            }
        }
        return array;
    }
    
    private static class IndexedPartialHashtree extends PartialHashtree
    {
        final int order;
        
        private IndexedPartialHashtree(final int order, final byte[] array) {
            super(array);
            this.order = order;
        }
        
        private IndexedPartialHashtree(final int order, final byte[][] array) {
            super(array);
            this.order = order;
        }
    }
}
