/*
 * 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.cryptolib.scytl.keystore.service;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore.PasswordProtection;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.scytl.keystore.ScytlKeyStoreServiceAPI;
import com.scytl.cryptolib.commons.constants.Constants;
import com.scytl.cryptolib.commons.utils.validations.Validate;
import com.scytl.cryptolib.scytl.keystore.configuration.ScytlKeyStoreP12PolicyFromProperties;
import com.scytl.cryptolib.scytl.keystore.configuration.ScytlKeyStorePolicy;
import com.scytl.cryptolib.scytl.keystore.cryptoapi.CryptoAPIScytlKeyStore;
import com.scytl.cryptolib.scytl.keystore.factory.CryptoScytlKeyStoreWithPBKDF;
import com.scytl.cryptolib.scytl.keystore.factory.ScytlKeyStoreWithPBKDFGenerator;
import com.scytl.cryptolib.scytl.keystore.factory.ScytlKeyStoreWithPBKDFGeneratorFactory;

/**
 * Provides operations with stores.
 */
public class ScytlKeyStoreService implements ScytlKeyStoreServiceAPI {

    private final ScytlKeyStoreWithPBKDFGenerator _keyStoreWithPBKDFGenerator;

    /**
     * Default constructor which initializes all properties to default values,
     * which are read from the properties specified by
     * {@link Constants#CRYPTOLIB_POLICY_PROPERTIES_FILE_PATH}.
     * 
     * @throws GeneralCryptoLibException
     *             if the default properties are invalid.
     */
    public ScytlKeyStoreService() throws GeneralCryptoLibException {

        this(Constants.CRYPTOLIB_POLICY_PROPERTIES_FILE_PATH);
    }

    /**
     * Constructor which initializes its internal state using the properties
     * file located at the specified path.
     * 
     * @param path
     *            the path of the properties file to be used to configure the
     *            service.
     * @throws GeneralCryptoLibException
     *             if the path is invalid or the properties are invalid.
     */
    public ScytlKeyStoreService(final String path)
            throws GeneralCryptoLibException {

        Validate.notNullOrBlank(path, "Properties file path");

        ScytlKeyStorePolicy storePolicy =
            new ScytlKeyStoreP12PolicyFromProperties(path);

        ScytlKeyStoreWithPBKDFGeneratorFactory keyStoreWithPBKDFGeneratorFactory =
            new ScytlKeyStoreWithPBKDFGeneratorFactory(storePolicy);
        _keyStoreWithPBKDFGenerator =
            keyStoreWithPBKDFGeneratorFactory.create();
    }

    @Override
    public CryptoAPIScytlKeyStore createKeyStore() {

        return _keyStoreWithPBKDFGenerator.create();
    }

    @Override
    public CryptoAPIScytlKeyStore loadKeyStore(final InputStream in,
            final PasswordProtection password)
            throws GeneralCryptoLibException {

        Validate.notNull(in, "Key store input stream");
        Validate.notNull(password, "Key store password protection");
        Validate.notNullOrBlank(password.getPassword(),
            "Key store password");

        try {
            return _keyStoreWithPBKDFGenerator.load(in,
                password.getPassword());
        } catch (IOException e) {
            throw new GeneralCryptoLibException(
                "Could not load Scytl key store.", e);
        }
    }

    @Override
    public CryptoAPIScytlKeyStore loadKeyStoreFromJSON(
            final InputStream in, final PasswordProtection password)
            throws GeneralCryptoLibException {

        Validate.notNull(in, "Key store JSON input stream");
        Validate.notNull(password, "Key store password protection");
        Validate.notNullOrBlank(password.getPassword(),
            "Key store password");

        CryptoScytlKeyStoreWithPBKDF cryptoKeyStore =
            _keyStoreWithPBKDFGenerator.loadFromJSON(in,
                password.getPassword());
        return cryptoKeyStore;
    }

    @Override
    public String formatKeyStoreToJSON(final InputStream in)
            throws GeneralCryptoLibException {

        Validate.notNull(in, "Key store input stream");

        try {
            return _keyStoreWithPBKDFGenerator.formatKeyStoreToJSON(in);
        } catch (IOException e) {
            throw new GeneralCryptoLibException(
                "Could not format Scytl key store to JSON.", e);
        }
    }
}
