/*
 * 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.service.ballotbox;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;

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

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.EntityId;
import com.scytl.products.ov.commons.beans.exceptions.EntryPersistenceException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.validation.ValidationErrorType;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.validation.ValidationError;
import com.scytl.products.ov.commons.validation.ValidationResult;
import com.scytl.products.ov.ei.services.infrastructure.log.ElectionInformationLogConstants;
import com.scytl.products.ov.ei.services.infrastructure.log.ElectionInformationLogEvents;

/**
 * Decorator for ballot box service.
 */
@Decorator
public class BallotBoxServiceDecorator implements BallotBoxService {

    @Inject
    @Delegate
    private BallotBoxService ballotBoxService;

    @Inject
    private SecureLoggingWriter secureLoggerWriter;

    @Inject
    private TrackIdInstance trackId;

    /**
     * Implementation for secure logging of the corresponding event.
     *
     * @see com.scytl.products.ov.ei.services.domain.service.ballotbox.BallotBoxService#checkIfBallotBoxesAreEmpty(java.lang.String,
     *      java.lang.String, java.lang.String)
     */
    @Override
    public ValidationResult checkIfBallotBoxesAreEmpty(final String tenantId, final String electionEventId,
            final String ballotBoxId) {

        final ValidationResult validationResult =
            ballotBoxService.checkIfBallotBoxesAreEmpty(tenantId, electionEventId, ballotBoxId);
        if (!validationResult.isResult()) {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.BALLOT_BOX_NOT_EMPTY)
                    .objectId(ballotBoxId).user(tenantId).electionEvent(electionEventId)
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_ERR_DESC, "ballot box is not empty")
                    .additionalInfo(ElectionInformationLogConstants.INFO_BALLOT_BOX_ID, ballotBoxId).createLogInfo());
        }

        return validationResult;
    }
    
    @Override
    public void writeEncryptedBallotBox(final OutputStream stream, final String tenantId, final String electionEventId,
            final String ballotBoxId, final boolean test) throws IOException {
        try {
            ballotBoxService.writeEncryptedBallotBox(stream, tenantId, electionEventId, ballotBoxId, test);
            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.BALLOT_BOX_EXPORT_READY)
                    .objectId(ballotBoxId).user(tenantId).electionEvent(electionEventId)
                    .additionalInfo(ElectionInformationLogConstants.INFO_BALLOT_BOX_TEST, Boolean.toString(test))
                    .createLogInfo());
        } catch (IOException e) {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.BALLOT_BOX_EXPORT_FAILED)
                    .objectId(ballotBoxId).user(tenantId).electionEvent(electionEventId)
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_ERR_DESC, e.getMessage())
                    .additionalInfo(ElectionInformationLogConstants.INFO_BALLOT_BOX_ID, ballotBoxId).createLogInfo());
            throw e;
        }
    }

    /**
     * Check if a ballot box is a test ballot box
     *
     * @param tenantId
     *            - tenant identifier
     * @param electionEventId
     *            - election event identifier
     * @param ballotBoxId
     *            - ballot box identifier
     * @return if the ballot box is a test ballot box or not
     * @throws ResourceNotFoundException
     */
    @Override
    public boolean checkIfTest(String tenantId, String electionEventId, String ballotBoxId)
            throws ResourceNotFoundException {

        boolean isTest = ballotBoxService.checkIfTest(tenantId, electionEventId, ballotBoxId);
        secureLoggerWriter.log(Level.INFO,
            new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.BALLOT_BOX_EXPORT_REQUESTED)
                .objectId(ballotBoxId).user(tenantId).electionEvent(electionEventId)
                .additionalInfo(ElectionInformationLogConstants.INFO_BALLOT_BOX_TEST, Boolean.toString(isTest))
                .createLogInfo());
        return isTest;
    }
    
    @Override
    public void blockBallotBoxes(String tenantId, String electionEventId,
            Collection<EntityId> ballotBoxIds)
            throws ResourceNotFoundException, EntryPersistenceException {
        ballotBoxService.blockBallotBoxes(tenantId, electionEventId, ballotBoxIds);
    }

    @Override
    public void unblockBallotBoxes(String tenantId, String electionEventId,
            Collection<EntityId> ballotBoxIds)
            throws ResourceNotFoundException, EntryPersistenceException {
        ballotBoxService.unblockBallotBoxes(tenantId, electionEventId, ballotBoxIds);
    }

    /**
     * Check if ballot box is blocked
     *
     * @param tenantId
     *            - tenant identifier
     * @param electionEventId
     *            - election event identifier
     * @param ballotBoxId
     *            - ballot box identifier
     * @throws ResourceNotFoundException
     */
    @Override
    public boolean isBlockedBallotBox(String tenantId, String electionEventId, String ballotBoxId)
            throws ResourceNotFoundException {
        boolean isBlocked = ballotBoxService.isBlockedBallotBox(tenantId, electionEventId, ballotBoxId);

        secureLoggerWriter.log(Level.INFO,
            new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.BALLOT_BOX_STATUS_REQUESTED)
                .objectId(ballotBoxId).user(tenantId).electionEvent(electionEventId)
                .additionalInfo("status", isBlocked ? "BLOCKED" : "UNBLOCKED").createLogInfo());
        return isBlocked;
    }

    /**
     * Validates if ballot box is not blocked
     *
     * @param tenantId
     *            - tenant identifier
     * @param electionEventId
     *            - election event identifier
     * @param ballotBoxId
     *            - ballot box identifier
     * @return
     */
    @Override
    public ValidationError validateBallotBoxNotBlocked(String tenantId, String electionEventId, String ballotBoxId)
            throws ResourceNotFoundException {

        try {
            final ValidationError validationError =
                ballotBoxService.validateBallotBoxNotBlocked(tenantId, electionEventId, ballotBoxId);

            if (validationError.getValidationErrorType().equals(ValidationErrorType.BLOCKED_BALLOT_BOX)) {

                secureLoggerWriter.log(Level.WARN,
                    new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.BALLOT_BOX_BLOCKED)
                        .objectId(ballotBoxId).electionEvent(electionEventId)
                        .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                        .additionalInfo(ElectionInformationLogConstants.INFO_BALLOT_BOX_ID, ballotBoxId)
                        .createLogInfo());
            }

            return validationError;
        } catch (ResourceNotFoundException e) {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.BALLOT_BOX_NOT_FOUND)
                    .objectId(ballotBoxId).electionEvent(electionEventId)
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_ERR_DESC, e.getMessage())
                    .additionalInfo(ElectionInformationLogConstants.INFO_BALLOT_BOX_ID, ballotBoxId)
                    .additionalInfo(ElectionInformationLogConstants.INFO_BALLOT_BOX_ID, ballotBoxId).createLogInfo());
            throw e;
        }

    }
}
