/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.ov.mixing.core;

import static org.junit.Assert.assertTrue;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import com.scytl.ov.mixing.core.elgamal.ElGamalMixAndProveJob;
import com.scytl.ov.mixing.core.elgamal.ElGamalMixJob;
import com.scytl.ov.mixing.core.elgamal.ElGamalMixerSPI;

public class MixerImplTest {

    @Rule
    public ExpectedException expectedEx = ExpectedException.none();

    @Test
    public void whenTryToCreateMixerImplWithoutAddingSpiThenException()
            throws AlgorithmNotFoundException, MixingException {

        expectedEx.expect(IllegalStateException.class);
        expectedEx.expectMessage("Tried to create a Mixer without adding any MixerSPI implementations");

        new MixerImpl.MixerImplBuilder(null).build();
    }

    @Test
    public void whenBuildWithOneSpiThenOk() throws AlgorithmNotFoundException, MixingException {

        new MixerImpl.MixerImplBuilder(null).withSPI(ElGamalMixerSPI.getInstance()).build();
    }

    @Test
    public void whenBuildWithTwoSpisThenOk() throws AlgorithmNotFoundException, MixingException {

        new MixerImpl.MixerImplBuilder(null).withSPI(ElGamalMixerSPI.getInstance()).withSPI(SomeOtherImpl.getInstance())
            .build();
    }

    @Test
    public void whenCreateMixJobWithNullAlgorithmThenException() throws AlgorithmNotFoundException, MixingException {

        String unexpectedAlgorithm = null;

        expectedEx.expect(NullPointerException.class);
        expectedEx.expectMessage("The algorithm was null");

        MixerImpl mixerImpl = new MixerImpl.MixerImplBuilder(null).withSPI(ElGamalMixerSPI.getInstance()).build();

        MixJob mixJob = mixerImpl.newMixJob(unexpectedAlgorithm);

        assertTrue(mixJob instanceof ElGamalMixJob);
    }

    @Test
    public void whenCreateMixJobWithNotSupportedAlgorithmThenException()
            throws AlgorithmNotFoundException, MixingException {

        String unexpectedAlgorithm = "XXXXXX";

        expectedEx.expect(AlgorithmNotFoundException.class);
        expectedEx.expectMessage("The specified algorithm is not supported: " + unexpectedAlgorithm);

        MixerImpl mixerImpl = new MixerImpl.MixerImplBuilder(null).withSPI(ElGamalMixerSPI.getInstance()).build();

        MixJob mixJob = mixerImpl.newMixJob(unexpectedAlgorithm);

        assertTrue(mixJob instanceof ElGamalMixJob);
    }

    @Test
    public void whenCreateMixAndProveJobWithNotSupportedAlgorithmThenException()
            throws AlgorithmNotFoundException, MixingException {

        String unexpectedAlgorithm = "XXXXXX";

        expectedEx.expect(AlgorithmNotFoundException.class);
        expectedEx.expectMessage("The specified algorithm is not supported: " + unexpectedAlgorithm);

        MixerImpl mixerImpl_with_ElGamalMixerSPI_added =
            new MixerImpl.MixerImplBuilder(null).withSPI(ElGamalMixerSPI.getInstance()).build();

        MixJob mixJob = mixerImpl_with_ElGamalMixerSPI_added.newMixAndProveJob(unexpectedAlgorithm);

        assertTrue(mixJob instanceof ElGamalMixJob);
    }

    @Test
    public void whenCreateMixJobWithSupportedAlgorithmThenOk() throws AlgorithmNotFoundException, MixingException {

        MixerImpl mixerImpl_with_ElGamalMixerSPI_added =
            new MixerImpl.MixerImplBuilder(null).withSPI(ElGamalMixerSPI.getInstance()).build();

        MixJob mixJob = mixerImpl_with_ElGamalMixerSPI_added.newMixJob(ElGamalMixerSPI.getInstance().algorithm());

        assertTrue(mixJob instanceof ElGamalMixJob);
    }

    @Test
    public void whenCreateMixAndProveJobWithSupportedAlgorithmThenOk()
            throws AlgorithmNotFoundException, MixingException {

        MixerImpl mixerImpl_with_ElGamalMixerSPI_added =
            new MixerImpl.MixerImplBuilder(null).withSPI(ElGamalMixerSPI.getInstance()).build();

        MixJob mixJob =
            mixerImpl_with_ElGamalMixerSPI_added.newMixAndProveJob(ElGamalMixerSPI.getInstance().algorithm());

        assertTrue(mixJob instanceof ElGamalMixAndProveJob);
    }

}

class SomeOtherImpl implements MixerSPI {

    private static final SomeOtherImpl INSTANCE = new SomeOtherImpl();

    private SomeOtherImpl() {
    }

    public static SomeOtherImpl getInstance() {
        return INSTANCE;
    }

    @Override
    public String algorithm() {
        return "SomeAlgorithm";
    }

    @Override
    public MixAndProveJob newMixAndProveJob(MixerContext context)
            throws UnsupportedVerificationException, MixingException {
        return null;
    }

    @Override
    public MixJob newMixJob(MixerContext context) throws MixingException {
        return null;
    }

    @Override
    public VerifyJob newVerifyJob(MixerContext context) throws UnsupportedVerificationException, MixingException {
        return null;
    }

    @Override
    public void shutdown() {

    }
}
