package net.catcert.psa.test.signature;

import java.math.BigInteger;
import java.security.cert.X509Certificate;
import java.util.List;

import net.catcert.psa.services.PsaServices;
import net.catcert.psa.util.CompleteSignatureResponseUtils;
import net.catcert.psa.util.MultiSignatureAtSignatureManagerUtils;
import net.catcert.psa.util.Utils;

import org.bouncycastle.util.encoders.Base64;

import com.sadiel.catcert.psa.ws.client.SignatureServiceStub;
import com.sadiel.catcert.psa.ws.client.factory.PSARequestFactory;
import com.sadiel.catcert.psa.ws.signature.CompleteSignatureDocument;
import com.sadiel.catcert.psa.ws.signature.CompleteSignatureResponseDocument;
import com.sadiel.catcert.psa.ws.signature.InitSignatureAtSignatureManagerDocument;
import com.sadiel.catcert.psa.ws.signature.InitSignatureAtSignatureManagerResponseDocument;
import com.sadiel.catcert.psa.ws.signature.UploadInfoRitualSignatureDocument;
import com.sadiel.catcert.psa.ws.signature.UploadInfoRitualSignatureResponseDocument;
import com.sadiel.www.pdf.visiblesignature.v0_1.CertificateDataListType;
import com.sadiel.www.pdf.visiblesignature.v0_1.CertificateDataType;
import com.sadiel.www.pdf.visiblesignature.v0_1.RectangleInfoType;
import com.sadiel.www.pdf.visiblesignature.v0_1.VisibleSignatureDataType;
import com.sadiel.www.pdf.visiblesignature.v0_1.VisibleSignaturePosition;

import dss_directsign.profiles._0._1.psa.catcert.CompleteSignatureRQSTDocument.CompleteSignatureRQST;
import dss_directsign.profiles._0._1.psa.catcert.InitSignatureAtSignatureManagerRQSTDocument.InitSignatureAtSignatureManagerRQST;
import dss_directsign.profiles._0._1.psa.catcert.MultiCompleteSignatureRSPNSDocument.MultiCompleteSignatureRSPNS;
import dss_directsign.profiles._0._1.psa.catcert.MultiSignatureAtSignatureManagerRSPNSDocument.MultiSignatureAtSignatureManagerRSPNS;
import dss_directsign.profiles._0._1.psa.catcert.OriginalAndEncryptedHashType;
import dss_directsign.profiles._0._1.psa.catcert.UploadInfoRitualSignatureRQSTDocument.UploadInfoRitualSignatureRQST;


/**
 * Classe d'exemple del procés de MultiSignatureAtSignatureManager.
 * @author suport tècnic CATCert
 *
 */
public class MultiSignatureAtSignatureManagerSample {

	public static void main(String args[]){

		try{

			/** PETICIÓ 1: Obtenció de l'acte de signatura
			 * 
			 * Paràmetres:
			 * - document a signar
			 * - política de procediment 
			 * - camp de signatura
			 * 
			 * Resposta:
			 * - identificador de l'acte de signatura
			 * 
			 * **/

			System.out.println("===========================================================");
			System.out.println("PETICIÓ 1: Obtenció de l'acte de signatura");
			System.out.println("===========================================================");

			//política de procediment
			//PP-0004 -> política de test per signatura d'un o múltiples documents PDF
			String functionalProcedureId = "PP-0004";

			//compromís
			String commUri = "urn:catcert:compromisos:signatura:aprovo";

			//documents a signar
			String dataToSignFilePath = System.getProperty("user.dir")+"/resource/test/docs/prova.pdf";
			byte[] dataToSign = Utils.resourceAsBytes(dataToSignFilePath);
			byte[][] documents = new byte[1][dataToSign.length];
			documents[0] = dataToSign;

			//validació contra PSIS
			boolean psisValidation = false;

			//signatura visible
			boolean showVisibleSign = true;

			//configuració de la signatura visible
			VisibleSignatureDataType visibleSignDataType = VisibleSignatureDataType.Factory.newInstance();
			VisibleSignaturePosition visibleSignPosition = VisibleSignaturePosition.Factory.newInstance();
			//rectangle del camp de signatura
			RectangleInfoType rectangle = RectangleInfoType.Factory.newInstance();
			rectangle.setLowerLeftX(BigInteger.valueOf(100));
			rectangle.setLowerLeftY(BigInteger.valueOf(100));
			rectangle.setUpperRightX(BigInteger.valueOf(430));
			rectangle.setUpperRightY(BigInteger.valueOf(200));
			rectangle.setPageNumber("1");
			visibleSignPosition.setRectangleInfo(rectangle);
			visibleSignDataType.setVisibleSignaturePosition(visibleSignPosition);
			//data
			visibleSignDataType.setDate(true);
			//imatge
			visibleSignDataType.setImage(false);
			//localització
			visibleSignDataType.setLocation(true);
			//raó
			visibleSignDataType.setReason(true);
			//camps del certificat
			CertificateDataListType certDataListType = CertificateDataListType.Factory.newInstance();
			com.sadiel.www.pdf.visiblesignature.v0_1.CertificateDataType.Enum[] certificateDataArray = new com.sadiel.www.pdf.visiblesignature.v0_1.CertificateDataType.Enum[7];
			certificateDataArray[0] = CertificateDataType.COUNTRY;
			certificateDataArray[1] = CertificateDataType.ORGANIZATION_NAME;
			certificateDataArray[2] = CertificateDataType.TITLE;
			certificateDataArray[3] = CertificateDataType.SURNAME;
			certificateDataArray[4] = CertificateDataType.GIVEN_NAME;
			certificateDataArray[5] = CertificateDataType.COMMON_NAME;
			certificateDataArray[6] = CertificateDataType.SERIAL_NUMBER;
			certDataListType.setCertificateDataArray(certificateDataArray);
			visibleSignDataType.setInfoText(certDataListType);

			//rol (no el coneixem a priori)
			String role = null;

			//l'usuari ha llegit el/s document/s a signar?
			boolean docsRead = true;

			//petició de signatura
			InitSignatureAtSignatureManagerRQST request = PSARequestFactory._().createInitSignatureAtManager(
					functionalProcedureId, 
					documents, 
					role, 
					null, 
					null, 
					null, 
					commUri,
					null, 
					docsRead, 
					showVisibleSign, 
					visibleSignDataType, 
					psisValidation);




			//localització (idioma)
			String locale = "ES";

			// petició multiple
			InitSignatureAtSignatureManagerRQST[] requests = new InitSignatureAtSignatureManagerRQST[1];
			requests[0] = request;
			//certificat de signatura (no el coneixem a priori)
			byte[] certByteArray = null;


			//petició de multisignatura (encara que només haguem de signar un document, cal muntar aquesta petició)
			InitSignatureAtSignatureManagerDocument multiRequest = PSARequestFactory._().createMultiInitSignatureAtManager(locale, certByteArray, requests);


			//servei de signatura
			SignatureServiceStub signatureServiceStub = PsaServices.getInstance().getSignatureServiceStub(); 

			//resposta de multisignatura
			InitSignatureAtSignatureManagerResponseDocument multiResponse = signatureServiceStub.initSignatureAtSignatureManager(multiRequest);

			MultiSignatureAtSignatureManagerRSPNS response = multiResponse.getInitSignatureAtSignatureManagerResponse().getMultiSignatureAtSignatureManagerRSPNS();
			//pintem la/es resposta/es
			MultiSignatureAtSignatureManagerUtils.pintaMultiSignatureAtSignatureManagerRespostes(response);

			//recuperem l'identificador de l'acte de signatura
			String actOid = (String) MultiSignatureAtSignatureManagerUtils.getActOids(response).get(0);

			/**
			 * CRIDA A L'APPLET PER RECUPERAR EL CERTIFICAT DE CLIENT
			 * TODO
			 */

			System.out.println();
			System.out.println("===========================================================");
			System.out.println("CRIDA APPLET: Obtenció del certificat del client");
			System.out.println("===========================================================");
			System.out.println("TODO");


			//suposem que hem recuperat aquest certificat
			//certificat de signatura
			String certFilePath = System.getProperty("user.dir")+"/resource/test/signature/SIGN_SegellOrgan_Ajuntament_Exemple.cer";
			X509Certificate x509Certificate = Utils.getX509Certificate(certFilePath);
			certByteArray = x509Certificate.getEncoded();


			//pintem el certificat de signatura
			System.out.println("Certificat d'exemple:");
			String certBase64 = new String(Base64.encode(certByteArray),"UTF-8");
			System.out.println(certBase64);


			/**
			 * PETICIÓ 2: Obtenció del hash de les dades a signar
			 * 
			 * Paràmetres:
			 * - identificador de l'acte de signatura
			 * - certificat del signatari
			 * - compromís
			 * - rol
			 * 
			 * Resposta:
			 * - identificador de l'acte de signatura
			 * - hash
			 * 
			 */

			System.out.println();
			System.out.println("===========================================================");
			System.out.println("PETICIÓ 2: Obtenció del hash de les dades a signar");
			System.out.println("===========================================================");

			//petició per actualització del ritual de signatura
			UploadInfoRitualSignatureRQST[] uploadInfoRitualSignRequestArray = new UploadInfoRitualSignatureRQST[1];
			UploadInfoRitualSignatureRQST uploadInfoRitualSignRqst = UploadInfoRitualSignatureRQST.Factory.newInstance();
			uploadInfoRitualSignRqst.setSignatureActOID(actOid);
			uploadInfoRitualSignRqst.setCertificate(certByteArray);
			uploadInfoRitualSignRequestArray[0] = uploadInfoRitualSignRqst;

			//petició per actualització de ritual de multisignatura (encara que només haguem de signar un document, cal muntar aquesta petició)
			UploadInfoRitualSignatureDocument multiUploadInfoRitualSignRequest = PSARequestFactory._().createMultiUploadInfoRQST(locale, uploadInfoRitualSignRequestArray);

			//resposta
			UploadInfoRitualSignatureResponseDocument multiResponseDoc = signatureServiceStub.uploadInfoRitualSignature(multiUploadInfoRitualSignRequest);
			MultiSignatureAtSignatureManagerRSPNS multiResponse2 = multiResponseDoc.getUploadInfoRitualSignatureResponse().getMultiSignatureAtSignatureManagerRSPNS();

			//pintem la/es resposta/es
			MultiSignatureAtSignatureManagerUtils.pintaMultiSignatureAtSignatureManagerRespostes(multiResponse2);

			//obtenció del/s hash/es 
			List hashes = MultiSignatureAtSignatureManagerUtils.getHashes(multiResponse2);


			/**
			 * CRIDA A L'APPLET PER SIGNAR LES DADES
			 * TODO
			 */

			System.out.println();
			System.out.println("===========================================================");
			System.out.println("CRIDA APPLET: Encriptació del/s hash/s");
			System.out.println("===========================================================");
			System.out.println("TODO");

			//suposem que tenim aquest hash signat
			//hash imaginari, signat amb el certificat del segell d'òrgan de l'Ajuntament d'Exemple
			String encryptedHashBase64 = "vc4j2EZ1YHzzUgKT9OdgmEjv44t9fQyCTK02EnwxNv0I9fuQPuhPVsRnCIcFnN+kUJnTI9xJF66fCb1iHcnjklOmcj/5t+2HcjeciuANkz7Koxj+beMECOx1/Y024Ig/324AgAcZzbtFfU85wJplPNeXgsPJ3xWvKLAVFxh/AgU=";
			byte[] encryptedHash = Base64.decode(encryptedHashBase64.getBytes());

			//pintem el hash encriptat
			System.out.println("Hash encriptat de proves: "+encryptedHashBase64);


			/**
			 *  PETICIÓ 3: Finalització del procés de signatura
			 *  
			 * Paràmetres:
			 * - identificador de l'acte de signatura
			 * - hash encriptat
			 * 
			 * Resposta:
			 * - identificador d'acte de signatura
			 * - document signat
			 */

			System.out.println();
			System.out.println("===========================================================");
			System.out.println("PETICIÓ 3: Finalització del procés de signatura");
			System.out.println("===========================================================");

			//la resposta ha d'incloure el comprovant de la signatura?
			boolean returnReport = true;
			//la resposta ha d'incloure el document signat?
			boolean returnSignedDocument = true; 
			//la resposta ha d'incloure l'identificador del document signat?
			boolean returnSignedDocumentId = true;

			//llistat dels hashes originals, i signats
			OriginalAndEncryptedHashType[]orginalAndEncriptedHashList = new OriginalAndEncryptedHashType[1];  
			OriginalAndEncryptedHashType origAndEncryptedHash = OriginalAndEncryptedHashType.Factory.newInstance();
			//hash
			origAndEncryptedHash.setHash((byte[])hashes.get(0));
			//hash encriptat
			origAndEncryptedHash.setEncryptedHash(encryptedHash);
			orginalAndEncriptedHashList[0] = origAndEncryptedHash;

			//petició de completat de signatura
			CompleteSignatureRQST[] completeSignRequestList = new CompleteSignatureRQST[1]; 
			CompleteSignatureRQST completeSignRqst = PSARequestFactory._().createCompleteSignatureAtManager(
					actOid, 
					orginalAndEncriptedHashList, 
					returnReport, 
					returnSignedDocument, 
					returnSignedDocumentId);
			completeSignRequestList[0] = completeSignRqst;

			//petició de completat de multisignatura
			CompleteSignatureDocument multiRequest3 = PSARequestFactory._().createMultiCompleteSignatureAtManager(locale, completeSignRequestList);

			//resposta
			CompleteSignatureResponseDocument completeSignatureDoc = signatureServiceStub.completeSignature(multiRequest3);
			MultiCompleteSignatureRSPNS multiResponse3 = completeSignatureDoc.getCompleteSignatureResponse().getMultiCompleteSignatureRSPNS();

			//pintem la/es resposta/es
			CompleteSignatureResponseUtils.pintaMultiCompleteSignatureRespostes(multiResponse3);

			//obtenció del/s document/s signat/s
			CompleteSignatureResponseUtils.saveSignedDocs(multiResponse3);


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

	}	

}
