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

import com.scytl.cryptolib.elgamal.cryptoapi.Ciphertext;
import com.scytl.products.ov.mixnet.MixnetLoadBalancer;
import com.scytl.products.ov.mixnet.commons.beans.WarmUpOutput;
import com.scytl.products.ov.mixnet.commons.configuration.ApplicationConfig;
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.homomorphic.Randomness;

import static java.util.Objects.requireNonNull;

import java.io.IOException;
import java.util.List;


public final class MixingService implements MixingServiceAPI {

  private final MixnetLoadBalancer mixnetLoadBalancer;

  private final WarmUpService warmUpService = new WarmUpService();

  private volatile WarmUpOutput warmUpOutput;

  public MixingService(final MixnetLoadBalancer mixnetLoadBalancer) {
    requireNonNull(mixnetLoadBalancer, "The mixnet load balancer must be set");
    this.mixnetLoadBalancer = mixnetLoadBalancer;
  }

  @Override
  public void warmUp(final ApplicationConfig applicationConfig) throws MixingException {
	warmUpOutput = warmUpService.warmUp(applicationConfig);
  }

  @Override
  public void mix(final ApplicationConfig applicationConfig,
      final LocationsProvider locationsProvider) throws MixingException {
    requireNonNull(applicationConfig, "The received application config was null");
    WarmUpOutput wUpOutput = this.warmUpOutput;
    Randomness[] randomExponents = 
            wUpOutput != null ? wUpOutput.getRandomExponents() : null;
    List<Ciphertext> preComputations = 
            wUpOutput != null ? wUpOutput.getPreComputations() : null;
    try {
        mixnetLoadBalancer.balance(applicationConfig, locationsProvider,
            randomExponents, preComputations);
    } catch (IOException e) {
        throw new MixingException("Error while executing mix operation", e);
    } finally {
      this.warmUpOutput = null;
    }
  }
}
