// SigBlockExtension.java
// $Id: SigBlockExtension.java,v 1.1 1997/04/15 20:39:06 yhchu Exp $
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

// The source code is jointly developed by W3C and some of its members
// participating in the Digital Signature Initiative.  The authors are:
//    Mark Champine, HP, <champine@apollo.hp.com>
//    Yang-hua Chu, MIT/W3C, <yhchu@w3.org>
//    Vasanthan Dasan, Sun, <vasanthan.dasan@central.sun.com>
//    Peter Lipp, University of Technology, Graz <plipp@iaik.tu-graz.ac.at>
//    Andreas Sterbenz, U. of Technology, Graz <sterbenz@iaik.tu-graz.ac.at>

package w3c.www.dsig;

import java.security.*;
import java.util.Vector;
import java.util.Enumeration;
import w3c.www.dsig.*;
import w3c.tools.sexpr.*;

/**
 * DSig SigBlockExtension class.
 * <P>
 * This class is a representation of the DSig SigBlock as defined in the
 * DSig label specification. A SigBlock consists of some AttribInfo and
 * zero or more signatures.
 * <P>
 * The class allows to get and set the sigblock's attribinfo, add
 * remove, etc. signature suites, and to verify the signatures
 * contained in the signatures suites.
 *
 * @version 1.0beta (last modified 3-October-1997)
 * @author Andreas Sterbenz
 * @author Yang-hua Chu
 */

// yc-m: public class SigBlockExtension extends UserOptionValue {
public class SigBlockExtension {

  private AttribInfo ainfo;
  private Vector sigSuites;
  private static final boolean DEBUG = false;

  /**
   * The name of the extension identifier
   */
  public static final
  String EXTENSION_ID="http://www.w3.org/TR/1998/REC-DSig-label/sigblock-1_0";

  /**
   * Create an empty Signature Block
   */
  public SigBlockExtension()
  {
    this.ainfo = new AttribInfo();
    this.sigSuites = new Vector();
    // yc-d: super.setOptional();
    // yc-d: super.setURL(EXTENSION_ID);
  }

  /**
   * Verify the signature suites in this sigblock according to the
   * user's default policy. Currently hardcoded to be equivalent to
   * verifyAll(label).
   */
  public Trivalue verify(DSigLabelInterface label)
  {
    return verifyAll(label);
  }

  /**
   * Verify if all signatures suites in this sigblock correctly sign
   * the given label.
   */
  public Trivalue verifyAll(DSigLabelInterface label)
  {
    if( size() == 0 ) return Trivalue.newUnknown();
    Trivalue result = Trivalue.newTrue();
    for (Enumeration e = sigSuites() ; e.hasMoreElements() ;) {
      SignatureSuite suite1 = (SignatureSuite)e.nextElement();
      result = result.and(suite1.verify(label, null));
      if (DEBUG) System.out.println("SigBlockExtension: " + suite1.getURL() + 
				    ": " + result.toString());
    }
    return result;
  }

  /**
   * Verify if all signatures suites with the identifying URL suitename
   * in this sigblock correctly sign the given label.
   */
  public Trivalue verify(DSigLabelInterface label, String suiteName)
  {
    SignatureSuite[] suites = getSigSuites(suiteName);
    if( suites.length == 0 ) return Trivalue.newUnknown();
    Trivalue result = Trivalue.newTrue();
    for( int i=0; i<suites.length; i++ ) {
      result = result.and(suites[i].verify(label, null));
    }
    return result;
  }

  /**
   * parse a UserOptionValue into a SigBlock
   * @exception DSigException if the data cannot be parsed correctly.
   */
  public void parse(Vector v) throws DSigException
  {
    ainfo.parse((Vector) v.elementAt(0));  // parse AttribInfo
    if (DEBUG) System.out.println("\nThe AttribInfo is " + ainfo.toString());
    for (int i=1; i<v.size(); i++) {
      SignatureSuite suite = SignatureSuite.parse2((Vector) v.elementAt(i));
      sigSuites.addElement(suite);
      if (DEBUG) System.out.println("\nThe SigSuite # " + i + " is " +
				   suite.toString());
    }
  }
//   void parse(UserOptionValue optionVal)
//     throws SigLabelException
//   {
//     if (optionVal.isMandatory())
//       setMandatory();
//     else
//       setOptional();
//     Object v[] = optionVal.getData();
//     ainfo.parse((Vector) v[0]);  // parse AttribInfo
//     if(DEBUG) System.out.println("\nThe AttribInfo is "+ ainfo.toString());
//     for (int i=1; i<v.length; i++) {
// //      SignatureSuite suite = new SignatureSuite();
// //      suite.parse((Vector) v[i]);

//       // AS: Parsing modified!!
//       SignatureSuite suite = SignatureSuite.parse2((Vector) v[i]);
//       sigSuites.addElement(suite);
//       if(DEBUG) System.out.println("\nThe SigSuite # " + i + " is " +
// 				    suite.toString());
//     }
//   }


  /**
   * Returns this SigBlock's AttribInfo object.
   */
  public AttribInfo getAttribInfo()
  {
    return ainfo;
  }


  /**
   * Sets the SigBlock's AttribInfo to the given object.
   */
  public void setAttribInfo(AttribInfo ainfo)
  {
    this.ainfo = ainfo;
  }

  /**
   * Add a SigSuite to this SigBlock's list of signatures suite.
   */
  public void addSigSuite(SignatureSuite suite)
  {
    sigSuites.addElement(suite);
  }

  /**
   * Removes a SigSuite from the SigBlock
   *
   * @return true if the SigSuite was found and removed, false otherwise.
   */
  public boolean removeSigSuite(SignatureSuite suite)
  {
    return sigSuites.removeElement(suite);
  }

  /**
   * Remove all signature suites from the sigblock. Usefull when the
   * label has been modified so that the signatures would be invalid
   * anyway.
   */
  public void removeAllSigSuites()
  {
    sigSuites = new Vector();
  }

  /**
   * Get all signature suites with the identifying URL suitename;
   * Returns an array of size 0 if none are found.
   */
  public SignatureSuite[] getSigSuites(String suiteName)
  {
    Vector suitevec = new Vector();
    for( Enumeration e = sigSuites(); e.hasMoreElements(); ) {
      SignatureSuite suite1 = (SignatureSuite)e.nextElement();
      if( suiteName.equals(suite1.getURL()) ) {
        suitevec.addElement(suite1);
      }
    }
    SignatureSuite[] suitearray = new SignatureSuite[suitevec.size()];
    suitevec.copyInto(suitearray);
    return suitearray;
  }


  /**
   * Return an enumeration of all signature suites in this sigblock.
   */
  public Enumeration sigSuites()
  {
    return sigSuites.elements();
  }

  /**
   * Returns the number of SigSuites that are stored in this SigBlock object.
   */
  public int size()
  {
    return sigSuites.size();
  }

  /**
   * Return the signature at position index in this SigBlock.
   * @exception ArrayIndexOutOfBoundsException if the index is not valid.
   */
  public SignatureSuite getSigSuiteAt(int index) 
       throws ArrayIndexOutOfBoundsException
  {
    return (SignatureSuite)sigSuites.elementAt(index);
  }

  /**
    * Return an S-Expression Vector representation of this
    * SigBlock extension.
    */
  public Vector toVector()
  {
    Vector v = new Vector();
    v.addElement(ainfo.toVector());  // attribinfo
    for (int i=0; i<sigSuites.size(); i++)  // sigsuite
      v.addElement(((SignatureSuite)sigSuites.elementAt(i)).toVector());
    return v;
  }

  /**
    * Return an S-Expression string representation of this
    * SigBlock extension.
    */
  public String toString()
  {
    String s = "";
    Vector v = toVector();
    for (int i=0; i< v.size(); i++)
      s += DSigUtil.toString(v.elementAt(i));
    return s;
  }

//   UserOptionValue toUserOptionValue()
//   {
//     Vector v1[] = new Vector[this.size()+1];  // # of sigsuite + 1 attribinfo
//     v1[0] = ainfo.toVector();
//     for (int i=0; i<sigSuites.size(); i++)
//       v1[i+1] = ((SignatureSuite)sigSuites.elementAt(i)).toVector();
//     super.setData(v1);
//     return (UserOptionValue)this;
//   }


//   /**
//    * Return an S-Expression string representation of this
//    * SigBlock extension.
//    */
//   public String toString()
//   {
//     toUserOptionValue();
//     return super.toString();
//   }

}

