/*
 * 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.channel.cc.commons.slogger;

import static java.util.Objects.requireNonNull;

import java.util.Enumeration;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerRepository;

import com.scytl.products.ov.channel.cc.commons.keymanagement.KeyManager;
import com.scytl.slogger.DeferredSecureAppender;
import com.scytl.slogger.SecureLoggerException;

/**
 * Implementation of {@link SecureLoggerManager}.
 */
public final class SecureLoggerManagerImpl
        implements SecureLoggerManager {

    private final LoggerRepository repository;

    private final KeyManager manager;

    /**
     * Constructor.
     * 
     * @param manager
     *            the key manager.
     */
    public SecureLoggerManagerImpl(KeyManager manager) {
        this(LogManager.getLoggerRepository(), manager);
    }

    /**
     * Constructor. For internal use only.
     * 
     * @param repository
     * @param manager
     */
    SecureLoggerManagerImpl(LoggerRepository repository,
            KeyManager manager) {
        this.repository = repository;
        this.manager = manager;
    }

    @Override
    public void closeSecureLogger() throws SecureLoggerException {
        closeSecureLogger(DEFAULT_SECURE_LOGGER_NAME);
    }

    @Override
    public void closeSecureLogger(String name)
            throws SecureLoggerException {
        getDeferredSecureAppender(name).close();
    }

    @Override
    public void openSecureLogger() throws SecureLoggerException {
        openSecureLogger(DEFAULT_SECURE_LOGGER_NAME);
    }

    @Override
    public void openSecureLogger(String name)
            throws SecureLoggerException {
        requireNonNull(name, "Name is null.");
        ErrorTracker tracker = new ErrorTrackerImpl();
        openSecureLogger(name, tracker);
    }

    /**
     * Activates the secure logger. For internal use only.
     * 
     * @param name
     *            the logger name
     * @param tracker
     *            the error tracker
     * @throws SecureLoggerException
     *             failed to activate the secure logger.
     */
    void openSecureLogger(String name, ErrorTracker tracker)
            throws SecureLoggerException {
        if (!manager.hasNodeKeysActivated()) {
            throw new SecureLoggerException(
                "Secure log keys are not available.");
        }
        DeferredSecureAppender appender = getDeferredSecureAppender(name);
        tracker.setTarget(appender.getErrorHandler());
        appender.setErrorHandler(tracker);
        appender.activateOptions(manager.nodeLogSigningPrivateKey(),
            manager.nodeLogEncryptionPrivateKey(),
            manager.nodeLogEncryptionPublicKey());
        tracker.checkNoError();
    }

    private DeferredSecureAppender getDeferredSecureAppender(String name)
            throws SecureLoggerException {
        Logger logger = repository.getLogger(name);
        Enumeration<?> appenders = logger.getAllAppenders();
        while (appenders.hasMoreElements()) {
            Object element = appenders.nextElement();
            if (element instanceof DeferredSecureAppender) {
                return (DeferredSecureAppender) element;
            }
        }
        throw new SecureLoggerException(
            "Deferred secure appender does not exist.");
    }
}
