/*
 * 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.vm.infrastructure.persistence;

import javax.decorator.Decorator;
import javax.decorator.Delegate;
import javax.inject.Inject;
import java.util.List;

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.exceptions.DuplicateEntryException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.vm.domain.model.information.VoterInformation;
import com.scytl.products.ov.vm.domain.model.information.VoterInformationRepository;
import com.scytl.products.ov.vm.infrastructure.log.VoterMaterialLogConstants;
import com.scytl.products.ov.vm.infrastructure.log.VoterMaterialLogEvents;

/**
 * A decorator with logger for voterIinformation repository.
 */
@Decorator
public abstract class VoterInformationRepositoryDecorator implements VoterInformationRepository {

    @Inject
    @Delegate
    private VoterInformationRepository voterInformationRepository;

    @Inject
    private TrackIdInstance trackIdInstance;

    @Inject
    private SecureLoggingWriter secureLoggerWriter;

    /**
     * Returns a voter information for a given tenant, election event and credential. In this implementation, we use a
     * database query to obtain voter information taking into account the input parameters.
     *
     * @param tenantId
     *            - the tenant identifier.
     * @param electionEventId
     *            - the election event identifier.
     * @param credentialId
     *            - the credential identifier.
     * @return The voter information.
     * @throws ResourceNotFoundException
     *             if the voter information is not found.
     */
    @Override
    public VoterInformation findByTenantIdElectionEventIdCredentialId(final String tenantId,
            final String electionEventId, final String credentialId) throws ResourceNotFoundException {

        try {
            VoterInformation result = voterInformationRepository.findByTenantIdElectionEventIdCredentialId(tenantId,
                electionEventId, credentialId);

            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(VoterMaterialLogEvents.VOTER_INFORMATION_FOUND)
                    .objectId(credentialId).user(credentialId).electionEvent(electionEventId)
                    .additionalInfo(VoterMaterialLogConstants.TRACK_ID, trackIdInstance.getTrackId()).createLogInfo());

            return result;
        } catch (ResourceNotFoundException e) {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(VoterMaterialLogEvents.VOTER_INFORMATION_NOT_FOUND)
                    .objectId(credentialId).user(credentialId).electionEvent(electionEventId)
                    .additionalInfo(VoterMaterialLogConstants.TRACK_ID, trackIdInstance.getTrackId())
                    .additionalInfo(VoterMaterialLogConstants.ERR_DESC,
                        "Resource not found in the VOTER_INFORMATION table.")
                    .createLogInfo());
            throw e;
        }
    }

    /**
     * Returns a voter information for a given tenant, election event and voting card. In this implementation, we use a
     * database query to obtain voter information taking into account the input parameters.
     *
     * @param tenantId
     *            - the tenant identifier.
     * @param electionEventId
     *            - the election event identifier.
     * @param votingCardId
     *            - the voting card identifier.
     * @return The voter information.
     * @throws ResourceNotFoundException
     *             if the voter information is not found.
     */
    @Override
    public VoterInformation findByTenantIdElectionEventIdVotingCardId(final String tenantId,
            final String electionEventId, final String votingCardId) throws ResourceNotFoundException {

        try {
            VoterInformation result = voterInformationRepository.findByTenantIdElectionEventIdVotingCardId(tenantId,
                electionEventId, votingCardId);

            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(VoterMaterialLogEvents.VOTER_INFORMATION_FOUND)
                    .objectId(votingCardId).user(votingCardId).electionEvent(electionEventId)
                    .additionalInfo(VoterMaterialLogConstants.TRACK_ID, trackIdInstance.getTrackId()).createLogInfo());

            return result;
        } catch (ResourceNotFoundException e) {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(VoterMaterialLogEvents.VOTER_INFORMATION_NOT_FOUND)
                    .objectId(votingCardId).user(votingCardId).electionEvent(electionEventId)
                    .additionalInfo(VoterMaterialLogConstants.TRACK_ID, trackIdInstance.getTrackId())
                    .additionalInfo(VoterMaterialLogConstants.ERR_DESC,
                        "Resource not found in the VOTER_INFORMATION table.")
                    .createLogInfo());
            throw e;
        }
    }
    
    @Override
    public boolean hasWithTenantIdElectionEventIdVotingCardId(
            String tenantId, String electionEventId, String votingCardId) {
        return voterInformationRepository
            .hasWithTenantIdElectionEventIdVotingCardId(tenantId,
                electionEventId, votingCardId);
    }

    /**
     * Find by tenant id election event id and search terms.
     *
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param searchTerm
     *            the search term
     * @param pageNumber
     *            the page number
     * @param pageSize
     *            the page size
     * @return the list
     * @throws ResourceNotFoundException
     *             the resource not found exception
     */
    @Override
    public List<VoterInformation> findByTenantIdElectionEventIdAndSearchTerms(final String tenantId,
            final String electionEventId, final String searchTerm, final int pageNumber, final int pageSize)
            throws ResourceNotFoundException {
        return voterInformationRepository.findByTenantIdElectionEventIdAndSearchTerms(tenantId, electionEventId,
            searchTerm, pageNumber, pageSize);
    }

    /**
     * Count by tenant id election event id.
     *
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param idSearchTerm
     *            the id search term
     * @return the long
     * @throws ResourceNotFoundException
     *             the resource not found exception
     */
    @Override
    public long countByTenantIdElectionEventIdAndSearchTerms(final String tenantId, final String electionEventId,
            final String idSearchTerm) throws ResourceNotFoundException {
        return voterInformationRepository.countByTenantIdElectionEventIdAndSearchTerms(tenantId, electionEventId,
            idSearchTerm);
    }

    @Override
    public VoterInformation save(final VoterInformation entity) throws DuplicateEntryException {
        try {
            final VoterInformation voterInformation = voterInformationRepository.save(entity);
            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(VoterMaterialLogEvents.VOTER_INFORMATION_FOUND)
                    .objectId(entity.getVotingCardId()).user("admin")
                    .electionEvent(entity.getElectionEventId())
                    .additionalInfo(VoterMaterialLogConstants.TRACK_ID, trackIdInstance.getTrackId()).createLogInfo());
            return voterInformation;
        } catch (DuplicateEntryException ex) {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(VoterMaterialLogEvents.VOTER_INFORMATION_NOT_FOUND)
                    .objectId(entity.getVotingCardId()).user("admin")
                    .electionEvent(entity.getElectionEventId())
                    .additionalInfo(VoterMaterialLogConstants.TRACK_ID, trackIdInstance.getTrackId())
                    .additionalInfo(VoterMaterialLogConstants.ERR_DESC, ex.getMessage())
                    .createLogInfo());
            throw ex;
        }
    }
}
