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

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

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.commons.beans.domain.model.vote.Vote;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.domain.model.rule.AbstractRule;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.commons.validation.ValidationError;
import com.scytl.products.ov.commons.beans.validation.ValidationErrorType;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBoxInformation;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBoxInformationRepository;
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;

/**
 * Rule which validates if the election is active when the vote is about to be
 * saved in the Ballot Box.
 */
@Decorator
public class ElectionDatesRuleDecorator implements AbstractRule<Vote> {

    // The name of the json parameter dateFrom.
    private static final String JSON_PARAMETER_DATE_FROM = "startDate";

    // The name of the json parameter dateTo.
    private static final String JSON_PARAMETER_DATE_TO = "endDate";

    // The name of the json parameter timeStamp.
    private static final String JSON_PARAMETER_TIMESTAMP = "timestamp";

    // The date separator
    private static final String DATE_SEPARATOR = "|";

    @Inject
    @Delegate
    private ElectionDatesRule electionDateRule;

    @Inject
    private BallotBoxInformationRepository ballotBoxInformationRepository;

    @Inject
    private SecureLoggingWriter secureLoggerWriter;

    @Inject
    private TrackIdInstance trackId;

    @Inject
    private SecureLoggerHelper secureLoggerHelper;

    private static final Logger LOG = LoggerFactory.getLogger("std");

    /**
     * This method validates whether the ballot box is still active before
     * storing the vote.
     * 
     * @param vote
     *            - The vote to be validated.
     * @return True if the vote satisfies the rule. Otherwise, false.
     */
    @Override
    public ValidationError execute(Vote vote) {
        ValidationError result = electionDateRule.execute(vote);
        if (!result.getValidationErrorType().equals(ValidationErrorType.SUCCESS)) {
            secureLog(vote, result.getValidationErrorType());
        }
        return result;
    }

    private void secureLog(Vote vote, ValidationErrorType validationErrorType) {
        try {
            String authTokenHash = secureLoggerHelper.getAuthTokenHash(vote.getAuthenticationToken());
            String voteHash = secureLoggerHelper.getVoteHash(vote);
            BallotBoxInformation ballotBoxInformation = getBallotBoxInformation(vote);
            JsonObject ballotBoxJson = JsonUtils.getJsonObject(ballotBoxInformation.getJson());
            JsonObject tokenJson = JsonUtils.getJsonObject(vote.getAuthenticationToken());
            String timeStampToken = tokenJson.getString(JSON_PARAMETER_TIMESTAMP);
            String errorMessage = "";
            if (validationErrorType.equals(ValidationErrorType.ELECTION_NOT_STARTED)) {
                errorMessage += "Election not started.";
            } else if (validationErrorType.equals(ValidationErrorType.ELECTION_OVER_DATE)) {
                errorMessage += "Election is over.";
            }
            secureLoggerWriter.log(
                Level.ERROR,
                new LogContent.LogContentBuilder()
                    .logEvent(ElectionInformationLogEvents.VOTE_OUT_OF_DATE)
                    .objectId(authTokenHash)
                    .user(vote.getVotingCardId())
                    .electionEvent(vote.getElectionEventId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_HASH_VOTE, voteHash)
                    .additionalInfo(ElectionInformationLogConstants.INFO_TIMESTAMP_AT, timeStampToken)
                    .additionalInfo(
                        ElectionInformationLogConstants.INFO_ELECTION_DATE,
                        ballotBoxJson.getString(JSON_PARAMETER_DATE_FROM) + DATE_SEPARATOR
                            + ballotBoxJson.getString(JSON_PARAMETER_DATE_TO))
                    .additionalInfo(ElectionInformationLogConstants.INFO_ERR_DESC,
                        "The vote to be stored is out of date for this ballot box." + errorMessage).createLogInfo());
        } catch (ResourceNotFoundException e) {
            LOG.error("Error writting the secure log", e);
        }
    }

    private BallotBoxInformation getBallotBoxInformation(Vote vote) throws ResourceNotFoundException {
		return ballotBoxInformationRepository.findByTenantIdElectionEventIdBallotBoxId(vote.getTenantId(),
				vote.getElectionEventId(), vote.getBallotBoxId());
    }

    /**
     * @see com.scytl.products.ov.commons.domain.model.rule.AbstractRule#getName()
     */
    @Override
    public String getName() {
        return electionDateRule.getName();
    }
}
