/*
 * 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.ei.services.domain.model.vote;

import javax.decorator.Decorator;
import javax.decorator.Delegate;
import javax.inject.Inject;

import org.apache.commons.lang3.exception.ExceptionUtils;

import com.scytl.products.oscore.logging.api.domain.Level;
import com.scytl.products.oscore.logging.api.domain.LogContent;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.ov.commons.beans.domain.model.receipt.Receipt;
import com.scytl.products.ov.commons.beans.domain.model.vote.Vote;
import com.scytl.products.ov.commons.beans.exceptions.ApplicationException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.validation.CryptographicOperationException;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.ei.services.infrastructure.log.ElectionInformationLogConstants;
import com.scytl.products.ov.ei.services.infrastructure.log.ElectionInformationLogEvents;
import com.scytl.products.ov.ei.services.infrastructure.log.SecureLoggerHelper;

/**
 * Decorator of the receipt factory.
 */
@Decorator
public class ReceiptFactoryDecorator implements ReceiptFactory {

    @Inject
    @Delegate
    private ReceiptFactory receiptFactory;

    @Inject
    private TrackIdInstance trackId;

    @Inject
    private SecureLoggingWriter secureLoggerWriter;

    @Inject
    private SecureLoggerHelper secureLoggerHelper;

    /**
     * @see com.scytl.products.ov.ei.services.domain.model.vote.ReceiptFactory#generate(Vote,
     *      String)
     */
    @Override
    public Receipt generate(Vote vote, String authToken) throws ApplicationException, CryptographicOperationException {
        String authTokenHash = secureLoggerHelper.getAuthTokenHash(vote.getAuthenticationToken());
        String voteHash = secureLoggerHelper.getVoteHash(vote);
        try {
            Receipt receipt = receiptFactory.generate(vote, authToken);
            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.RECEIPT_CORRECTLY_GENERATED)
                    .objectId(authTokenHash).user(vote.getVotingCardId()).electionEvent(vote.getElectionEventId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_HASH_VOTE, voteHash)
                    .additionalInfo(ElectionInformationLogConstants.INFO_RECEIPT, receipt.getReceipt())
                    .createLogInfo());
            return receipt;
        } catch (ApplicationException | CryptographicOperationException e) {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.ERROR_COMPUTING_RECEIPT)
                    .objectId(authTokenHash).user(vote.getVotingCardId()).electionEvent(vote.getElectionEventId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_HASH_VOTE, voteHash)
                    .additionalInfo(ElectionInformationLogConstants.INFO_ERR_DESC,
                        "Error generating receipt: " + ExceptionUtils.getRootCauseMessage(e))
                    .createLogInfo());
            throw e;
        }
    }

    /**
     * @see com.scytl.products.ov.ei.services.domain.model.vote.ReceiptFactory#sign(com.scytl.products.ov.ei.services.domain.model.vote.Receipt,
     *      com.scytl.products.ov.commons.beans.domain.model.vote.Vote)
     */
    @Override
    public String sign(Receipt receipt, Vote vote) throws CryptographicOperationException, ResourceNotFoundException {
        try {
            final String receiptDesc = receiptFactory.sign(receipt, vote);
            logCorrectReceiptSignature(receipt, vote);
            return receiptDesc;
        } catch (CryptographicOperationException | ResourceNotFoundException e) {
            String authTokenHash = secureLoggerHelper.getAuthTokenHash(vote.getAuthenticationToken());
            String voteHash = secureLoggerHelper.getVoteHash(vote);
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.ERROR_SIGNING_RECEIPT)
                    .objectId(authTokenHash).user(vote.getVotingCardId()).electionEvent(vote.getElectionEventId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_HASH_VOTE, voteHash)
                    .additionalInfo(ElectionInformationLogConstants.INFO_RECEIPT, receipt.getReceipt())
                    .additionalInfo(ElectionInformationLogConstants.INFO_ERR_DESC,
                        "Error signing receipt: " + ExceptionUtils.getRootCauseMessage(e))
                    .createLogInfo());
            throw e;
        }
    }

    private void logCorrectReceiptSignature(Receipt receipt, Vote vote) {
        String authTokenHash = secureLoggerHelper.getAuthTokenHash(vote.getAuthenticationToken());
        String voteHash = secureLoggerHelper.getVoteHash(vote);
        secureLoggerWriter.log(Level.INFO,
            new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.RECEIPT_CORRECTLY_SIGNED)
                .objectId(authTokenHash).user(vote.getVotingCardId()).electionEvent(vote.getElectionEventId())
                .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                .additionalInfo(ElectionInformationLogConstants.INFO_HASH_VOTE, voteHash)
                .additionalInfo(ElectionInformationLogConstants.INFO_RECEIPT, receipt.getReceipt()).createLogInfo());
    }

}
