/*
 * 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.application.patch;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.ElGamalPublicKey;
import com.scytl.products.ov.commons.beans.ElectoralAuthority;
import com.scytl.products.ov.commons.beans.SharesPublicKey;
import com.scytl.products.ov.constants.Constants;
import com.scytl.products.ov.sdm.application.exception.CreateEBKeysSerializerException;
import com.scytl.products.ov.sdm.domain.service.ConfigConstants;
import com.scytl.products.ov.utils.ConfigObjectMapper;

/**
 * This is now the official implementation of the CreateEBKeysSerializer. It
 * simply stores the EB key in a json file representing the electoral authority
 * public information
 */
public class CreateEBKeysSerializer {

    private static final Logger LOG = LoggerFactory.getLogger("std");

    private final ConfigObjectMapper configObjectMapper;

    /**
     * @param configObjectMapper
     */
    public CreateEBKeysSerializer(final ConfigObjectMapper configObjectMapper) {
        super();
        this.configObjectMapper = configObjectMapper;
    }

    /**
     * Serialize the public part of the key stored in the shares as a file in
     * JSON format.
     * 
     * @param outputFolder
     *            the top level output folder of the serialized electoral board
     *            public key.
     * @param electoralAuthorityId
     *            the id of the serialized electoral authority keys
     * @param electoralAuthorityPublicKey
     *            the combined electoral authority public key.
     * @param decryptionPublicKey
     *            the public part of the shares key
     * @return True if both the Electoral Authority and the shares public key
     *         were successfully serialized, false otherwise.
     */
    public boolean serializeElectoralAuthorityKeys(Path outputFolder, String electoralAuthorityId,
            ElGamalPublicKey electoralAuthorityPublicKey, ElGamalPublicKey decryptionPublicKey) {

        String electoralAuthorityPublicKeyB64;
        String sharesPublicKeyB64;
        try {
            electoralAuthorityPublicKeyB64 = Base64.getEncoder()
                .encodeToString(electoralAuthorityPublicKey.toJson().getBytes(StandardCharsets.UTF_8));
            sharesPublicKeyB64 =
                Base64.getEncoder().encodeToString(decryptionPublicKey.toJson().getBytes(StandardCharsets.UTF_8));
        } catch (GeneralCryptoLibException e) {
            throw new CreateEBKeysSerializerException(
                "An error occurred while attempting to serialize an ElGamal public key: " + e.getMessage(), e);
        }

        LOG.info("Persisting the electoral authority " + electoralAuthorityId + "...");

        ElectoralAuthority electoralAuthority = new ElectoralAuthority();
        electoralAuthority.setId(electoralAuthorityId);
        electoralAuthority.setPublicKey(electoralAuthorityPublicKeyB64);

        SharesPublicKey sharesPublicKey = new SharesPublicKey();
        sharesPublicKey.setElectoralAuthorityId(electoralAuthorityId);
        sharesPublicKey.setPublicKey(sharesPublicKeyB64);

        final Path electoralAuthorityFolder = outputFolder.resolve(Constants.ONLINE_DIRECTORY)
            .resolve(Constants.ELECTORAL_AUTHORITIES_DIRECTORY).resolve(electoralAuthorityId);

        Path electoralAuthorityJsonPath =
            electoralAuthorityFolder.resolve(ConfigConstants.CONFIG_FILE_NAME_ELECTORAL_AUTHORITY_JSON);
        Path decryptionKeyJsonPath =
            electoralAuthorityFolder.resolve(ConfigConstants.CONFIG_FILE_NAME_DECRYPTION_KEY_JSON);

        try {
            Files.createDirectories(electoralAuthorityFolder);
            configObjectMapper.fromJavaToJSONFile(electoralAuthority, electoralAuthorityJsonPath.toFile());
            configObjectMapper.fromJavaToJSONFile(sharesPublicKey, decryptionKeyJsonPath.toFile());
        } catch (IOException e) {
            throw new UncheckedIOException(
                "An error occurred while serializing the public keys for the Electoral Authority "
                    + electoralAuthorityId,
                e);
        }

        return Files.exists(electoralAuthorityJsonPath) && Files.exists(decryptionKeyJsonPath);
    }

}
