/*
 * 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.sdm.ui.ws.rs.config;

import com.scytl.products.ov.commons.verify.CryptolibPayloadSigningCertificateValidator;
import com.scytl.products.ov.commons.verify.PayloadSigningCertificateValidator;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;

import com.scytl.cryptolib.api.asymmetric.AsymmetricServiceAPI;
import com.scytl.cryptolib.api.elgamal.ElGamalServiceAPI;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.scytl.keystore.ScytlKeyStoreServiceAPI;
import com.scytl.cryptolib.api.services.ServiceFactory;
import com.scytl.cryptolib.asymmetric.service.AsymmetricServiceFactoryHelper;
import com.scytl.cryptolib.elgamal.service.ElGamalServiceFactoryHelper;
import com.scytl.cryptolib.scytl.keystore.service.ScytlKeyStoreServiceFactoryHelper;
import com.scytl.products.ov.commons.dto.ElGamalComputationsValuesCodec;
import com.scytl.products.ov.commons.dto.ElGamalComputationsValuesCodecImpl;
import com.scytl.products.ov.commons.path.AbsolutePathResolver;
import com.scytl.products.ov.commons.path.PathResolver;
import com.scytl.products.ov.commons.path.PrefixPathResolver;
import com.scytl.products.ov.commons.sign.CryptolibPayloadSigner;
import com.scytl.products.ov.commons.sign.MetadataFileSigner;
import com.scytl.products.ov.commons.sign.PayloadSigner;
import com.scytl.products.ov.commons.verify.CryptolibPayloadVerifier;
import com.scytl.products.ov.commons.verify.MetadataFileVerifier;
import com.scytl.products.ov.commons.verify.PayloadVerifier;
import com.scytl.products.ov.readers.ConfigurationInputReader;
import com.scytl.products.ov.sdm.application.service.PlatformRootCAService;
import com.scytl.products.ov.sdm.infrastructure.DatabaseManager;
import com.scytl.products.ov.sdm.infrastructure.DatabaseManagerFactory;

/**
 * MVC Configuration
 */
@Configuration
public class SecureDataManagerConfig {

    @Autowired
    private Environment env;

    @Autowired
    private DatabaseManagerFactory databaseManagerFactory;

    @Value("${user.home}")
    private String prefix;

    @Value("${database.path}")
    private String databaseURL;

    @Bean
    @Primary
    public PathResolver getPrefixPathResolver() {
        return new PrefixPathResolver(prefix);
    }

    @Bean
    @Qualifier("absolutePath")
    public PathResolver getAbsolutePathResolver() {
        return new AbsolutePathResolver();
    }

    @Bean
    public MetadataFileVerifier getMetadataFileVerifier(final AsymmetricServiceAPI asymmetricServiceAPI) {
        return new MetadataFileVerifier(asymmetricServiceAPI);
    }

    @Bean
    public MetadataFileSigner getMetadataFileSigner(final AsymmetricServiceAPI asymmetricServiceAPI) {
        return new MetadataFileSigner(asymmetricServiceAPI);
    }

    @Bean
    public ServiceFactory<AsymmetricServiceAPI> asymmetricServiceAPIServiceFactory(
            final GenericObjectPoolConfig genericObjectPoolConfig) {
        return AsymmetricServiceFactoryHelper.getFactoryOfThreadSafeServices(genericObjectPoolConfig);
    }

    @Bean
    public AsymmetricServiceAPI asymmetricServiceAPI(
            final ServiceFactory<AsymmetricServiceAPI> asymmetricServiceAPIServiceFactory)
            throws GeneralCryptoLibException {
        return asymmetricServiceAPIServiceFactory.create();
    }
    
    @Bean
    public ServiceFactory<ElGamalServiceAPI> elGamalServiceAPIServiceFactory(
            final GenericObjectPoolConfig genericObjectPoolConfig) {
        return ElGamalServiceFactoryHelper.getFactoryOfThreadSafeServices(genericObjectPoolConfig);
    }

    @Bean
    public ElGamalServiceAPI elGamalServiceAPI(
            final ServiceFactory<ElGamalServiceAPI> elGamalServiceAPIServiceFactory)
            throws GeneralCryptoLibException {
        return elGamalServiceAPIServiceFactory.create();
    }
    
    @Bean
    public ServiceFactory<ScytlKeyStoreServiceAPI> scytlKeyStoreServiceAPIServiceFactory(
            final GenericObjectPoolConfig genericObjectPoolConfig) {
        return ScytlKeyStoreServiceFactoryHelper.getFactoryOfThreadSafeServices(genericObjectPoolConfig);
    }

    @Bean
    public ScytlKeyStoreServiceAPI scytlKeyStoreServiceAPI(
            final ServiceFactory<ScytlKeyStoreServiceAPI> scytlKeyStoreServiceAPIServiceFactory)
            throws GeneralCryptoLibException {
        return scytlKeyStoreServiceAPIServiceFactory.create();
    }
    
    @Bean
    public ElGamalComputationsValuesCodec elGamalComputationsValuesCodec() {
        return ElGamalComputationsValuesCodecImpl.getInstance();
    }

    @Bean
    public GenericObjectPoolConfig genericObjectPoolConfig() {

        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxTotal(Integer.valueOf(env.getProperty("services.cryptolib.pool.size")));
        genericObjectPoolConfig.setMaxIdle(Integer.valueOf(env.getProperty("services.cryptolib.timeout")));

        return genericObjectPoolConfig;
    }

    @Bean(initMethod = "createDatabase")
    public DatabaseManager databaseManager() {
        return databaseManagerFactory.newDatabaseManager(databaseURL);
    }
    
    @Bean
    public ConfigurationInputReader configurationInputReader() {
        return new ConfigurationInputReader();
    }

    @Bean
    PlatformRootCAService platformRootCAService(PathResolver pathResolver) {
        return new PlatformRootCAService(pathResolver);
    }

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

    @Bean
    PayloadSigningCertificateValidator certificateValidator() {
        return new CryptolibPayloadSigningCertificateValidator();
    }

    @Bean
    PayloadVerifier payloadVerifier(AsymmetricServiceAPI asymmetricService,
            PayloadSigningCertificateValidator certificateValidator) {
        return new CryptolibPayloadVerifier(asymmetricService, certificateValidator);
    }
}
