//////////////////////////////////////////////////////////////////////////// 
// 
// Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1993, 1994, 1995.
// Unpublished work.  All Rights Reserved.
// 
// The software contained on this media is the property of the
// DSTC Pty Ltd.  Use of this software is strictly in accordance
// with the license agreement in the accompanying LICENSE.DOC 
// file. If your distribution of this software does not contain 
// a LICENSE.DOC file then you have no rights to use this 
// software in any manner and should contact DSTC at the address 
// below to determine an appropriate licensing arrangement.
// 
//      DSTC Pty Ltd
//      Level 7, GP South
//      University of Queensland
//      St Lucia, 4072
//      Australia
//      Tel: +61 7 3365 4310
//      Fax: +61 7 3365 4311
//      Email: jcsi@dstc.qut.edu.au
// 
// This software is being provided "AS IS" without warranty of
// any kind.  In no event shall DSTC Pty Ltd be liable for
// damage of any kind arising out of or in connection with
// the use or performance of this software.
// 
//////////////////////////////////////////////////////////////////////////// 

package com.dstc.security.cms.v1;

import java.util.Vector;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import com.dstc.security.x509.AlgorithmId;
import com.dstc.security.x509.X509CertImpl;
import com.dstc.security.cms.v1.CertificateSet;
import com.dstc.security.cms.v1.CRLSet;
import com.dstc.security.cms.v1.SignerInfo;
import com.dstc.security.asn1.Asn1;
import com.dstc.security.asn1.Asn1Exception;
import com.dstc.security.asn1.Constructed;
import com.dstc.security.asn1.Sequence;
import com.dstc.security.asn1.SetOf;
import com.dstc.security.provider.OID;

/**
 * <p> Implements the ASN.1 structure SignedData.
 *
 * <pre>
 *     SignedData ::= SEQUENCE {
 *        version CMSVersion, 
 *        digestAlgorithms DigestAlgorithmIdentifiers,
 *        encapContentInfo EncapsulatedContentInfo,
 *        certificates [0] IMPLICIT CertificateSet OPTIONAL,
 *        crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
 *        signerInfos SignerInfos }
 *      
 *     DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
 *      
 *     SignerInfos ::= SET OF SignerInfo
 * </pre>
 *
 * @version 0.98, 98/07/01
 * @author Ming Yung
 */
public final class SignedData extends Sequence
{
  private int version = 1;
  private Set digestAlgos;
  private EncapContentInfo contentInfo;
  private Set certificates;
  private Set crls;
  private Set signerInfos;

  /**
   * Constructs a SignedData from a Set of algorithms, a ContentInfo,
   * a Set of Certificates, a Set of CRLs and a Set of SignerInfo
   */
  public SignedData(Set algos, EncapContentInfo contentInfo,
                    Set certs, Set crls, Set signers)
  {
     if (!contentInfo.getContentType().equals(OID.id_data))
       this.version = 3;
     addComponent(new com.dstc.security.asn1.Integer(this.version));

     this.digestAlgos = algos;
     SetOf setOf = new SetOf();
     Iterator it = algos.iterator();
     while (it.hasNext())
     { 
       setOf.addComponent(new AlgorithmId(OID.getAlgOid((String)it.next()))); 
     }
     addComponent(setOf);

     this.contentInfo = contentInfo;
     addComponent(this.contentInfo);

     try
     {
       if (certs != null)
       {
         this.certificates = certs;
         CertificateSet certSet = new CertificateSet(certs);
         certSet.setTagNumber(0);
         certSet.setTagClass(Asn1.TAG_CLASS_CONTEXT);
         addComponent(certSet);
       }
  
       if (crls != null)
       {
         this.crls = crls;
         CRLSet crlSet = new CRLSet(crls);
         crlSet.setTagNumber(1);
         crlSet.setTagClass(Asn1.TAG_CLASS_CONTEXT);
         addComponent(crlSet);
       }
     }
     catch (Exception e)
     {
       e.printStackTrace();
     }

     this.signerInfos = signers;
     setOf = new SetOf();
     it = signers.iterator();
     while (it.hasNext())
     { 
       setOf.addComponent((SignerInfo)it.next());
     }
     addComponent(setOf);
  }

  /**
   * Constructs a SignedData from a DER encoding
   */
  public SignedData(byte encoded[]) throws Asn1Exception
  {
    doDecode(encoded);
    int i = 0;

    this.version = 
      ((com.dstc.security.asn1.Integer)components.elementAt(i++)).getInt();

    this.digestAlgos = new HashSet();
    SetOf set = (SetOf)components.elementAt(i++);
    Vector comps = set.getComponents();
    for (int j=0; j<comps.size(); j++)
    {
      this.digestAlgos.add(new AlgorithmId(
        ((Asn1)comps.elementAt(j)).encode()));
    }

    this.contentInfo = 
      new EncapContentInfo(((Asn1)components.elementAt(i++)).encode());
    
    try
    {
      if (((Constructed)components.elementAt(i)).getTagNumber() == 0)
      {
        this.certificates = 
          (new CertificateSet(((Asn1)components.elementAt(i)
            ).encode())).getCerts();
        i++;
      }
    }
    catch (ClassCastException e)
    {
      //Ignore
    }
    
    try
    {
      if (((Constructed)components.elementAt(i)).getTagNumber() == 1)
      {
        this.crls = 
          (new CRLSet(((Asn1)components.elementAt(i)).encode())).getCRLs();
        i++;
      }
    }
    catch (ClassCastException e)
    {
      //Ignore
    }
    
    this.signerInfos = new HashSet();
    set = (SetOf)components.elementAt(i++);
    comps = set.getComponents();
    for (int j=0; j<comps.size(); j++)
    {
      this.signerInfos.add(new SignerInfo(
        ((Asn1)comps.elementAt(j)).encode()));
    }
  }

  /**
   * Return the EncapsulatedContentInfo for this SignedData
   */
  public EncapContentInfo getContentInfo()
  {
    return this.contentInfo;
  }

  /**
   * Return a Set of SignerInfo objects for this SignedData
   */
  public Set getSignerInfos()
  {
    return this.signerInfos;
  }

  /**
   * Return a Set of X509Certificates for this SignedData
   */
  public Set getCertificates()
  {
    return this.certificates;
  }

  /**
   * Return a Set of X509CRLs for this SignedData
   */
  public Set getCRLs()
  {
    return this.crls;
  }
}
