/*
 * 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 javax.json.JsonObject;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;

import com.scytl.products.ov.commons.path.PathResolver;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.sdm.domain.model.electionevent.ElectionEventRepository;
import com.scytl.products.ov.sdm.domain.model.generator.DataGeneratorResponse;
import com.scytl.products.ov.sdm.domain.service.ConfigConstants;
import com.scytl.products.ov.sdm.domain.service.EncryptionParametersDataGeneratorService;
import com.scytl.products.ov.sdm.infrastructure.JsonConstants;

/**
 * This implementation reads the election event from database and creates a file on the disk with the encryption parameters.
 */
@Service
public class EncryptionParametersDataGeneratorServiceImpl implements EncryptionParametersDataGeneratorService {

	// The name of the json parameter encryption parameters.
	private static final String JSON_PARAM_NAME_ENCRYPTION_PARAMETERS = "encryptionParameters";

	@Autowired
	private PathResolver pathResolver;

	@Autowired
	private ElectionEventRepository electionEventRepository;

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

	/**
	 * This method generates the file with the encryption parameters used in the system. They are read from the election
	 * event as json.
	 * 
	 * @see com.scytl.products.ov.sdm.domain.service.EncryptionParametersDataGeneratorService#generate(java.lang.String)
	 */
	@Override
	public DataGeneratorResponse generate(String electionEventId) {
		DataGeneratorResponse result = new DataGeneratorResponse();

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

		// just in case create the path where to store the file
		Path configPath = pathResolver.resolve(ConfigConstants.CONFIG_FILES_BASE_DIR).resolve(electionEventId);
		try {
			makePath(configPath);
		} catch (IOException e2) {
			LOGGER.error("", e2);
			result.setSuccessful(false);
			return result;
		}

		// hopefully there is data for the electionEventId, because if not, just get out of here!
		String electionEventAsJson = electionEventRepository.find(electionEventId);
		if (JsonConstants.JSON_EMPTY_OBJECT.equals(electionEventAsJson)) {
			result.setSuccessful(false);
			return result;
		}

		// now parse the json and get what we need
		JsonObject encryptionParameters =
			getJsonObject(electionEventAsJson).getJsonObject(JsonConstants.JSON_ATTRIBUTE_NAME_SETTINGS).getJsonObject(
				JSON_PARAM_NAME_ENCRYPTION_PARAMETERS);

		// write them in a file on the disk
		Path configPropertiesPath =
			configPath.resolve(com.scytl.products.ov.constants.Constants.ENCRYPTION_PARAMS_FILENAME);
		try (OutputStream output = getOutputStream(configPropertiesPath)) {
			output.write(encryptionParameters.toString().getBytes());
			output.flush();
		} catch (IOException e) {
			LOGGER.error("", e);
			result.setSuccessful(false);
			return result;
		}
		return result;
	}

	/**
	 * Creates all the directories from the path if they don't exist yet. This is wrapper over a static method in order to
	 * make the class testable.
	 * 
	 * @param path The path to be created.
	 * @return a Path representing the directory created.
	 * @throws IOException in case there is a I/O problem.
	 */
	Path makePath(Path path) throws IOException {
		return Files.createDirectories(path);
	}

	/**
	 * Returns a JsonObject for the given json. It is a wrapper over a static method in order to make the class testable.
	 * 
	 * @param json The json to be converted into a JsonObject.
	 * @return a JsonObject for the given json.
	 */
	JsonObject getJsonObject(String json) {
		return JsonUtils.getJsonObject(json);
	}

	/**
	 * Returns an OutputStream object for the given path. It is a wrapper over a static method in order to make the class
	 * testable.
	 * 
	 * @param path The path for which to create an OutputStream.
	 * @return an OutputStream for the given path.
	 * @throws IOException in case there is a I/O problem with the creation of the OutputStream.
	 */
	OutputStream getOutputStream(Path path) throws IOException {
		return Files.newOutputStream(path);
	}
}
