package meerkat.bulletinboard;

import com.google.protobuf.ByteString;
import meerkat.crypto.concrete.ECDSASignature;
import meerkat.crypto.concrete.SHA256Digest;
import meerkat.protobuf.BulletinBoardApi.*;
import meerkat.util.BulletinBoardMessageGenerator;
import meerkat.util.BulletinBoardUtils;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Random;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;

/**
 * Created by Arbel Deutsch Peled on 16-Jun-16.
 */
public class BulletinBoardDigestTest {

    private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12";
    private static String KEYFILE_EXAMPLE3 = "/certs/enduser-certs/user3-key-with-password-shh.p12";

    private static String KEYFILE_PASSWORD1 = "secret";
    private static String KEYFILE_PASSWORD3 = "shh";

    private GenericBulletinBoardSignature[] signers;
    private ByteString[] signerIDs;

    @Before
    public void init() {

        signers = new GenericBulletinBoardSignature[2];
        signerIDs = new ByteString[signers.length];
        signers[0] = new GenericBulletinBoardSignature(new ECDSASignature());
        signers[1] = new GenericBulletinBoardSignature(new ECDSASignature());

        InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
        char[] password = KEYFILE_PASSWORD1.toCharArray();

        KeyStore.Builder keyStoreBuilder = null;
        try {
            keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password);

            signers[0].loadSigningCertificate(keyStoreBuilder);

            keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3);
            password = KEYFILE_PASSWORD3.toCharArray();

            keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password);
            signers[1].loadSigningCertificate(keyStoreBuilder);

            for (int i = 0 ; i < signers.length ; i++) {
                signerIDs[i] = signers[i].getSignerID();
            }

        } catch (IOException e) {
            System.err.println("Failed reading from signature file " + e.getMessage());
            fail("Failed reading from signature file " + e.getMessage());
        } catch (CertificateException e) {
            System.err.println("Failed reading certificate " + e.getMessage());
            fail("Failed reading certificate " + e.getMessage());
        } catch (KeyStoreException e) {
            System.err.println("Failed reading keystore " + e.getMessage());
            fail("Failed reading keystore " + e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            System.err.println("Couldn't find signing algorithm " + e.getMessage());
            fail("Couldn't find signing algorithm " + e.getMessage());
        } catch (UnrecoverableKeyException e) {
            System.err.println("Couldn't find signing key " + e.getMessage());
            fail("Couldn't find signing key " + e.getMessage());
        }

    }

    @Test
    public void testBatchDigest() throws SignatureException {

        final int MESSAGE_SIZE = 100;
        final int CHUNK_SIZE = 10;
        final int TAG_NUM = 10;

        BulletinBoardMessageGenerator generator = new BulletinBoardMessageGenerator(new Random(0));

        BulletinBoardMessage completeMessage = generator.generateRandomMessage(signers, MESSAGE_SIZE, TAG_NUM);

        BulletinBoardMessage stub = BulletinBoardUtils.makeStub(completeMessage);
        List<BatchChunk> batchChunks = BulletinBoardUtils.breakToBatch(completeMessage, CHUNK_SIZE);

        BulletinBoardDigest digest = new GenericBulletinBoardDigest(new SHA256Digest());

        digest.update(completeMessage);
        MessageID id1 = digest.digestAsMessageID();

        digest.update(stub);
        for (BatchChunk batchChunk : batchChunks){
            digest.update(batchChunk.getData().toByteArray());
        }

        MessageID id2 = digest.digestAsMessageID();

        assertThat("Digests not equal!", id1.getID().equals(id2.getID()));

    }

}
