package de.tu_dresden.diplom.richter_mirko_mat2628335.uddipopulation;

import org.apache.log4j.Logger;
import org.systinet.uddi.client.v3.struct.*;
import org.systinet.uddi.client.v3.UDDI_Inquiry_PortType;
import org.systinet.uddi.client.v3.UDDIException;
import org.systinet.uddi.client.base.StringArrayList;
import org.systinet.uddi.InvalidParameterException;

import java.security.cert.X509Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateException;
import java.io.*;
import java.util.Iterator;
import java.util.Vector;

import de.tu_dresden.diplom.richter_mirko_mat2628335.uddipopulation.businessDiplCoop.DiplomaCooperation;

import javax.xml.soap.SOAPException;

/**
 * Interface to the prototyp "usage counter for WS-Access", being used to obtain the certificates
 * from the UDDI-registry
 */
public class UDDI extends Base {

   private static final Logger logger = Logger.getLogger(UDDI.class);

   /**
    * Gets some UDDIBindingCertEntry from the UDDi-Registry (business is DIPLOMA COOPERATION by default!)
    * ATTENTION: BindingTemplates that doesn't have the technical fingerprint "have certificates" are beeing ignored.
    * @param serviceKey The serviceKey to find the bindingtemplate in.
    * @param bindingKey The bindingTemplateKey to find.
    * @return The Information (cert-chain, accessPoint etc.) obtained out of the UDDI.
    * @see UDDIBindingCertEntry
    */
   private UDDIBindingCertEntry getUDDIBindingCertEntry(String serviceKey, String bindingKey){
      final String fn = "[getUDDIBindingCertEntry] ";
      UDDIBindingCertEntry result = new UDDIBindingCertEntry();
      String bindingTModelKey = Base.CERTIFICATE_TAXONOMY_TMODEL_KEY;
      try {
         Find_binding find_binding = new Find_binding();
         find_binding.setServiceKey(serviceKey);
         find_binding.setTModelKeyArrayList(new StringArrayList(bindingTModelKey));
         //find_binding.setTModelKeyArrayList(new StringArrayList("uddi:notExistent"));
         UDDI_Inquiry_PortType inquiry = getInquiryStub();
         if (logger.isDebugEnabled()) logger.debug(fn + "Search in progress ...");
         BindingDetail bindingDetail = inquiry.find_binding(find_binding);
         BindingTemplateArrayList bindingList = bindingDetail.getBindingTemplateArrayList();
         if (bindingList == null) {
            logger.warn(fn + "No bindings found for the Service '" + serviceKey + "' and tModel-Key '" + bindingTModelKey + "'!");
         } else {
            if (logger.isInfoEnabled()) logger.info(fn + "Found " + bindingList.size() + " bindings for the Service '" + serviceKey + "' and tModel-Key '" + bindingTModelKey + "'");
            if (logger.isDebugEnabled()) logger.debug(fn + "Searching for Binding ...");
            for (Iterator it = bindingList.iterator(); it.hasNext();) {
               BindingTemplate bindTempl = (BindingTemplate) it.next();
               if (bindTempl.getBindingKey().equals(bindingKey)) {
                  if (logger.isInfoEnabled()) logger.info(fn + "Found the Binding!");
                  TModelInstanceInfoArrayList instanceInfos = bindTempl.getTModelInstanceInfoArrayList();
                  if (instanceInfos == null) {
                     logger.warn(fn + "no instanceInfo elements for the Binding!");
                  } else {
                     if (logger.isInfoEnabled()) logger.info(fn + "Found " + instanceInfos.size() + " instanceInfos!");
                     for (Iterator iter = instanceInfos.iterator(); iter.hasNext();) {
                        TModelInstanceInfo instanceInfo = (TModelInstanceInfo) iter.next();
                        if (instanceInfo.getTModelKey().equals(bindingTModelKey)) {
                           if(logger.isInfoEnabled())logger.info(fn + "Found instanceInfo with tModelKey '" + bindingTModelKey+ "'");
                           InstanceDetails details = instanceInfo.getInstanceDetails();
                           result.setCertificatesInUDDI(readCertificateString(details.getInstanceParms()));
                           if(logger.isInfoEnabled())logger.info(fn + "Setting accessPoint to '" + bindTempl.getAccessPoint().getValue() + "'");
                           result.setAccessPoint(bindTempl.getAccessPoint().getValue());
                           break;
                        }
                     }
                  }
                  break;
               }
            }
         }
      } catch (InvalidParameterException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (UDDIException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (SOAPException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
      return result;
   }

   /**
    * Get the UDDI-Entry for the WitnessDigester-Service
    * @return
    */
   public UDDIBindingCertEntry getWitnessDigesterEntry() {
      return getUDDIBindingCertEntry(DiplomaCooperation.WITNESS_SERVICE_KEY, DiplomaCooperation.DIGESTER_KEY);
   }

   /**
    * Get the UDDI-Entry for the WitnessContextRegistrator-Service
    * @return
    */
   public UDDIBindingCertEntry getWitnessContextRegistratorEntry() {
      return getUDDIBindingCertEntry(DiplomaCooperation.WITNESS_SERVICE_KEY, DiplomaCooperation.CONTEXT_REGISTRATOR_KEY);
   }

   /**
    * Get the UDDI-Entry for the TicketReservation-Service
    * @return
    */
   public UDDIBindingCertEntry getTicketReservationEntry() {
      return getUDDIBindingCertEntry(DiplomaCooperation.TICKET_SERVICE_KEY, DiplomaCooperation.TICKET_RESERVATION_KEY);
   }

   /**
    * Get the UDDI-Entry for the TicketBooking-Service
    * @return
    */
   public UDDIBindingCertEntry getTicketBookingEntry() {
      return getUDDIBindingCertEntry(DiplomaCooperation.TICKET_SERVICE_KEY, DiplomaCooperation.TICKET_BOOKING_KEY);
   }

   /**
    * Breaks the String that has been send by the UDDI (normaly more than one certificate)
    * into its Part-Certificates.
    * @param redFromUDDI
    * @return
    */
   private X509Certificate[] readCertificateString(String redFromUDDI) {
      X509Certificate[] result = null;
      try {
         InputStream inStream = new StringBufferInputStream(redFromUDDI);
         BufferedInputStream bis = new BufferedInputStream(inStream);
         CertificateFactory cf = CertificateFactory.getInstance("X.509");
         Vector resultCerts = new Vector();
         while (bis.available() > 0) {
            X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);
            resultCerts.add(cert);
            System.out.println("Subject: " + cert.getSubjectDN());
            System.out.println("Issuer : " + cert.getIssuerDN());
         }
         bis.close();
         inStream.close();
         if(resultCerts.size() > 0){
            result = (X509Certificate[]) resultCerts.toArray(new X509Certificate[resultCerts.size()]);
         }
      } catch (CertificateException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (IOException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
      return result;
   }

}
