package net.catcert.psa.services;

import java.security.Security;
import java.util.Properties;

import net.catcert.psa.util.PWCBHandler;

import org.apache.axis2.AxisFault;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.neethi.Policy;
import org.apache.rampart.policy.model.CryptoConfig;
import org.apache.rampart.policy.model.RampartConfig;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.sadiel.catcert.psa.ws.client.QueryServiceStub;
import com.sadiel.catcert.psa.ws.client.SignatureServiceStub;
import com.sadiel.catcert.psa.ws.client.UtilServiceStub;

/**
 * 
 * @author suport tècnic CATCert
 *
 */
public class PsaServices{

	// constants for crypto provider
	private String provider_merlin 		= "org.apache.ws.security.components.crypto.Merlin";
	private String keystore_type 		= "org.apache.ws.security.crypto.merlin.keystore.type";
	private String keystore_pwd  		= "org.apache.ws.security.crypto.merlin.keystore.password";
	private String keystore_alias		= "org.apache.ws.security.crypto.merlin.keystore.alias";
	private String keystore_file  		= "org.apache.ws.security.crypto.merlin.file";
	private String engage_module_rampart = "rampart";

	private String uri_psa_signature_service = "http://preproduccio.psa.cat/engineWS/signature/service";
	private String uri_psa_query_service = "http://preproduccio.psa.cat/engineWS/query/service";
	private String uri_psa_util_service = "http://preproduccio.psa.cat/engineWS/util/service";

	private static PsaServices instance = null;
	
	protected PsaServices(){
		// add bouncycastle provider (wss4j requires bc provider in order to recognize some algorithms)
		if(Security.getProvider("BC")==null){
			Security.addProvider(new BouncyCastleProvider());
		}
	}

	public static PsaServices getInstance() {
		if(instance == null) {
			instance = new PsaServices();
		}
		return instance;
	}

	/**
	 * Get signatureSerivceStub to invoke psa signature service
	 * @return
	 * @throws Exception
	 */
	public SignatureServiceStub getSignatureServiceStub() throws Exception {

		// create context and add rampart module
		ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem ("resource/module/rampart-1.4.mar", null);

		// create the stub with endpoint uri
		SignatureServiceStub stub = new SignatureServiceStub(ctx,uri_psa_signature_service); 
		ServiceClient client = stub._getServiceClient();

		// configure client
		configurePolicy(client);

		// returns the stub ready to invoke
		return stub;
	}
	
	/**
	 * Get queryServiceStub to invoke psa query service
	 * @return
	 * @throws Exception
	 */
	public QueryServiceStub getQueryServiceStub() throws Exception {

		// create context and add rampart module
		ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem ("resource/module/rampart-1.4.mar", null);

		// create the stub with endpoint uri
		QueryServiceStub stub = new QueryServiceStub(ctx,uri_psa_query_service); 
		ServiceClient client = stub._getServiceClient();

		// configure client
		configurePolicy(client);

		// returns the stub ready to invoke
		return stub;
	}

	
	/**
	 * Get utilSerivceStub to invoke psa util service
	 * @return
	 * @throws Exception
	 */
	public UtilServiceStub getUtilServiceStub() throws Exception {

		// create context and add rampart module
		ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem ("resource/module/rampart-1.4.mar", null);

		// create the stub with endpoint uri
		UtilServiceStub stub = new UtilServiceStub(ctx,uri_psa_util_service); 
		ServiceClient client = stub._getServiceClient();

		// configure client
		configurePolicy(client);

		// returns the stub ready to invoke
		return stub;
	}


	/**
	 * Engage rampart module and adds wss policy
	 * @param sc
	 * @throws AxisFault
	 */
	private void configurePolicy(ServiceClient sc) throws AxisFault{

		// engage rampart
		sc.engageModule(engage_module_rampart);
		// create wss policy
		Policy rampartConfig = getRampartConfig();
		// attach policy to the client stub
		sc.getAxisService().getPolicySubject().attachPolicy(rampartConfig); 

	}

	/**
	 * Generate rampartConfig dinamycally
	 * @return
	 */
	private Policy getRampartConfig() { 

		// rampart config
		RampartConfig rampartConfig = new RampartConfig();
		rampartConfig.setUser("oid.2.5.4.5=87654321x, cn=ajuntament d'exemple, ou=ajuntament d'exemple, ou=serveis publics de certificacio cda-1, ou=vegeu https://www.catcert.net/vercda-1 c(03), o=generalitat de catalunya, c=es");
		rampartConfig.setEncryptionUser("cda_xifra_pre");
		rampartConfig.setPwCbClass(PWCBHandler.class.getName());

		// crypto config
		CryptoConfig sigCrypto = new CryptoConfig(); 
		sigCrypto.setProvider(provider_merlin); 
		Properties props = new Properties(); 
		props.setProperty(keystore_type, "jks"); 
		props.setProperty(keystore_file, "resource/trustedcerts.jks"); 
		props.setProperty(keystore_pwd, "111111");
		props.setProperty(keystore_alias, "oid.2.5.4.5=87654321x, cn=ajuntament d'exemple, ou=ajuntament d'exemple, ou=serveis publics de certificacio cda-1, ou=vegeu https://www.catcert.net/vercda-1 c(03), o=generalitat de catalunya, c=es");
		sigCrypto.setProp(props);

		// set the config for signature, encryption and decryption
		rampartConfig.setSigCryptoConfig(sigCrypto);
		rampartConfig.setDecCryptoConfig(sigCrypto); 
		rampartConfig.setEncrCryptoConfig(sigCrypto); 
		Policy policy = new Policy(); 
		policy.addAssertion(rampartConfig); 
		return policy; 
	}


}
