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

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Callable;

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

import com.scytl.cryptolib.api.primitives.PrimitivesServiceAPI;
import com.scytl.cryptolib.elgamal.bean.ElGamalPrivateKey;
import com.scytl.cryptolib.elgamal.bean.ElGamalPublicKey;
import com.scytl.cryptolib.mathematical.groups.impl.ZpSubgroup;
import com.scytl.products.ov.mixnet.NonMixer;
import com.scytl.products.ov.mixnet.commons.ballots.ElGamalEncryptedBallots;
import com.scytl.products.ov.mixnet.commons.configuration.BGParams;
import com.scytl.products.ov.mixnet.commons.configuration.locations.LocationsProvider;
import com.scytl.products.ov.mixnet.commons.exceptions.MixingException;
import com.scytl.products.ov.mixnet.commons.proofs.bg.commitments.CommitmentParams;

public class NonMixingBatch implements Callable<MixingResult> {

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

    private final int id;

    private final NonMixer nonMixer;

    private final ElGamalEncryptedBallots elGamalEncryptedBallots;

    private final int offset;

    private final int batchNum;

    private final BGParams batchBGParams;

    private final ZpSubgroup zpGroup;

    private final int partitionSize;

    private final ElGamalPublicKey publicKey;

    private final ElGamalPrivateKey ballotDecryptionKey;

    private final LocationsProvider locationsProvider;

    private PrimitivesServiceAPI primitivesService;

    public NonMixingBatch(final int partitionSize, final NonMixer nonMixer,
            final ElGamalEncryptedBallots elGamalEncryptedBallots, final int offset, final int batchNum,
            final BGParams bGParams, final ZpSubgroup zpGroup, final int id, final ElGamalPublicKey publicKey,
            final ElGamalPrivateKey ballotDecryptionKey, final LocationsProvider locationsProvider,
            PrimitivesServiceAPI primitivesService) {

        this.partitionSize = partitionSize;
        this.nonMixer = nonMixer;
        this.elGamalEncryptedBallots = elGamalEncryptedBallots;
        this.offset = offset;

        this.batchNum = batchNum;
        this.batchBGParams = bGParams;
        this.zpGroup = zpGroup;
        this.publicKey = publicKey;
        this.ballotDecryptionKey = ballotDecryptionKey;

        this.locationsProvider = locationsProvider;
        this.id = id;
        this.primitivesService = primitivesService;
    }

    @Override
    public MixingResult call() throws MixingException {

        Instant start = Instant.now();
        MixingResult mixingResult;

        LOG.info("Non mixing " + partitionSize + " encrypted ballots...");

        try {

            final CommitmentParams batchCommitmentParams = createBatchCommitmentParams(batchBGParams);

            nonMixer.mix(elGamalEncryptedBallots, batchCommitmentParams, publicKey, zpGroup, batchNum,
                partitionSize, offset, ballotDecryptionKey, locationsProvider, primitivesService);

            mixingResult = new MixingResult(true, batchNum, partitionSize, offset);

            LOG.info("Batch id=" + id + "(index of partitions array) with " + partitionSize + " finished OK.");

        } catch (final Exception e) {
            LOG.error("An error occurred while performing mixing batch number " + batchNum, e);
            mixingResult = new MixingResult(false, batchNum, partitionSize, offset);
        }

        Instant end = Instant.now();
        LOG.info("Batch id=" + id + " duration was: " + Duration.between(start, end));

        return mixingResult;
    }

    private CommitmentParams createBatchCommitmentParams(final BGParams batchBGParams) {
        return new CommitmentParams(zpGroup, batchBGParams.getN());
    }

}