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

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import static java.nio.file.Files.createDirectories;
import static java.nio.file.Files.exists;
import static java.nio.file.Files.readAllBytes;
import static java.nio.file.Files.write;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;

import com.scytl.products.ov.commons.path.PathResolver;
import com.scytl.products.ov.sdm.domain.model.ballot.BallotRepository;
import com.scytl.products.ov.sdm.domain.model.generator.DataGeneratorResponse;
import com.scytl.products.ov.sdm.domain.service.BallotDataGeneratorService;
import com.scytl.products.ov.sdm.domain.service.ConfigConstants;
import com.scytl.products.ov.sdm.infrastructure.JsonConstants;

/**
 * This implementation contains a call to the configuration engine for
 * generating the ballot data.
 */
@Service
public class BallotDataGeneratorServiceImpl implements BallotDataGeneratorService {

    private final BallotRepository repository;

    private final PathResolver resolver;

    private static final Logger LOGGER = LoggerFactory.getLogger(BallotDataGeneratorServiceImpl.class);

    /**
     * Constructor.
     * 
     * @param repository
     * @param resolver
     */
    @Autowired
    public BallotDataGeneratorServiceImpl(BallotRepository repository, PathResolver resolver) {
        this.repository = repository;
        this.resolver = resolver;
    }

    /**
     * This method generates a file with the ballot content in json format.
     * Because of a temporary inconsistency between the versions of config.json
     * (the last version from the team in Athens - admin portal, has extra
     * fields than the version which is compatible with the last version of the
     * configuration engine). The file is generate in a location which for now
     * is hardcoded.
     * 
     * @see com.scytl.products.ov.sdm.domain.service.BallotDataGeneratorService#generate(String,
     *      String)
     */
    @Override
    public DataGeneratorResponse generate(String id, String electionEventId) {
        DataGeneratorResponse result = new DataGeneratorResponse();

        // basic validation of input
        if (StringUtils.isEmpty(id)) {
            result.setSuccessful(false);
            return result;
        }

        // read the ballot from the database
        String json = repository.find(id);
        // simple check if there is a voting card set data returned
        if (JsonConstants.JSON_EMPTY_OBJECT.equals(json)) {
            result.setSuccessful(false);
            return result;
        }
        byte[] bytes = json.getBytes(StandardCharsets.UTF_8);

        Path file = resolver.resolve(ConfigConstants.CONFIG_FILES_BASE_DIR).resolve(electionEventId)
            .resolve(ConfigConstants.CONFIG_DIR_NAME_ONLINE)
            .resolve(ConfigConstants.CONFIG_DIR_NAME_ELECTIONINFORMATION)
            .resolve(ConfigConstants.CONFIG_DIR_NAME_BALLOTS).resolve(id)
            .resolve(ConfigConstants.CONFIG_FILE_NAME_BALLOT_JSON);
        try {
            createDirectories(file.getParent());
            // ballot.json must not be written for each ballot box from the
            // ballot because already working voting card generator can read
            // corrupted content, thus ballot.json must be written only once.
            // Write ballot.json only if the file does not exist or has a
            // different content. The content is pretty small so it is possible
            // compare everything in memory. Synchronized block protects the
            // operation from a concurrent call, because services in Spring are
            // normally singletons.
            synchronized (this) {
                if (!exists(file) || !Arrays.equals(bytes, readAllBytes(file))) {
                    write(file, bytes);
                }
            }
        } catch (IOException e) {
            LOGGER.error("Failed to write ballot to file.", e);
            result.setSuccessful(false);
        }
        return result;
    }

    @Override
    public void cleanAll(String electionEventId) {
        Path ballotsPath = resolver.resolve(ConfigConstants.CONFIG_FILES_BASE_DIR).resolve(electionEventId)
            .resolve(ConfigConstants.CONFIG_DIR_NAME_ONLINE)
            .resolve(ConfigConstants.CONFIG_DIR_NAME_ELECTIONINFORMATION)
            .resolve(ConfigConstants.CONFIG_DIR_NAME_BALLOTS);
        
        if (!exists(ballotsPath))
            throw new IllegalStateException("Ballot files have not been generated yet");

        File[] ballotPath = ballotsPath.toFile().listFiles();

        for (File ballotFolder : ballotPath) {
            if (ballotFolder.isDirectory()) {
                Path file = ballotFolder.toPath().resolve(ConfigConstants.CONFIG_FILE_NAME_BALLOT_JSON);
                try {
                    Files.deleteIfExists(file);    
                } catch (IOException e) {
                    LOGGER.error("Failed to delete ballot file.", e);
                }
            }
        }
    }
}