/*
 * 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.products.ov.mixnet.spring;

import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import com.scytl.cryptolib.api.elgamal.ElGamalServiceAPI;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.primitives.PrimitivesServiceAPI;
import com.scytl.cryptolib.api.proofs.ProofsServiceAPI;
import com.scytl.cryptolib.elgamal.service.ElGamalService;
import com.scytl.cryptolib.primitives.service.PrimitivesService;
import com.scytl.cryptolib.proofs.service.ProofsService;
import com.scytl.products.oscore.logging.api.factory.SecureLoggingFactory;
import com.scytl.products.oscore.logging.api.formatter.MessageFormatter;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.oscore.logging.core.factory.SecureLoggingFactoryLog4j;
import com.scytl.products.oscore.logging.core.formatter.SplunkFormatter;
import com.scytl.products.oscore.logging.core.provider.TransactionInfoProvider;
import com.scytl.products.ov.mixnet.BGMixnetLoadBalancer;
import com.scytl.products.ov.mixnet.BGVerifier;
import com.scytl.products.ov.mixnet.BallotDecryptionService;
import com.scytl.products.ov.mixnet.MixnetLoadBalancer;
import com.scytl.products.ov.mixnet.SimpleBallotDecryptionService;
import com.scytl.products.ov.mixnet.api.MixingService;
import com.scytl.products.ov.mixnet.api.MixingServiceAPI;
import com.scytl.products.ov.mixnet.api.VerifyingService;
import com.scytl.products.ov.mixnet.api.VerifyingServiceAPI;
import com.scytl.products.ov.mixnet.commons.constants.Constants;
import com.scytl.products.ov.mixnet.commons.validation.EncryptedBallotsDuplicationValidator;
import com.scytl.products.ov.mixnet.mvc.MixingController;
import com.scytl.products.ov.mixnet.mvc.VerifyingController;

@Configuration
public class MixerSpringConfig {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    @Bean
    public static MixingSecureLoggerConfig mixingSecureLoggerConfig() {
        return new MixingSecureLoggerConfig();
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public TransactionInfoProvider transactionInfoProvider() {
        return new TransactionInfoProvider();
    }

    @Bean
    public MixingController mixingController(final MixingServiceAPI mixingService,
            final TransactionInfoProvider transactionInfoProvider) {
        return new MixingController(mixingService, transactionInfoProvider);
    }

    @Bean
    public VerifyingController verifyingController(final VerifyingServiceAPI verifyingServiceAPI) {
        return new VerifyingController(verifyingServiceAPI);
    }

    @Bean
    public MixingServiceAPI mixingServiceAPI(final MixnetLoadBalancer mixnetLoadBalancer) {
        return new MixingService(mixnetLoadBalancer);
    }

    @Bean
    public VerifyingServiceAPI verifyingServiceAPI(final BGVerifier verifier) {
        return new VerifyingService(verifier);
    }

    @Bean
    public BGVerifier verifier(SecureLoggingWriter loggingWriter) {
        return new BGVerifier(loggingWriter);
    }

    @Bean
    public SecureLoggingFactory secureLoggingFactory(TransactionInfoProvider transactionInfoProvider) {
        MessageFormatter formatter = new SplunkFormatter("OV", "MIX", transactionInfoProvider);
        return new SecureLoggingFactoryLog4j(formatter);
    }

    @Bean
    public SecureLoggingWriter secureLoggingWriter(final SecureLoggingFactory secureLoggingFactory) {
        return secureLoggingFactory.getLogger(Constants.SECURE_LOGGER_NAME);
    }

    @Bean
    public PrimitivesService primitivesService() throws GeneralCryptoLibException {
        return new PrimitivesService();
    }

    @Bean
    public ElGamalServiceAPI elGamalService() throws GeneralCryptoLibException {
        return new ElGamalService();
    }

    @Bean
    public ProofsServiceAPI proofsService() throws GeneralCryptoLibException {
        return new ProofsService();
    }

    @Bean
    public BallotDecryptionService ballotDecryptionService(PrimitivesServiceAPI primitivesService,
            ElGamalServiceAPI elGamalService,
            ProofsServiceAPI proofsService,
            TransactionInfoProvider transactionInfoProvider,
            SecureLoggingWriter loggingWriter) throws GeneralCryptoLibException {
        return new SimpleBallotDecryptionService(transactionInfoProvider, primitivesService, 
            elGamalService, proofsService, loggingWriter);
    }

    @Bean
    public MixnetLoadBalancer balancer(PrimitivesServiceAPI primitivesService,
            BallotDecryptionService ballotDecryptionService,
            TransactionInfoProvider transactionInfoProvider,
            SecureLoggingWriter loggingWriter) throws GeneralCryptoLibException {
        return new BGMixnetLoadBalancer.Builder()
            .setPrimitivesService(primitivesService)
            .setBallotDecryptionService(ballotDecryptionService)
            .setTransactionInfoProvider(transactionInfoProvider)
            .setLoggingWriter(loggingWriter)
            .addBallotsValidator(new EncryptedBallotsDuplicationValidator())
            .build();
    }
}
