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

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBException;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;

import com.scytl.product.ov.sdm.plugin.PhaseName;
import com.scytl.product.ov.sdm.plugin.Plugins;
import com.scytl.products.ov.sdm.plugin.ExecutionListenerImpl;
import com.scytl.products.ov.sdm.plugin.KeyParameter;
import com.scytl.products.ov.sdm.plugin.Parameters;
import com.scytl.products.ov.sdm.plugin.PluginSequenceResolver;
import com.scytl.products.ov.sdm.plugin.ResultCode;
import com.scytl.products.ov.sdm.plugin.SequentialExecutor;
import com.scytl.products.ov.sdm.plugin.SequentialExecutorImpl;
import com.scytl.products.ov.sdm.plugin.XmlObjectsLoader;

/**
 * This test class only 'works' in Windows and reports success for Linux, which
 * is misleading
 **/
public class SequentialExecutorTest {

    private Parameters parameters;

    ExecutionListenerImpl listener = new ExecutionListenerImpl();

    PluginSequenceResolver commands;

    Plugins plugins;

    SequentialExecutor sequentialExecutor = new SequentialExecutorImpl();

    @Before
    public void setEnv() throws IOException, JAXBException, SAXException, URISyntaxException {
        parameters = new Parameters();
        parameters.addParam(KeyParameter.EE_ALIAS.name(), "EE_159_tiebreaks");
        parameters.addParam(KeyParameter.EE_ID.name(), "8f057477a28e425ea8a70321807bf126");
        parameters.addParam(KeyParameter.SDM_PATH.name(), "C:\\\\Users\\\\lvazquez\\\\sdm");
        parameters.addParam(KeyParameter.USB_LETTER.name(), "D:");
        parameters.addParam(KeyParameter.PRIVATE_KEY.name(), "asdadad");

        plugins = XmlObjectsLoader.loadFile("/plugins_test_err.xml");
        commands = new PluginSequenceResolver(plugins);
    }

    @Test
    public void execute_command_test() throws URISyntaxException {
        List<String> commandsForPhase =
            commands.getActionsForPhaseAndOrder(PhaseName.GENERATE_PRE_VOTING_OUTPUTS.value(), 1);
        sequentialExecutor.execute(commandsForPhase, parameters, listener);
    }

    @Test
    public void when_command_invalid_action_then_error_101_test() throws Exception {
        List<String> commandsForPhase =
            commands.getActionsForPhaseAndOrder(PhaseName.GENERATE_PRE_VOTING_OUTPUTS.value(), 1);
        invoke(ResultCode.INVALID_ACTION, commandsForPhase);
    }

    private List<String> sanitize(List<String> commandsForPhase, ResultCode errorCode) throws URISyntaxException {
        List<String> sanitized = new ArrayList<>();
        for (String string : commandsForPhase) {
            sanitized.add(sanitize(string, errorCode));
        }
        return sanitized;
    }

    private String sanitize(String string, ResultCode errorCode) throws URISyntaxException {
        String absolutePath = "";
        if (ResultCode.SUCCESS.equals(errorCode)) {
            absolutePath = Paths.get(this.getClass().getResource("/success" + errorCode.value() + ".bat").toURI())
                .toFile().getAbsolutePath();
        } else {
            absolutePath = Paths.get(this.getClass().getResource("/error" + errorCode.value() + ".bat").toURI())
                .toFile().getAbsolutePath();
        }
        return absolutePath;
    }

    @Test
    public void when_command_missing_params_then_error_102_test() throws Exception {
        List<String> commandsForPhase =
            commands.getActionsForPhaseAndOrder(PhaseName.GENERATE_PRE_VOTING_OUTPUTS.value(), 2);
        invoke(ResultCode.MISSING_PARAMETER, commandsForPhase);
    }

    private void invoke(ResultCode errorCode, List<String> commandsForPhase) throws URISyntaxException {
        if (!System.getProperty("os.name").toLowerCase().contains("win")) {
            return;
        }
        commandsForPhase = sanitize(commandsForPhase, errorCode);
        sequentialExecutor.execute(commandsForPhase, parameters, listener);
        if (ResultCode.SUCCESS.equals(errorCode)) {
            Assert.assertEquals(0, listener.getError());
        } else {
            Assert.assertEquals(errorCode.value(), listener.getError());
        }
    }

    @Test
    public void when_command_param_invalid_then_error_103_test() throws Exception {
        List<String> commandsForPhase =
            commands.getActionsForPhaseAndOrder(PhaseName.GENERATE_PRE_VOTING_OUTPUTS.value(), 3);
        invoke(ResultCode.PARAMETER_NOT_VALID, commandsForPhase);
    }

    @Test
    public void when_command_filenotfound_then_error_104_test() throws Exception {
        List<String> commandsForPhase =
            commands.getActionsForPhaseAndOrder(PhaseName.GENERATE_PRE_VOTING_OUTPUTS.value(), 4);
        invoke(ResultCode.FILE_NOT_FOUND, commandsForPhase);
    }

    @Test
    public void when_error_parsing_then_error_105_test() throws Exception {
        List<String> commandsForPhase =
            commands.getActionsForPhaseAndOrder(PhaseName.GENERATE_PRE_VOTING_OUTPUTS.value(), 5);
        invoke(ResultCode.ERROR_PARSING_FILE, commandsForPhase);
    }

    @Test
    public void executeCommandTest() throws URISyntaxException, IOException, JAXBException, SAXException {

        URI uri = this.getClass().getResource("/validPlugin.xml").toURI();
        String resourcePath = uri.getPath();
        Plugins plugins = XmlObjectsLoader.unmarshal(new File(resourcePath).toPath());

        PluginSequenceResolver pluginSequence = new PluginSequenceResolver(plugins);
        List<String> commandsForPhase =
            pluginSequence.getActionsForPhase(PhaseName.GENERATE_PRE_VOTING_OUTPUTS);

        Parameters parameters = new Parameters();
        parameters.addParam(KeyParameter.EE_ALIAS.name(), "EE_159_tiebreaks");
        parameters.addParam(KeyParameter.EE_ID.name(), "8f057477a28e425ea8a70321807bf126");
        parameters.addParam(KeyParameter.SDM_PATH.name(), Paths.get(uri).getParent().toString());
        parameters.addParam(KeyParameter.USB_LETTER.name(), "D:");

        invoke(ResultCode.SUCCESS, commandsForPhase);

    }
}
