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

import com.scytl.slogger.SecureFileAppender;
import com.scytl.slogger.event.SecureLoggingEvent;
import com.scytl.slogger.event.SecurePatternLayout;
import com.scytl.slogger.processor.EventProcessorException;
import com.scytl.slogger.processor.TimerLoggingEventProcessor;
import com.scytl.slogger.processor.hmac.encrypted.signed.SignedEncryptedHMacEventProcessor;

import org.apache.log4j.Layout;

import java.util.LinkedList;
import java.util.List;

/**
 * Checkpoint event processor.
 */
public class CheckpointEventProcessor extends TimerLoggingEventProcessor {

  private final Object lock = new Object();

  private final SignedEncryptedHMacEventProcessor hmacProcessor;

  private final int numberLogLines;

  private int currentNumberLogLines;


  /**
   * Constructor.
   *
   * @param hmacProcessor the HMAC processor
   * @param appender the appender
   * @param numberLogLines the number of log lines
   * @param milliseconds the timeout in milliseconds.
   */
  public CheckpointEventProcessor(final SignedEncryptedHMacEventProcessor hmacProcessor,
      final SecureFileAppender appender, final int numberLogLines, final long milliseconds) {
    super(appender, milliseconds);
    if (numberLogLines <= 0) {
      throw new IllegalArgumentException("Number of log entries must be greater than zero");
    }
    this.hmacProcessor = hmacProcessor;
    this.numberLogLines = numberLogLines;
  }

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

    List<SecureLoggingEvent> loggingEventList;
    synchronized (lock) {

      if (loggingEvent.isCheckpoint()) {
        return checkPointLog(layout);
      }

      loggingEventList = hmacProcessor.processEvent(loggingEvent, layout);
      // SignedEncryptedHMacEventProcessor only generates 1 entry for
      // processed log entry
      currentNumberLogLines++;

      if (currentNumberLogLines >= numberLogLines) {
        loggingEventList.addAll(checkPointLog(layout));
      }
    }

    return loggingEventList;
  }

  @Override
  public List<SecureLoggingEvent> startProcessor(final SecurePatternLayout layout)
      throws EventProcessorException {
    List<SecureLoggingEvent> loggingEventList = new LinkedList<>();
    synchronized (lock) {
      loggingEventList.addAll(hmacProcessor.startProcessor(layout));
    }
    loggingEventList.addAll(super.startProcessor(layout));

    return loggingEventList;
  }

  @Override
  public List<SecureLoggingEvent> stopProcessor(final SecurePatternLayout layout)
      throws EventProcessorException {
    List<SecureLoggingEvent> loggingEventList = super.stopProcessor(layout);
    synchronized (lock) {
      loggingEventList.addAll(hmacProcessor.stopProcessor(layout));
    }

    return loggingEventList;
  }

  private List<SecureLoggingEvent> checkPointLog(final Layout layout)
      throws EventProcessorException {
    List<SecureLoggingEvent> loggingEventList = new LinkedList<>();

    synchronized (lock) {
      currentNumberLogLines = 0;
      resetTimer();
      loggingEventList.addAll(hmacProcessor.secretKeyLog((SecurePatternLayout) layout));
    }

    return loggingEventList;
  }
}
