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

import static java.util.Collections.singletonMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

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

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
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.BallotBox;
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.infrastructure.AbstractEntityRepository;
import com.scytl.products.ov.sdm.infrastructure.DatabaseManager;
import com.scytl.products.ov.sdm.infrastructure.JsonConstants;

/**
 * Implementation of operations with ballot box.
 */
@Repository
public class BallotBoxRepositoryImpl extends AbstractEntityRepository
        implements BallotBoxRepository {

    // The name of the json parameter ballot.
    private static final String JSON_NAME_PARAM_BALLOT = "ballot";

    // the name of the ballot alias
    private static final String JSON_NAME_PARAM_BALLOT_ALIAS =
        "ballotAlias";

    @Autowired
    @Lazy
    BallotRepository ballotRepository;

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

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

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

        JsonObject ballotBox = JsonUtils.getJsonObject(ballotBoxAsJson);
        return ballotBox.getJsonObject(JSON_NAME_PARAM_BALLOT)
            .getString(JsonConstants.JSON_ATTRIBUTE_NAME_ID);
    }

    @Override
    public List<String> listAliases(final String ballotId)
            throws DatabaseException {
        String sql = "select alias from " + entityName()
            + " where ballot.id = :ballotId";
        Map<String, Object> parameters =
            singletonMap("ballotId", ballotId);
        List<ODocument> documents;
        try {
            documents = selectDocuments(sql, parameters, -1);
        } catch (OException e) {
            throw new DatabaseException("Failed to list aliases.", e);
        }
        List<String> aliases = new ArrayList<>(documents.size());
        for (ODocument document : documents) {
            aliases.add(document.field("alias", String.class));
        }
        return aliases;
    }

    /**
     * @see com.scytl.products.ov.sdm.domain.model.ballotbox.BallotBoxRepository#updateRelatedBallotAlias(java.util.List)
     */
    @Override
    public void updateRelatedBallotAlias(final List<String> ballotBoxIds) {
        try {
            for (String id : ballotBoxIds) {
                ODocument ballotBox = getDocument(id);
                String ballotId =
                    ballotBox.field("ballot.id", String.class);
                List<String> aliases =
                    ballotRepository.listAliases(ballotId);
                // should be only one alias. to maintain compatibility with FE,
                // save
                // as comma-separated string
                ballotBox.field(JSON_NAME_PARAM_BALLOT_ALIAS,
                    StringUtils.join(aliases, ","));
                saveDocument(ballotBox);
            }
        } catch (OException e) {
            throw new DatabaseException(
                "Failed to update related ballot aliases.", e);
        }
    }

    @Override
    public String findByElectoralAuthority(final String id) {
        Map<String, Object> attributes = singletonMap(
            JsonConstants.JSON_STRUCTURE_NAME_ELECTORAL_AUTHORITY_ID, id);
        return list(attributes);
    }

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

    @Override
    protected String entityName() {
        return BallotBox.class.getSimpleName();
    }
}
