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

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.scytl.products.ov.mixnet.commons.configuration.ApplicationConfig;
import com.scytl.products.ov.mixnet.commons.configuration.file.FileBasedApplicationConfig;
import com.scytl.products.ov.mixnet.commons.configuration.locations.LocationsProvider;
import com.scytl.products.ov.mixnet.commons.exceptions.InvalidInputException;
import com.scytl.products.ov.mixnet.commons.validation.FileValidator;
import com.scytl.products.ov.mixnet.mvc.MixingController;
import com.scytl.products.ov.mixnet.mvc.VerifyingController;
import com.scytl.products.ov.mixnet.spring.MixerSpringConfig;

public class Application {

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

    /**
     * @param args
     *            The command-line arguments that are expected.
     */
    public static void main(final String[] args) throws IOException {

        final Instant start = Instant.now();

        checkParametersLength(args);

        final Path applicationConfigPath = Paths.get(args[0]);
        FileValidator.checkFile(applicationConfigPath);

        try (AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(MixerSpringConfig.class)) {

            final ApplicationConfig applicationConfig = FileBasedApplicationConfig.convertToStreamConfig(getApplicationConfig(applicationConfigPath));

            LocationsProvider locationsProvider = LocationsProvider.build(applicationConfig);

            MixingController mixingController = (MixingController) context.getBean("mixingController");
            mixingController.mix(applicationConfig, locationsProvider);

            VerifyingController verifyingController = (VerifyingController) context.getBean("verifyingController");
            verifyingController.verify(applicationConfig, locationsProvider);
        }

        final Instant end = Instant.now();
        LOG.info("Application duration was: " + Duration.between(start, end));
    }

    private static void checkParametersLength(final String[] args) {
        if (args.length != 1) {
            throw new InvalidInputException(
                    "Incorrect number of parameters. One json file is expected: sh bin/mixnet-engine.sh mixnetConfig.json");
        }
    }

    /**
     * This conversion will be done by Spring when we have a mixing webapp
     *
     * @param applicationConfigPath
     *            the path of the application config to load.
     * @return the loaded ApplicationConfig.
     * @throws InvalidInputException
     *             if there are any problems loading the application configuration.
     */
    private static FileBasedApplicationConfig getApplicationConfig(final Path applicationConfigPath) {

        try {

            final ObjectMapper mapper = new ObjectMapper();

            return mapper.readValue(applicationConfigPath.toFile(), FileBasedApplicationConfig.class);
        } catch (final IOException e) {
            throw new InvalidInputException(
                "An error occurred while attempting to read the applicationConfigPath file", e);
        }
    }
}
