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

import com.scytl.slogger.CleanDirProvider;
import com.scytl.slogger.crypto.SecureLoggerCryptographyFactory;
import com.scytl.slogger.crypto.SecureLoggerCryptographyProvider;
import com.scytl.slogger.crypto.SecureLoggerKeyStore;
import com.scytl.slogger.util.Securities;
import com.scytl.slogger.validator.LogFilePatternReceiver;
import com.scytl.slogger.validator.LoggingEventValidator;
import com.scytl.slogger.validator.ValidatorHelper;

import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.PublicKey;

import junit.framework.TestCase;

/**
 *
 */
public abstract class ProcessorTester extends TestCase {

  /**
   */
  private static final String TEST_LOG = "test.log";

  protected static final String SIGNATURE_PKCS12_PASSWORD = "GXXCNJH48X5F649VRY52";

  protected static final String CIPHER_PKCS12_PASSWORD = "649VRY52GXXCNJH48X5F";

  protected static final String SIGNATURE_PKCS12 = "signatureKeyStore.p12";

  protected static final String CIPHER_PKCS12 = "cipherKeyStore.p12";

  protected static final String LINE_SEPARATOR = "\n";

  protected static final String LOG_TRACE = "Log";

  protected static final int NUMBER_LOG_LINES = 10;

  protected static final long TIMER_LOG_MILLISECONDS = 60 * 60 * 1000;

  protected TestSecureAppender _secureAppender;

  protected Logger _logger;

  protected BufferedReader _logFileReader;

  protected SecureLoggerCryptographyProvider _cryptographyProvider;

  /**
   * @return Returns the cryptographyProvider.
   */
  public SecureLoggerCryptographyProvider getCryptographyProvider() {
    return _cryptographyProvider;
  }

  public void testValidator() throws Exception {
    for (int i = 0; i < 100; i++) {
      _logger.info(LOG_TRACE);
    }
    _secureAppender.close();
    ValidatorHelper.validateLog(_secureAppender, getLoggingEventValidator(),
        LogFilePatternReceiver.DEFAULT_TIMESTAMP_FORMAT);
  }

  protected PrivateKey getCipherPrivateKey() throws GeneralSecurityException, IOException {

    SecureLoggerKeyStore keyStore = _cryptographyProvider.readKeyStore(
        Thread.currentThread().getContextClassLoader().getResourceAsStream(CIPHER_PKCS12),
        CIPHER_PKCS12_PASSWORD.toCharArray());
    return _cryptographyProvider.getUserCipherPrivateKey(keyStore,
        CIPHER_PKCS12_PASSWORD.toCharArray());
  }

  protected PublicKey getCipherPublicKey() throws GeneralSecurityException, IOException {

    SecureLoggerKeyStore keyStore = _cryptographyProvider.readKeyStore(
        Thread.currentThread().getContextClassLoader().getResourceAsStream(CIPHER_PKCS12),
        CIPHER_PKCS12_PASSWORD.toCharArray());
    return _cryptographyProvider.getUserCipherPublicKey(keyStore);
  }

  protected abstract LoggingEventProcessor getLoggingEventProcessor() throws Exception;

  protected abstract LoggingEventValidator getLoggingEventValidator() throws Exception;

  protected PrivateKey getSignaturePrivateKey() throws GeneralSecurityException, IOException {

    SecureLoggerKeyStore keyStore = _cryptographyProvider.readKeyStore(
        Thread.currentThread().getContextClassLoader().getResourceAsStream(SIGNATURE_PKCS12),
        SIGNATURE_PKCS12_PASSWORD.toCharArray());
    return _cryptographyProvider.getUserSignaturePrivateKey(keyStore,
        SIGNATURE_PKCS12_PASSWORD.toCharArray());
  }

  protected PublicKey getSignaturePublicKey() throws GeneralSecurityException, IOException {

    SecureLoggerKeyStore keyStore = _cryptographyProvider.readKeyStore(
        Thread.currentThread().getContextClassLoader().getResourceAsStream(SIGNATURE_PKCS12),
        SIGNATURE_PKCS12_PASSWORD.toCharArray());
    return _cryptographyProvider.getUserSignaturePublicKey(keyStore);
  }

  /**
   * @see junit.framework.TestCase#setUp()
   */
  @Override
  protected void setUp() throws Exception {
    Securities.addBouncyCastleProviderIfNecessary();
    _cryptographyProvider = new SecureLoggerCryptographyFactory().build();

    File logFile = new File(CleanDirProvider.getCleanedTmpDir().getAbsolutePath(), TEST_LOG);
    _secureAppender = new TestSecureAppender(logFile.getAbsolutePath());
    _secureAppender.setName("APPENDER_TEST");
    _secureAppender.setLoggingEventProcessor(getLoggingEventProcessor());
    _secureAppender.activateOptions();

    _logger = LogManager.getRootLogger();
    _logger.addAppender(_secureAppender);
    _logger.setLevel(Level.INFO);

    _logFileReader = new BufferedReader(new FileReader(_secureAppender.getFile()));
  }

  /**
   * @see junit.framework.TestCase#tearDown()
   */
  @Override
  protected void tearDown() throws Exception {
    try {
      _logFileReader.close();
      LogManager.shutdown();
      CleanDirProvider.deleteTmpDir();
    } finally {
      Securities.removeBouncyCastleProviderIfNecessary();
    }
  }

}
