/*
 * 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.slogger.processor.signature;

import com.scytl.slogger.crypto.SecureLoggerCryptographyProvider;
import com.scytl.slogger.event.SecureLoggingEvent;
import com.scytl.slogger.event.SecureMessageProperties;
import com.scytl.slogger.event.SecurePatternLayout;
import com.scytl.slogger.processor.EventProcessorException;
import com.scytl.slogger.processor.LoggingEventProcessor;

import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.util.Base64;
import java.util.LinkedList;
import java.util.List;

/**
 * Processor that signs each log entry.
 */
public class SignatureEventProcessor implements LoggingEventProcessor {

  private final PrivateKey privateKey;

  private final SecureLoggerCryptographyProvider cryptographyProvider;

  /**
   * Constructor.
   *
   * @param privateKey the privte key
   * @param cryptographyProvider the cryptography provider.
   */
  public SignatureEventProcessor(final PrivateKey privateKey,
      final SecureLoggerCryptographyProvider cryptographyProvider) {
    this.privateKey = privateKey;
    this.cryptographyProvider = cryptographyProvider;

  }

  @Override
  public void killProcessor() throws EventProcessorException {}

  @Override
  public List<SecureLoggingEvent> processEvent(final SecureLoggingEvent loggingEvent,
      final SecurePatternLayout layout) throws EventProcessorException {

    byte[] signature = signData(loggingEvent, layout);

    List<SecureLoggingEvent> loggingEventList = new LinkedList<>();
    loggingEventList.add(loggingEvent.addProperty(SecureMessageProperties.SIGNATURE,
        Base64.getEncoder().encodeToString(signature)));
    return loggingEventList;
  }

  @Override
  public List<SecureLoggingEvent> startProcessor(final SecurePatternLayout layout)
      throws EventProcessorException {
    return new LinkedList<>();
  }

  @Override
  public List<SecureLoggingEvent> stopProcessor(final SecurePatternLayout layout) {
    return new LinkedList<>();
  }

  /**
   * Signs a given event.
   *
   * @param loggingEvent the event
   * @param layout the layout
   * @return the signature
   * @throws EventProcessorException failed to sign the event.
   */
  protected byte[] signData(final SecureLoggingEvent loggingEvent, final SecurePatternLayout layout)
      throws EventProcessorException {
    try {
      byte[] data = layout.format(loggingEvent, true).getBytes(StandardCharsets.UTF_8);
      return cryptographyProvider.sign(data, privateKey);
    } catch (GeneralSecurityException e) {
      throw new EventProcessorException(e);
    }
  }
}
