package com.izenpe.zain.cliente.cert;

import java.util.ArrayList;

import org.apache.axis.encoding.Base64;
import org.apache.axis.message.MessageElement;
import org.oasis_open.docs.www.dss._2004._06.oasis_dss_1_0_core_schema_wd_27_xsd.VerifyResponse;
import org.w3c.dom.Document;

import com.izenpe.zain.client.ZainConfig;
import com.izenpe.zain.cliente.util.Propiedades;
import com.izenpe.zain.cliente.util.XmlUtil;
import com.izenpe.zain.cliente.util.ZainUtil;
import com.safelayer.trustedx.client.smartwrapper.Constants;
import com.safelayer.trustedx.client.smartwrapper.SmartVerifyRequest;
import com.safelayer.trustedx.client.smartwrapper.SmartVerifyResponse;

public class VerificacionCertificadoX509 {
	// Ejemplo de certificado X.509 a ser verificado.
	private static final String fileName = "miren.cer";

	public static void main(String[] args) {
		try {

			// Asignación de la configuración de forma programática
			ZainConfig.setCurrent(Propiedades.ZAIN_CONFIG);

			/*
			 * Se crea la petición a través de la URL definida en ZAIN_ENDPOINT.
			 */
			SmartVerifyRequest smartVerifyReq = new SmartVerifyRequest(Propiedades.ZAIN_ENDPOINT);

			// Se establece el perfil CERTSTATUS en la petición de Verificación
			// de firma.
			smartVerifyReq.setProfile(Constants.Profile.CERTSTATUS);

			/*
			 * Se establece el idioma de la petición en español. 2
			 * posibilidades: 1. Español: 'es' 2. Inglés: 'en'
			 */
			smartVerifyReq.setLanguage("es");

			/*
			 * Se solicita en la petición de Verificación que se añadan a la
			 * respuesta los valores de los certificados.
			 */
			smartVerifyReq.setAddCertificateValues(Constants.AddValues.SIMPLE);

			/*
			 * Solicitaría que en la respuesta la plataforma añada la
			 * información de revocación de los certificados. (Token OCSP)
			 */
			 smartVerifyReq.setAddRevocationValues(Constants.AddValues.SIMPLE);

			// Datos a verificar.
			smartVerifyReq.setSignatureBase64(Base64.encode(ZainUtil.readBinaryFile("data/input/" + fileName)));
			smartVerifyReq.setSignatureBase64Type(Constants.SignatureType.CERTIFICATE);

			// Envío de la petición.
			SmartVerifyResponse smartVerifyResp = smartVerifyReq.send();

			// Se comprueba la validez del certificado

			if (ZainUtil.isValid(smartVerifyResp)) {
				System.out.println("La validación del certificado es correcta.");
				/*
				 * Mediante el método getInternalObject se puede acceder al objeto
				 * interno de Axis. De este modo, pueden realizarse modificaciones
				 * avanzadas en la petición u obtener algún dato específico de la
				 * respuesta.
				 */
				VerifyResponse verifyResp = (VerifyResponse) smartVerifyResp.getInternalObject();
				MessageElement messageElement = verifyResp.getOptionalOutputs().getCertificateValues().getCertificateList().getCertificate(0).get_any()[0];
				
				Document doc = messageElement.getAsDocument();

				/*
				 * Mediante expresiones XPath, se extrae la información del
				 * certificado X.509.
				 * 
				 */
				String numeroSerie = XmlUtil.getXpath(doc, "/izp:certificado/izp:numeroSerie/text()");
				String reconocido = XmlUtil.getXpath(doc, "/izp:certificado/izp:reconocido/text()");
				String politica = XmlUtil.getXpath(doc, "/izp:certificado/izp:politica/text()");
				String cn = XmlUtil.getXpath(doc, "/izp:certificado/izp:cn/text()");
				String desde = XmlUtil.getXpath(doc, "/izp:certificado/izp:validez/izp:desde/text()");
				String hasta = XmlUtil.getXpath(doc, "/izp:certificado/izp:validez/izp:hasta/text()");
				ArrayList keyUsageList = XmlUtil.getXpathList(doc, "/izp:certificado/izp:keyUsage/izp:uso/text()");
				ArrayList extendedKeyUsageList = XmlUtil.getXpathList(doc, "/izp:certificado/izp:extendedKeyUsage/izp:uso/text()");

				/*
				 *  Se imprime por consola toda la información del certificado X.509.
				 * 
				 * En la clase XmlUtil.java, hay una función que parsea la fecha al 
				 * formato que se ve en la documentación.
				 */
				System.out.println("----- INFORMACIÓN DEL CERTIFICADO -----");
				System.out.println("Número de serie: " + numeroSerie);
				System.out.println("Reconocido: " + reconocido.trim());
				System.out.println("Política: " + politica);
				System.out.println("Nombre común: " + cn);
				System.out.println("Validez - Desde: " + ZainUtil.formatearFecha(desde));
				System.out.println("Validez - Hasta: " + ZainUtil.formatearFecha(hasta));
				for (int i = 0; i < keyUsageList.size(); i++) {
					System.out.println("Uso de la clave [" + i + "]: " + keyUsageList.get(i));
				}
				for (int i = 0; i < extendedKeyUsageList.size(); i++) {
					System.out.println("Uso de la clave extendida [" + i + "]: " + extendedKeyUsageList.get(i));
				}
			} else {
				System.out.println("La validación del certificado no es correcta: " + smartVerifyResp.getResultMessage());
			}


		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}