package WSS4J;

import com.ibm.xml.sax.StandardErrorHandler;
import java.io.File;
import org.xml.sax.InputSource;
import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.Key;
import org.w3c.dom.Node;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ibm.xml.dsig.KeyInfo;
import com.ibm.xml.dsig.SignatureContext;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

public class X509CertificatePointerToken extends SignatureToken
{
    private static WSSMessage wssMessage = null;

    public X509CertificatePointerToken(
                String keyStoreFileName,
                String keyStorePassword,
                String keyName,
                String tokenWSUId,
                WSSMessage wssMessage
                ){

        super(keyStoreFileName, keyStorePassword, keyName, tokenWSUId, wssMessage );

        this.wssMessage = wssMessage;

    }

    public String getType()
    {
        return "X509CertificatePointerToken";
    }

    public String getXMLString()
    {
        return null;
    }

    public String sign(
                 String wsuElementID,
                 String digestAlgo,
                 String signatureAlgo,
                 String canonicalizationAlgo
                 ){

          Element templateElement = null;
          Element x509Data = null;

          try{

              /*****Step1*****/
              Document inputDoc = wssMessage.getWSSDocument();
              templateElement =  
                                 (Element) inputDoc.importNode(
                                 templateRootEl, 
                                 true
                                 );

              /*****Step2*****/
              Element reference = (Element) templateElement.
                                   getElementsByTagName("Reference").item(0);
              reference.setAttribute( "URI", "#" + wsuElementID );

              /*****Step3*****/
              Element digestMethod = 
                               (Element)templateElement.
                            getElementsByTagName("DigestMethod").item(0);
              digestMethod.setAttribute ( "Algorithm", digestAlgo );

              Element signatureMethod = 
                              (Element)templateElement.
                           getElementsByTagName("SignatureMethod").item(0);
              signatureMethod.setAttribute ( "Algorithm", signatureAlgo );

              Element canonicalizationMethod = 
                           (Element)templateElement.
                        getElementsByTagName("CanonicalizationMethod").item(0);
              canonicalizationMethod.setAttribute 
                                      ( "Algorithm", canonicalizationAlgo );

              /*****Step4*****/
              KeyInfo.X509Data x5data = new KeyInfo.X509Data();
              x5data.setParameters(certificate, true, false, false);

              KeyInfo keyInfo = new KeyInfo();
              keyInfo.setX509Data(new KeyInfo.X509Data[] { x5data });

              keyInfo.insertTo(templateElement);

              /*****Step5*****/
              Element keyInfoEl = (Element)templateElement.
                                     getElementsByTagName("KeyInfo").item(0);

              Element securityTokenRef = templateElement.
                                    getOwnerDocument().createElementNS(
                               "http://schemas.xmlsoap.org/ws/2002/secext",
                               "SecurityTokenReference"
                               );

              securityTokenRef.setAttribute(
                               "xmlns",
                               "http://schemas.xmlsoap.org/ws/2002/secext"
                               );

              keyInfoEl.appendChild ( securityTokenRef );

              /*****Step6*****/
              x509Data = (Element) templateElement.
                                    getElementsByTagNameNS(
                                    "http://www.w3.org/2000/09/xmldsig#",
                                    "X509Data").item(0);

              x509Data.setAttribute( 
                             "xmlns", 
                             "http://www.w3.org/2000/09/xmldsig#" );

              x509Data.getParentNode().removeChild(x509Data);
              inputDoc.normalize();

              securityTokenRef.appendChild ( x509Data );

              /*****Step7*****/
              SignatureContext sigContext = new SignatureContext();

              /*****Step8*****/
              sigContext.setIDResolver(new WSUIdResolver());

              /*****Step9*****/
              sigContext.sign(templateElement, key);

          }catch( Exception e ) {
             System.out.println( 
              "Exception in X509CertificatePointerToken's sign......" );
             e.printStackTrace();
          } // end of catch

        return getXMLString( templateElement );  
    }

    public String signWithXPath(
                 String XPathExpression,
                 String digestAlgo,
                 String signatureAlgo,
                 String canonicalizationAlgo
                 ){

          Element templateElement = null;
          Element x509Data = null;

          try{

              /*****Step1*****/
              Document inputDoc = wssMessage.getWSSDocument();
              templateElement =  
                                 (Element) inputDoc.importNode(
                                 templateRootEl, 
                                 true
                                 );

              /*****Step2*****/
              String xpathTransform = 
                   "\n<Transforms>" +
                   "\n    <Transform " + 
                   "\nAlgorithm=\"http://www.w3.org/TR/1999/REC-xpath-19991116\">" +
                   "\n        <XPath xmlns=\"http://www.w3.org/2000/09/xmldsig#\">" +
                   "\n            " + XPathExpression +
                   "\n        </XPath>" + 
                   "\n    </Transform>" +
                   "\n</Transforms>\n";

              Document XPathTransformDoc = loadDocument(xpathTransform);
              Element referenceElementFirstChild = null;
              Element referenceElement = (Element) templateElement.
                                      getElementsByTagName ( "Reference" ).
                                      item(0);

              NodeList referenceElementChilds = referenceElement.
                                                          getChildNodes();
              for ( int i = 0; i < referenceElementChilds.getLength(); i++ ){
                  if ( referenceElementChilds.item(i).getNodeType() == 
                                                              Node.ELEMENT_NODE ){
                      referenceElementFirstChild = 
                                    (Element) referenceElementChilds.item(i);
                      break;  
                  }// end of if
              }// end of for
              Element XPathTransformElement = (Element) inputDoc.importNode(
                                   XPathTransformDoc.getDocumentElement(), 
                                   true
                                   );

              referenceElement.insertBefore(
                                XPathTransformElement,
                                referenceElementFirstChild
                                );

              /*****Step3*****/
              Element digestMethod = 
                               (Element)templateElement.
                            getElementsByTagName("DigestMethod").item(0);
              digestMethod.setAttribute ( "Algorithm", digestAlgo );

              Element signatureMethod = 
                              (Element)templateElement.
                           getElementsByTagName("SignatureMethod").item(0);
              signatureMethod.setAttribute ( "Algorithm", signatureAlgo );

              Element canonicalizationMethod = 
                           (Element)templateElement.
                        getElementsByTagName("CanonicalizationMethod").item(0);
              canonicalizationMethod.setAttribute 
                                      ( "Algorithm", canonicalizationAlgo );

              /*****Step4*****/
              KeyInfo.X509Data x5data = new KeyInfo.X509Data();
              x5data.setParameters(certificate, true, false, false);

              KeyInfo keyInfo = new KeyInfo();
              keyInfo.setX509Data(new KeyInfo.X509Data[] { x5data });

              keyInfo.insertTo(templateElement);

              /*****Step5*****/
              Element keyInfoEl = (Element)templateElement.
                                     getElementsByTagName("KeyInfo").item(0);

              Element securityTokenRef = templateElement.
                                    getOwnerDocument().createElementNS(
                               "http://schemas.xmlsoap.org/ws/2002/secext",
                               "SecurityTokenReference"
                               );

              securityTokenRef.setAttribute(
                               "xmlns",
                               "http://schemas.xmlsoap.org/ws/2002/secext"
                               );

              keyInfoEl.appendChild ( securityTokenRef );

              /*****Step6*****/
              x509Data = (Element) templateElement.
                                    getElementsByTagNameNS(
                                    "http://www.w3.org/2000/09/xmldsig#",
                                    "X509Data").item(0);

              x509Data.setAttribute( 
                             "xmlns", 
                             "http://www.w3.org/2000/09/xmldsig#" );

              x509Data.getParentNode().removeChild(x509Data);
              inputDoc.normalize();

              securityTokenRef.appendChild ( x509Data );

              /*****Step7*****/
              SignatureContext sigContext = new SignatureContext();

              /*****Step8*****/
              sigContext.setIDResolver(new WSUIdResolver());

              /*****Step9*****/
              sigContext.sign(templateElement, key);

          }catch( Exception e ) {
             System.out.println( 
              "Exception in X509CertificatePointerToken's signXPath.." );
             e.printStackTrace();
          }
        return getXMLString( templateElement );  
    }
}