/*
 * 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.sdm.infrastructure.votingcardset;

import static java.util.Collections.singletonMap;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.json.JsonArray;
import javax.json.JsonObject;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.orientechnologies.common.exception.OException;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.sdm.application.exception.DatabaseException;
import com.scytl.products.ov.sdm.domain.model.ballot.BallotRepository;
import com.scytl.products.ov.sdm.domain.model.ballotbox.BallotBoxRepository;
import com.scytl.products.ov.sdm.domain.model.votingcardset.VotingCardSet;
import com.scytl.products.ov.sdm.domain.model.votingcardset.VotingCardSetRepository;
import com.scytl.products.ov.sdm.infrastructure.AbstractEntityRepository;
import com.scytl.products.ov.sdm.infrastructure.DatabaseManager;
import com.scytl.products.ov.sdm.infrastructure.JsonConstants;

/**
 * Implementation of operations with voting card set.
 */
@Repository
public class VotingCardSetRepositoryImpl extends AbstractEntityRepository implements VotingCardSetRepository {

    @Autowired
    BallotBoxRepository ballotBoxRepository;

    @Autowired
    BallotRepository ballotRepository;

    /**
     * Constructor
     *
     * @param databaseManager
     *            the injected database manager
     */
    @Autowired
    public VotingCardSetRepositoryImpl(final DatabaseManager databaseManager) {
        super(databaseManager);
    }

    @PostConstruct
    @Override
    public void initialize() throws DatabaseException {
        super.initialize();
    }

    /**
     * @see com.scytl.products.ov.sdm.domain.model.votingcardset.VotingCardSetRepository#getBallotBoxId(java.lang.String)
     */
    @Override
    public String getBallotBoxId(final String votingCardSetId) {
        String votingCardSetAsJson = find(votingCardSetId);
        // simple check if there is a voting card set data returned
        if (JsonConstants.JSON_EMPTY_OBJECT.equals(votingCardSetAsJson)) {
            return "";
        }

        JsonObject votingCardSet = JsonUtils.getJsonObject(votingCardSetAsJson);
        JsonObject ballotBox = votingCardSet.getJsonObject(JsonConstants.JSON_ATTRIBUTE_NAME_BALLOT_BOX);

        String ballotBoxId = ballotBox.getString(JsonConstants.JSON_ATTRIBUTE_NAME_ID);
        return ballotBoxId;
    }

    @Override
    public void updateRelatedBallot(final List<String> votingCardsIds) {
        try {
            for (String id : votingCardsIds) {
                String ballotBoxId = getBallotBoxId(id);
                JsonObject ballotBoxObject = JsonUtils.getJsonObject(ballotBoxRepository.find(ballotBoxId));
                String ballotBoxAlias = ballotBoxObject.getString(JsonConstants.JSON_ATTRIBUTE_NAME_ALIAS, "");
                String ballotId = ballotBoxObject.getJsonObject(JsonConstants.JSON_ATTRIBUTE_NAME_BALLOT)
                    .getString(JsonConstants.JSON_ATTRIBUTE_NAME_ID);
                JsonObject ballotObject = JsonUtils.getJsonObject(ballotRepository.find(ballotId));
                String ballotAlias = ballotObject.getString(JsonConstants.JSON_ATTRIBUTE_NAME_ALIAS, "");

                ODocument set = getDocument(id);
                set.field(JsonConstants.JSON_ATTRIBUTE_NAME_BALLOT_ALIAS, ballotAlias);
                set.field(JsonConstants.JSON_ATTRIBUTE_NAME_BALLOT_BOX_ALIAS, ballotBoxAlias);
                saveDocument(set);
            }
        } catch (OException e) {
            throw new DatabaseException("Failed to update related ballot.", e);
        }
    }

    /**
     * @see com.scytl.products.ov.sdm.domain.model.votingcardset.VotingCardSetRepository#updateRelatedVerificationCardSet(java.lang.String,
     *      java.lang.String)
     */
    @Override
    public void updateRelatedVerificationCardSet(final String votingCardSetId, final String verificationCardSetId) {
        try {
            ODocument set = getDocument(votingCardSetId);
            set.field(JsonConstants.JSON_ATTRIBUTE_NAME_VERIFICATIONCARDSETID, verificationCardSetId);
            saveDocument(set);
        } catch (OException e) {
            throw new DatabaseException("Failed to update related verification card set.", e);
        }
    }

    @Override
    public String listByElectionEvent(final String electionEventId) throws DatabaseException {
        return list(singletonMap("electionEvent.id", electionEventId));
    }

    /**
     * @see com.scytl.products.ov.sdm.infrastructure.AbstractEntityRepository#entityName()
     */
    @Override
    protected String entityName() {
        return VotingCardSet.class.getSimpleName();
    }

    @Override
    public String getVerificationCardSetId(final String votingCardSetId) {
        String votingCardSetAsJson = find(votingCardSetId);
        if (JsonConstants.JSON_EMPTY_OBJECT.equals(votingCardSetAsJson)) {
            return "";
        }

        JsonObject votingCardSet = JsonUtils.getJsonObject(votingCardSetAsJson);

        return votingCardSet.getString(JsonConstants.JSON_ATTRIBUTE_NAME_VERIFICATIONCARDSETID);
    }
    

    // get voting card set in json object format. This method assumes that there
    // is just one element as result of the
    // search.
    public JsonObject getVotingCardSetJson(final String electionEventId, final String votingCardSetId)
            throws ResourceNotFoundException {
        JsonObject votingCardSet;
        Map<String, Object> attributeValueMap = new HashMap<>();
        attributeValueMap.put(JsonConstants.JSON_STRUCTURE_NAME_ELECTION_EVENT_ID, electionEventId);
        attributeValueMap.put(JsonConstants.JSON_ATTRIBUTE_NAME_ID, votingCardSetId);
        String votingCardSetResultListAsJson = list(attributeValueMap);
        if (StringUtils.isEmpty(votingCardSetResultListAsJson)) {
            throw new ResourceNotFoundException("Voting card set not found");
        } else {
            JsonArray votingCardSetResultList = JsonUtils.getJsonObject(votingCardSetResultListAsJson)
                .getJsonArray(JsonConstants.JSON_ATTRIBUTE_NAME_RESULT);

            // Assume that there is just one element as result of the search.
            if (votingCardSetResultList != null && !votingCardSetResultList.isEmpty()) {
                votingCardSet = votingCardSetResultList.getJsonObject(0);
            } else {
                throw new ResourceNotFoundException("Voting card set not found");
            }
        }

        return votingCardSet;
    }

}
