package be.ehealth.technicalconnector.service.seals;

import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;

import be.ehealth.technicalconnector.service.ServiceFactory;
import be.ehealth.technicalconnector.service.sts.security.Credential;
import be.ehealth.technicalconnector.service.sts.security.impl.KeyStoreCredential;
import be.fgov.ehealth.seals.core.v1.ChoiceDecodedDataErrorType;
import be.fgov.ehealth.seals.core.v1.ChoiceEncodedDataErrorType;
import be.fgov.ehealth.seals.core.v1.EncodedDataType;
import be.fgov.ehealth.seals.core.v1.OriginalDataType;
import be.fgov.ehealth.seals.protocol.v1.DecodeRequest;
import be.fgov.ehealth.seals.protocol.v1.DecodeResponse;
import be.fgov.ehealth.seals.protocol.v1.EncodeRequest;
import be.fgov.ehealth.seals.protocol.v1.EncodeResponse;
import be.fgov.ehealth.technicalconnector.tests.junit.rule.SessionRule;

/**
 * Codage Service Integration Tests This set of tests shows the use of the Codage Service through the use of the Technical Connector
 * 
 * @author EHP
 */
public class SealsServiceIntegrationTest {

    /** The decoded text, used in encode (input), checked in decode (verify against returned decoded text) */
    private String plainText = "Private text to be encoded";

    @ClassRule
    public static SessionRule rule = SessionRule.withInactiveSession()
                                                .build();

    /**
     * Test the encode operation of the Codage Service through the use of the Technical Connector
     * 
     * The encode methods needs the following parameters: - application name - ID(s) of the message(s) to encode - message(s) to encode -
     * randomize? (boolean)
     */
    @Test
    public void testEncode() throws Exception {
        String id = "_1";
        EncodeResponse response = invokeEncode(id);

        /*
         * Verify the response
         */
        Assert.assertNotNull(response.getId());
        ChoiceEncodedDataErrorType encodedData = response.getResponses()
                                                         .get(0);
        Assert.assertEquals(id, encodedData.getEncodedData()
                                           .getId());
        Assert.assertNotNull(encodedData.getEncodedData()
                                        .getValue());
        Assert.assertNull(encodedData.getError());

    }

    private EncodeResponse invokeEncode(String id) throws Exception {
        /*
         * Set the values to use in this test
         */
        // the application name (retrieved from property file)
        String applicationName = rule.getSessionProperty("test.applicationname");

        // the message to encode (stored in class variable for use with the decode)
        String message = plainText;
        // randomize the returned values?
        String algorithmCode = "F";

        /*
         * Create request
         */
        // create encode request
        EncodeRequest request = new EncodeRequest();
        // set application name
        request.setApplicationName(applicationName);
        // the request expects a list of original data to be encoded.
        // in this example we will provide a list with 1 item to be encoded
        List<OriginalDataType> listOriginalData = new ArrayList<OriginalDataType>();
        // create the item to be encoded
        OriginalDataType originalData = new OriginalDataType();
        // set id
        originalData.setId(id);
        // set the actual text to be encoded
        originalData.setInputData(message);
        // set if the data has to be randomized or not
        originalData.setAlgorithmCode(algorithmCode);
        // add the data to the list of data to be encoded
        listOriginalData.add(originalData);
        // add the list of data to the encode request
        request.getOriginalDatas()
               .addAll(listOriginalData);

        /*
         * Invoke the technical connector framework's Codage Service's encode operation
         */
        // get the X509 certificate and private key from the test keystore. (retrieved from property file)
        Credential credential = new KeyStoreCredential(rule.getSessionProperty("test.seals.location"), rule.getSessionProperty("test.seals.alias"), rule.getSessionProperty("test.seals.password"));


        // invoke technical connector
        SealsService service = ServiceFactory.getSealsService();
        return service.encode(credential.getCertificate(), credential.getPrivateKey(), request);
    }

    /**
     * Test the decode operation of the Codage Service through the use of the Technical Connector
     * 
     * The decode methods needs the following parameters: - application name - ID(s) of the message(s) to decode - message(s) to decode -
     * randomize? (boolean)
     * 
     * @author EHP
     */
    @Test
    public void testDecode() throws Exception {
        /*
         * Set the values to use in this test
         */
        // The application name (retrieved from property file)
        String applicationName = rule.getSessionProperty("test.applicationname");
        // the message ID (1 per message)
        String id = "_2";
        // the message to decode (retrieved from class variable, filled in previous test)
        byte[] message = invokeEncode(id).getResponses()
                                         .get(0)
                                         .getEncodedData()
                                         .getValue();

        /*
         * Create request
         */
        // create decode request
        DecodeRequest request = new DecodeRequest();
        // set application name
        request.setApplicationName(applicationName);
        // the request expects a list of encoded data to be decoded.
        // in this example we will provide a list with 1 item to be decoded
        List<EncodedDataType> listEncodedData = new ArrayList<EncodedDataType>();
        // create the item to be decoded
        EncodedDataType encodedData = new EncodedDataType();
        // set id
        encodedData.setId(id);
        // set the encoded text to be decoded
        encodedData.setValue(message);
        // add the encoded data to the list of data to be decoded
        listEncodedData.add(encodedData);
        // add the list of data to the decode request
        request.getEncodedDatas()
               .addAll(listEncodedData);

        /*
         * Invoke the technical connector framework's Codage Service's decode operation
         */
        DecodeResponse response = null;
        // get the X509 certificate and private key from the test keystore. (retrieved from property file)
        Credential credential = new KeyStoreCredential(rule.getSessionProperty("test.seals.location"), rule.getSessionProperty("test.seals.alias"), rule.getSessionProperty("test.seals.password"));

        // invoke technical connector
        SealsService service = ServiceFactory.getSealsService();
        response = service.decode(credential.getCertificate(), credential.getPrivateKey(), request);

        /*
         * Verify the response
         */
        // check if a ticket number is present
        Assert.assertNotNull(response.getId());
        // as the request expects a list of data to be decoded, the response gives a list of decoded data back
        // the example requests the decoding of 1 entry in the list, so we just get the first response out.
        ChoiceDecodedDataErrorType decodedData = response.getResponses()
                                                         .get(0);
        // check if the ID is the same as the one that has been entered in the request
        Assert.assertEquals(id, decodedData.getDecodedData()
                                           .getId());
        // check if the data has been decoded correct
        Assert.assertEquals(plainText, decodedData.getDecodedData()
                                                  .getOutputData());
        // check if there is no error present
        Assert.assertNull(decodedData.getError());
    }
}
