/*
 * 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.au.services.domain.service.challenge;

import java.util.Map;
import java.util.TreeMap;

import javax.ejb.Stateless;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.au.services.domain.model.challenge.ChallengeInformation;
import com.scytl.products.ov.au.services.domain.model.validation.ChallengeInformationValidation;
import com.scytl.products.ov.au.services.infrastructure.log.AuthenticationLogConstants;
import com.scytl.products.ov.au.services.infrastructure.log.AuthenticationLogEvents;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.validation.CryptographicOperationException;
import com.scytl.products.ov.commons.logging.service.I18nLoggerMessages;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.validation.ValidationResult;

/**
 * This service provides the functionality to validate a challenge information based on the predefined rules.
 */
@Stateless
public class ChallengeInformationValidationService {

    private static final I18nLoggerMessages I18N = I18nLoggerMessages.getInstance();
    
    private final Map<Integer,ChallengeInformationValidation> validations = new TreeMap<>();
    
    private static final Logger LOG = LoggerFactory.getLogger("std");

	@Inject
	private TrackIdInstance trackId;

	@Inject
	private SecureLoggingWriter secureLoggerWriter;
	
	@Inject
    @Any
	void setValidations(Instance<ChallengeInformationValidation> instance) {
	    for (ChallengeInformationValidation validation : instance) {
	        validations.put(validation.getOrder(), validation);
	    }
	}

	/**
	 * This method validates an challenge information by applying the set of validation rules.
	 *
	 * @param tenantId - the tenant identifier.
	 * @param electionEventId - the election event identifier.
	 * @param votingCardId - the voting card identifier.
	 * @param challengeInformation - the challenge information to be validated.
	 * @return an AuthenticationTokenValidationResult containing the result of the validation.
	 * @throws ResourceNotFoundException
	 * @throws CryptographicOperationException
	 */
	public ValidationResult validate(String tenantId, String electionEventId, String votingCardId,
									 ChallengeInformation challengeInformation) throws ResourceNotFoundException, CryptographicOperationException {
		LOG.info(I18N.getMessage("ChallengeInformationValidationService.validate.start"));

		// result of validation
		ValidationResult validationResult = new ValidationResult();
		validationResult.setResult(true);

		// execute validations
		for (ChallengeInformationValidation validation : validations.values()) {
			if (validation.execute(tenantId, electionEventId, votingCardId, challengeInformation)) {
				LOG.info(I18N.getMessage("ChallengeInformationValidationService.validate.validationSuccess"),
					validation.getClass().getSimpleName());
			} else {
				LOG.info(I18N.getMessage("ChallengeInformationValidationService.validate.validationFail"),
					validation.getClass().getSimpleName());
				validationResult.setResult(false);
				break;
			}
		}

		LOG.info(I18N.getMessage("ChallengeInformationValidationService.validate.resultOfValidation"),
			validationResult.isResult());

		// challenge response validated
		if (validationResult.isResult()) {
			secureLoggerWriter.log(Level.INFO,
				new LogContent.LogContentBuilder().logEvent(AuthenticationLogEvents.CHALLENGE_RESPONSE_VALIDATED)
					.objectId(votingCardId).user(votingCardId).electionEvent(electionEventId)
					.additionalInfo(AuthenticationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
					.additionalInfo(AuthenticationLogConstants.INFO_CREDENTIAL_ID, challengeInformation.getCredentialId())
					.createLogInfo());
		}

		return validationResult;
	}
}
