/*
 * 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.vw.services.infrastructure.remote;

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.confirmation.ConfirmationMessage;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.exceptions.VoteCastCodeRepositoryException;
import com.scytl.products.ov.commons.beans.validation.CryptographicOperationException;
import com.scytl.products.ov.commons.dto.CastCodeAndComputeResults;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.vw.infrastructure.log.SecureLoggerInformation;
import com.scytl.products.ov.vw.infrastructure.log.VotingWorkflowLogConstants;
import com.scytl.products.ov.vw.infrastructure.log.VotingWorkflowLogEvents;
import com.scytl.products.ov.vw.services.domain.model.confirmation.VoteCastCodeRepository;

/**
 * Decorator of the vote cast code repository.
 */
@Decorator
public class VoteCastCodeRepositoryDecorator implements VoteCastCodeRepository {

    @Inject
    @Delegate
    private VoteCastCodeRepository voteCastCodeRepository;

    @Inject
    private TrackIdInstance trackIdInstance;

    @Inject
    private SecureLoggingWriter secureLoggerWriter;

    @Inject
    private SecureLoggerInformation secureLoggerInformation;

    /**
     * @see com.scytl.products.ov.vw.services.domain.model.confirmation.VoteCastCodeRepository#generateCastCode(java.lang.String,
     *      java.lang.String, java.lang.String,
     *      com.scytl.products.ov.vw.services.domain.model.confirmation.ConfirmationMessage)
     */
    @Override
    public CastCodeAndComputeResults generateCastCode(String tenantId, String electionEventId,
            String verificationCardId, String votingCardId, String authenticationTokenSignature,
            ConfirmationMessage confirmationMessage) throws CryptographicOperationException {
        try {
            CastCodeAndComputeResults result = voteCastCodeRepository.generateCastCode(tenantId, electionEventId,
                verificationCardId, votingCardId, authenticationTokenSignature, confirmationMessage);
            secureLoggerWriter
                .log(Level.INFO,
                    new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.MAPPING_CAST_CODE_FOUND)
                        .objectId(secureLoggerInformation.getAuthenticationTokenHash())
                        .user(secureLoggerInformation.getAuthenticationTokenObject().getVoterInformation()
                            .getVotingCardId())
                        .electionEvent(electionEventId)
                        .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackIdInstance.getTrackId())
                        .additionalInfo(VotingWorkflowLogConstants.INFO_VERIFICATION_CARD_ID, verificationCardId)
                        .additionalInfo(VotingWorkflowLogConstants.INFO_VERIFICATION_CARD_SET_ID,
                            secureLoggerInformation.getAuthenticationTokenObject().getVoterInformation()
                                .getVerificationCardSetId())
                        .createLogInfo());
            return result;
        } catch (CryptographicOperationException e) {
            secureLoggerWriter
                .log(Level.ERROR,
                    new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.MAPPING_CAST_CODE_NOT_FOUND)
                        .objectId(secureLoggerInformation.getAuthenticationTokenHash())
                        .user(secureLoggerInformation.getAuthenticationTokenObject().getVoterInformation()
                            .getVotingCardId())
                        .electionEvent(electionEventId)
                        .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackIdInstance.getTrackId())
                        .additionalInfo(VotingWorkflowLogConstants.INFO_VERIFICATION_CARD_ID, verificationCardId)
                        .additionalInfo(VotingWorkflowLogConstants.INFO_VERIFICATION_CARD_SET_ID,
                            secureLoggerInformation.getAuthenticationTokenObject().getVoterInformation()
                                .getVerificationCardSetId())
                        .additionalInfo(VotingWorkflowLogConstants.INFO_ERR_DESC, "Vote cast code not found")
                        .createLogInfo());
            throw e;
        }
    }

    /**
     * @see com.scytl.products.ov.vw.services.domain.model.confirmation.VoteCastCodeRepository#storesCastCode(java.lang.String,
     *      java.lang.String, java.lang.String,
     *      com.scytl.com.scytl.products.ov.commons.dto.CastCodeAndComputeResults)
     */
    @Override
    public boolean storesCastCode(String tenantId, String electionEventId, String votingCardId,
            CastCodeAndComputeResults voteCastMessage) throws ResourceNotFoundException {
        try {
            boolean result =
                voteCastCodeRepository.storesCastCode(tenantId, electionEventId, votingCardId, voteCastMessage);
            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.CAST_CODE_STORED)
                    .objectId(secureLoggerInformation.getAuthenticationTokenHash()).user(votingCardId)
                    .electionEvent(electionEventId)
                    .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackIdInstance.getTrackId())
                    .createLogInfo());
            return result;
        } catch (ResourceNotFoundException e) {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.CAST_CODE_ERROR_STORING)
                    .objectId(secureLoggerInformation.getAuthenticationTokenHash()).user(votingCardId)
                    .electionEvent(electionEventId)
                    .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackIdInstance.getTrackId())
                    .additionalInfo(VotingWorkflowLogConstants.INFO_BALLOT_BOX_ID,
                        secureLoggerInformation.getAuthenticationTokenObject().getVoterInformation().getBallotBoxId())
                    .additionalInfo(VotingWorkflowLogConstants.INFO_VOTE_HASH, secureLoggerInformation.getVoteHash())
                    .additionalInfo(VotingWorkflowLogConstants.INFO_ERR_DESC,
                        "Error saving Cast code: " + ExceptionUtils.getRootCauseMessage(e))
                    .createLogInfo());
            throw e;
        }
    }

    /**
     * @see com.scytl.products.ov.vw.services.domain.model.confirmation.VoteCastCodeRepository#getCastCode(java.lang.String,
     *      java.lang.String, java.lang.String)
     */
    @Override
    public CastCodeAndComputeResults getCastCode(String tenantId, String electionEventId, String votingCardId)
            throws ResourceNotFoundException {
        try {
            CastCodeAndComputeResults result =
                voteCastCodeRepository.getCastCode(tenantId, electionEventId, votingCardId);
            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.DB_CAST_CODE_FOUND)
                    .objectId(secureLoggerInformation.getAuthenticationTokenHash()).user(votingCardId)
                    .electionEvent(electionEventId)
                    .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackIdInstance.getTrackId())
                    .additionalInfo(VotingWorkflowLogConstants.INFO_BALLOT_BOX_ID,
                        secureLoggerInformation.getAuthenticationTokenObject().getVoterInformation().getBallotBoxId())
                    .createLogInfo());
            return result;
        } catch (ResourceNotFoundException e) {
            secureLoggerWriter
                .log(Level.ERROR,
                    new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.DB_CAST_CODE_NOT_FOUND)
                        .objectId(secureLoggerInformation.getAuthenticationTokenHash()).user(votingCardId)
                        .electionEvent(electionEventId)
                        .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackIdInstance.getTrackId())
                        .additionalInfo(VotingWorkflowLogConstants.INFO_BALLOT_BOX_ID,
                            secureLoggerInformation.getAuthenticationTokenObject().getVoterInformation()
                                .getBallotBoxId())
                        .additionalInfo(VotingWorkflowLogConstants.INFO_ERR_DESC,
                            "Cast code not found: " + ExceptionUtils.getRootCauseMessage(e))
                        .createLogInfo());
            throw e;
        }
    }

    @Override
    public boolean voteCastCodeExists(final String tenantId, final String electionEventId, final String votingCardId)
            throws VoteCastCodeRepositoryException {
        return voteCastCodeRepository.voteCastCodeExists(tenantId, electionEventId, votingCardId);
    }

}
