package com.izenpe.signupdate.client.xades;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.oasis_open.docs.www.dss._2004._06.oasis_dss_1_0_core_schema_wd_27_xsd.OptionalOutputs;
import org.w3c.dom.Document;

import com.izenpe.zain.client.SignUpdateConfig;
import com.izenpe.zain.signupdate.SignupdateRequestSender;
import com.izenpe.zain.signupdate.SignupdateResponse;
import com.izenpe.zain.signupdate.constants.Language;
import com.izenpe.zain.signupdate.constants.SignaturePlacement;
import com.izenpe.zain.signupdate.constants.SignatureProfile;
import com.izenpe.zain.signupdate.constants.XPathPosition;
import com.izenpe.zain.signupdate.utils.XpathUtils;
import com.izenpe.zain.signupdate.wss.UsernameTokenHeader;

public final class XadesEpesEnveloped {
	private static final String INPUT_PATH = "inputs\\xades.xml";
	private static final String OUTPUT_PATH = "outputs\\signedXadesEpesEnveloped.xml";
	private static final String END_POINT = "https://psf.izenpe.com:8080/trustedx-sgw/SignUpdateGateway";
//	private static final String END_POINT = "https://psf.izenpe.com:8443/trustedx-sgw/SignUpdateGateway";
	
	public static SignUpdateConfig ZAIN_CONFIG;
	static {
		ZAIN_CONFIG = new SignUpdateConfig();

		ZAIN_CONFIG.setAuthenticationPolicy("urn:izenpe:tws:policies:authentication:psf");

		ZAIN_CONFIG.setTruststoreActive(true);
		ZAIN_CONFIG.setTruststorePath("./keystore/<nombre_truststore>");
		ZAIN_CONFIG.setTruststorePassword("Contraseña del almacen de certificados");

		ZAIN_CONFIG.setKeystoreActive(false);
		ZAIN_CONFIG.setKeystorePath("./keystore/<nombre_keystore>");
		ZAIN_CONFIG.setKeystorePassword("Contraseña del almacen de claves");
		ZAIN_CONFIG.setKeystoreType("PKCS12");

		ZAIN_CONFIG.setProxyActive(false);
		ZAIN_CONFIG.setProxyHost("");
		ZAIN_CONFIG.setProxyPort("");
		ZAIN_CONFIG.setProxyUsername("");
		ZAIN_CONFIG.setProxyPassword("");
		
		ZAIN_CONFIG.setTimeout("20000");

		ZAIN_CONFIG.setRequestLogActive(true);
		ZAIN_CONFIG.setRequestLogSavePath("./soap_messages/request/");
		ZAIN_CONFIG.setResponseLogActive(true);
		ZAIN_CONFIG.setResponseLogSavePath("./soap_messages/response/");
	}

	public static void main(String[] args) throws Exception {
		new XadesEpesEnveloped();
	}

	private XadesEpesEnveloped() throws Exception {
		// ====================================================================================================
		// CONFIGURACION DINAMICA DE LAS PROPIEDADES
		// ====================================================================================================
		SignUpdateConfig.setCurrent(ZAIN_CONFIG);
		
		// ====================================================================================================
		// LEEMOS EL FICHERO A FIRMAR
		// ====================================================================================================
		final InputStream inputStream = new FileInputStream(XadesEpesEnveloped.INPUT_PATH);
		final byte[] buff = new byte[inputStream.available()];
		inputStream.read(buff);
		inputStream.close();
		
		// ====================================================================================================
		// SE CREA LA CABECERA WS-SECURITY CON USERNAMETOKEN
		// ====================================================================================================
		UsernameTokenHeader header = new UsernameTokenHeader();
		header.setUsername("username");
		header.setPassword("password");
		
		// ====================================================================================================
		// REALIZAMOS LA PETICION
		// ====================================================================================================
		final SignupdateResponse signupdateResponse 
				= SignupdateRequestSender
						.getSender()
							.setUsernameTokenHeader(header)
							.setEndpoint(XadesEpesEnveloped.END_POINT)
							.setSignatureProfile(SignatureProfile.XADES_EPES)
							.setSignaturePlacement(SignaturePlacement.ENVELOPED)
							.setXmlEnvelopedXPathPosition("//sitioFirma", XPathPosition.FIRST_CHILD)
							.setSignPropertyPolicy("urn:ejgv:dss:policy:1")
							.setLanguage(Language.ES)
	//						.setZainSigner("DN")
							.setSignatureDocumentBytes(buff)
						.sendRequest();

		// ====================================================================================================
		// PROCESAMOS LA RESPUESTA
		// ====================================================================================================
		if (signupdateResponse.isValid()) {
			System.out.println("Firma XADES EPES ENVELOPED correcta ===========================================");
			System.out.println("===============================================================================");

			// Firma ------------------------------------------------------------------------------------------
			final byte[] signature = signupdateResponse.getSignature();

			final OutputStream outputStream = new FileOutputStream(XadesEpesEnveloped.OUTPUT_PATH);
			outputStream.write(signature);
			outputStream.close();

			System.out.println("Firma guardada ----------------------------------------------------------------");
			System.out.println("");

			// Certificado ------------------------------------------------------------------------------------
			final Document[] certificates = signupdateResponse.getCertificates();
			for (int i = 0; i < certificates.length; i++) {
				System.out.println("Certificado obtenido ----------------------------------------------------------");

				final String numeroSerie = XpathUtils.getInstance().getValue(certificates[i], "/certificado/numeroSerie/text()");
				final String reconocido = XpathUtils.getInstance().getValue(certificates[i], "/certificado/reconocido/text()");
				final String politica = XpathUtils.getInstance().getValue(certificates[i], "/certificado/politica/text()");
				final String cn = XpathUtils.getInstance().getValue(certificates[i], "/certificado/cn/text()");
				final String subject = XpathUtils.getInstance().getValue(certificates[i], "/certificado/subject/text()");
				final String fechaDesde = XpathUtils.getInstance().getValue(certificates[i], "/certificado/validez/desde/text()");
				final String fechaHasta = XpathUtils.getInstance().getValue(certificates[i], "/certificado/validez/hasta/text()");
				final List<String> keyUsageList = XpathUtils.getInstance().getValueList(certificates[i], "/certificado/keyUsage/uso/text()");
				final List<String> extendedKeyUsageList = XpathUtils.getInstance().getValueList(certificates[i], "/certificado/extendedKeyUsage/uso/text()");

				System.out.println("Numero de serie: " + numeroSerie);
				System.out.println("Reconocido: " + reconocido);
				System.out.println("Política: " + politica);
				System.out.println("Nombre: " + cn);
				System.out.println("Subject: " + subject);
				System.out.println("Validez - Desde: " + fechaDesde);
				System.out.println("Validez - Hasta: " + fechaHasta);
				System.out.println("Key usage: " + Arrays.toString(keyUsageList.toArray()));
				System.out.println("Extended key usage: " + Arrays.toString(extendedKeyUsageList.toArray()));
				System.out.println("");
			}
			
			// Timestamp --------------------------------------------------------------------------------------
			final Date timestampDate = signupdateResponse.getTimestampDate();
			System.out.println("Timestamp obtenido ------------------------------------------------------------");
			System.out.println("Fecha: " + timestampDate);
			System.out.println("");
			
			OptionalOutputs optionalOutputs = signupdateResponse.getOptionalOutputs();
			System.out.println("Formato de firma ------------------------------------------------------------");
			System.out.println("Formato: " + optionalOutputs.getNewSignatureForm());
			System.out.println("");
		} else {
			final String resultMajor = signupdateResponse.getResultMajor();
			final String resultMinor = signupdateResponse.getResultMinor();

			System.out.println("Se ha producido un error en la firma ==========================================");
			System.out.println("===============================================================================");
			System.out.println("Major: " + resultMajor);
			System.out.println("Minor: " + resultMinor);
			System.out.println("Message: " + signupdateResponse.getResultMessage());
			System.out.println("");
		}
	}
}
