/*
 * 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.channel.cc.choicecodes.verification.spring;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.scytl.cryptolib.api.asymmetric.AsymmetricServiceAPI;
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.asymmetric.service.AsymmetricServiceFactoryHelper;
import com.scytl.cryptolib.mathematical.groups.activity.GroupElementsCompressor;
import com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement;
import com.scytl.cryptolib.primitives.service.PrimitivesServiceFactoryHelper;
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.channel.cc.commons.services.ChoiceCodesKeyRepository;
import com.scytl.products.ov.channel.cc.commons.services.ChoiceCodesKeyRepositoryImpl;
import com.scytl.products.ov.channel.cc.commons.services.compute.KeyDerivationService;
import com.scytl.products.ov.channel.cc.commons.slogger.ServiceTransactionInfoProvider;
import com.scytl.products.ov.channel.cc.commons.util.FingerprintGenerator;
import com.scytl.products.ov.commons.sign.CryptolibPayloadSigner;
import com.scytl.products.ov.commons.sign.PayloadSigner;

@Configuration
public class ServiceConfig {

    private static final String MAX_ELEMENTS_CRYPTO_POOL = "asymmetric.max.elements.crypto.pool";

    @Bean
    public KeyDerivationService keyDerivationService() {
        return new KeyDerivationService();
    }

    @Bean
    public ChoiceCodesKeyRepository choiceCodesKeyRepository() {
        return new ChoiceCodesKeyRepositoryImpl();
    }

    @Bean
    public GroupElementsCompressor<ZpGroupElement> groupElementsCompressor() {
        return new GroupElementsCompressor<>();
    }

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

    @Bean
    public ServiceTransactionInfoProvider getServiceTransactionInfoProvider() {
        return new ServiceTransactionInfoProvider();
    }

    @Bean
    public MessageFormatter messageFormatter(final TransactionInfoProvider transactionInfoProvider) {
        return new SplunkFormatter("OV", "CCGEN", transactionInfoProvider);
    }

    @Bean
    public SecureLoggingFactory secureLoggingFactory(final MessageFormatter messageFormatter) {
        return new SecureLoggingFactoryLog4j(messageFormatter);
    }

    @Bean
    public SecureLoggingWriter auditLoggingWriter(final SecureLoggingFactory secureLoggingFactory) {
        return secureLoggingFactory.getLogger("AuditLogger");
    }

    @Bean
    public FingerprintGenerator getFingerprintGenerator(PrimitivesServiceAPI primitivesService) {
        return new FingerprintGenerator(primitivesService);
    }

    @Bean
    public AsymmetricServiceAPI asymmetricService() {
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setMaxTotal(Integer.parseInt(System.getProperty(MAX_ELEMENTS_CRYPTO_POOL, "50")));
        try {
            return AsymmetricServiceFactoryHelper.getFactoryOfThreadSafeServices(config).create();
        } catch (GeneralCryptoLibException e) {
            throw new IllegalStateException("Exception while trying to create AsymmetricService", e);
        }
    }

    @Bean
    public PrimitivesServiceAPI primitivesService() {
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setMaxTotal(Integer.parseInt(System.getProperty(MAX_ELEMENTS_CRYPTO_POOL, "50")));
        try {
            return PrimitivesServiceFactoryHelper.getFactoryOfThreadSafeServices(config).create();
        } catch (GeneralCryptoLibException e) {
            throw new IllegalStateException("Exception while trying to create PrimitivesService", e);
        }
    }

    @Bean
    public PayloadSigner payloadSigner(@Autowired AsymmetricServiceAPI asymmetricService) {
        return new CryptolibPayloadSigner(asymmetricService);
    }
}
