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

import com.googlecode.jcsv.writer.CSVWriter;
import com.googlecode.jcsv.writer.internal.CSVWriterBuilder;
import com.scytl.products.ov.mixnet.command.writer.DecryptedVoteConverter;
import com.scytl.products.ov.mixnet.commons.beans.VoteWithProof;
import com.scytl.products.ov.mixnet.commons.exceptions.MixingException;
import com.scytl.products.ov.mixnet.commons.tools.ConfigObjectMapper;
import com.scytl.products.ov.mixnet.commons.tools.VoteWithProofConverter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;

/**
 * Assists in writing decrypted votes with proofs to their own CSV files.
 */
public class VotesWithProofWriter {

  /**
   * Non-public constructor 
   */
  private VotesWithProofWriter() {	  
  }
	
  /**
   * Write a stream of decrypted votes along with their proofs to two files, one for the votes with
   * proofs and another one with the decrypted votes alone.
   *
   * @param votesWithProofFilePath the file the votes with proofs will be stored to
   * @param decryptedVotesFilePath the file the decrypted votes will be stored to
   * @param votesWithProof the votes with proof to be stored
   */
  public static void write(final OutputStream votesWithProofOutputStream, final OutputStream decryptedVotes,
      final List<VoteWithProof> votesWithProof)
      throws IOException {

	validateStreamIsNotNull(votesWithProofOutputStream);
	validateStreamIsNotNull(decryptedVotes);
    validateContents(votesWithProof);

    ConfigObjectMapper objectMapper = new ConfigObjectMapper();

    try (Writer votesWithProofWriter = new OutputStreamWriter(votesWithProofOutputStream);
        Writer decryptedVotesWriter = new OutputStreamWriter(decryptedVotes);
        CSVWriter<VoteWithProof> vwpWriter =
            new CSVWriterBuilder<VoteWithProof>(votesWithProofWriter)
                .entryConverter(new VoteWithProofConverter(objectMapper)).build();
        CSVWriter<VoteWithProof> dvWriter =
            new CSVWriterBuilder<VoteWithProof>(decryptedVotesWriter)
                .entryConverter(new DecryptedVoteConverter()).build()) {
        for (VoteWithProof voteWithProof : votesWithProof) {
            // Write the vote with proof.
            vwpWriter.write(voteWithProof);
            // Write the decrypted vote only.
            dvWriter.write(voteWithProof);
        }
     }
  }

  private static void validateContents(final List<VoteWithProof> value) {
    if (null == value) {
      invalidWritingCommand("The decrypted ballot list is not set");
    }
  }

  private static void validateStreamIsNotNull(final OutputStream stream) {
    if (null == stream ) {
      invalidWritingCommand("Could not write to stream");
    }

  }

  private static void invalidWritingCommand(final String string) {
    throw new MixingException(string);
  }
}
