
package de.ivu.elect.business.wahl.control;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;

import javax.annotation.Nonnull;

import org.apache.commons.io.IOUtils;

import de.ivu.elect.business.datei.entity.Datei;
import de.ivu.elect.business.wahl.entity.NlWahlCustomData;
import de.ivu.elect.business.wahl.entity.Wahl;

public class NlHashByteArrayOutputStream extends ByteArrayOutputStream {

  private static final int BUFFER_SIZE = 64 * 1024;

  private final OutputStream wrapped;

  private final Datei datei;

  public NlHashByteArrayOutputStream(OutputStream wrapped, Datei datei) {
    super(BUFFER_SIZE);

    this.wrapped = wrapped;
    this.datei = datei;
  }

  @Override
  public void close() throws IOException {
    super.close();

    writeTo(wrapped);

    wrapped.close();

    // ELECTVAPP-348
    if (datei != null) {
      Wahl wahl = datei.getWahl();

      if (wahl != null && datei.getPk().getId() != null) {
        NlWahlCustomData customData = wahl.getCustomData(NlWahlCustomData.class);

        customData.addDateiHash(datei.getPk().getId(), /* ELECT-11082 DigestUtils.sha256Hex */ sha256(toByteArray()));
      }
    }
  }

  public static String sha256(InputStream inputStream) {
    // ELECT-11082 return org.apache.commons.codec.digest.DigestUtils.sha256Hex(inputStream);
    try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
      IOUtils.copy(inputStream, bos);

      return NlHashByteArrayOutputStream.sha256(bos.toByteArray());
    } catch (Exception ex) {
      throw new RuntimeException(ex.getMessage(), ex);
    }
  }

  @Nonnull
  public static String sha256(byte[] input) {
    try {
      return enc(MessageDigest.getInstance("SHA-256").digest(input));
    } catch (Exception ex) {
      throw new RuntimeException(ex.getMessage(), ex);
    }
  }

  /**
   * https://www.baeldung.com/sha-256-hashing-java
   */
  private static String enc(byte[] encodedhash) {
    StringBuilder hexString = new StringBuilder(2 * encodedhash.length);

    for (byte b : encodedhash) {
      String hex = Integer.toHexString(0xff & b);

      if (hex.length() == 1) {
        hexString.append('0');
      }

      hexString.append(hex);
    }

    return hexString.toString();
  }
}
