package rabbit;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import converters.JsonConverter;
import datamodel.*;
import executors.CommandExecutor;
import mongo.MongoManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.http.HttpStatus;

import java.io.IOException;

/**
 * Received messages that come from a queue
 */
public class Receiver {
    private static final Logger logger = LoggerFactory.getLogger(Receiver.class);
    private Channel channel;
    private QueueingConsumer consumer;
    private Connection connection;
    private MongoManager mm;
    /**
     * Set parameters for RabbitMQ receiver
     */
    public Receiver() {
        RabbitMqConfig rmqConf = new RabbitMqConfig();
        String hostName = rmqConf.getHost();
        String queueName = rmqConf.getReceiveQueue();
        String userName = rmqConf.getUsername();
        String password = rmqConf.getPassword();
        
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(hostName);
        factory.setUsername(userName);
        factory.setPassword(password);

        try {
            connection = factory.newConnection();
            channel = connection.createChannel();

            /*
            * a client can be assigned only 1 message, the next message will be
            * assigned only after it finishes processing the first message
            */
            int prefetchCount = 1;

            channel.basicQos(prefetchCount);
            boolean durable = true;
            channel.queueDeclare(queueName, durable, false, false, null);
            consumer = new QueueingConsumer(channel);
            boolean autoAck = false;
            channel.basicConsume(queueName, autoAck, consumer);

            // create connection for database
            mm = new MongoManager();

        }
        catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * Listen for messages
     */
    public void startReceiving() {
        Sender sender = new Sender();
        while (true) {
            try {
                //Monitoring scannerMonit = new Monitoring();
                //scannerMonit.startMonitoring();

                QueueingConsumer.Delivery delivery = consumer.nextDelivery();
                String message = new String(delivery.getBody());
                Job job = JsonConverter.jsonStringToObject(message, Job.class);
                MDC.put("jobId", job.getId());
                logger.info("Received message over queue.");

                String measurementString = mm.pullJsonById(job.getId());

                Measurement measurement = JsonConverter.jsonStringToObject(measurementString, Measurement.class);

                // start monitoring activities
                //Monitoring nmapMonit = new Monitoring();
                //nmapMonit.startMonitoring();


                CommandCreator commandCreator = new CommandCreator();
                String commandToExecute = commandCreator.createCommand(measurement.getUserCommand());

                CommandPidAndResults results  = executeCommand(commandToExecute);

                String[] tocUserCommand = measurement.getUserCommand().split("\\s+");
                if (tocUserCommand[0].equals("availability")) {
                    ApplicationStatusChecker applicationStatusChecker = new ApplicationStatusChecker();
                    HttpStatus httpStatus =  applicationStatusChecker.checkStatus(tocUserCommand[1]);
                    results.setCommandResults(results.getCommandResults() + "HttpStatus : " + httpStatus);
                }

                // finalize monitoring activities
                //nmapMonit.stopMonitoring();
                //nmapMonit.saveResultsInDb(job.getId(), results.getCommadnPid(), mm, "nmap");

                String xmlResult = results.getCommandResults();
                mm.updateJsonWithId(job.getId(), "rawResult", xmlResult);

                // send job over the queue
                sender.send(job);
                //scannerMonit.stopMonitoring();
                //scannerMonit.saveResultsInDb(job.getId(), Long.parseLong(getPid()), mm, "scanner");

                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
                logger.info("Sent message over queue.");
                MDC.remove("jobId");
            } catch (InterruptedException e) {
                logger.error(e.getMessage(), e);
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    /**
     * Start a command with received message
     *
     * @param command terminal command that will be executed
     * @throws InterruptedException
     */
    private CommandPidAndResults executeCommand(String command) throws InterruptedException {
        CommandExecutor cmd = new CommandExecutor();
        return cmd.execute(new Command(command));
    }

    /**
     * Obtain the PID of the component
     *
     * @return PID of the component
     */
    private String getPid() {
        String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
        return processName.split("@")[0];
    }

    /**
     * Close receiving connection.
     */
    public void closeConnection() {
        try {
            // close connection to databse
            mm.closeConnection();

            // close conection to message queue
            if (connection.isOpen()) {
                connection.close();
            }
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }

}

@@ -3033,17 +3033,16 @@
 ing();%0A%0A
-%0A
         
@@ -3060,237 +3060,76 @@
 mand
-Creator commandCreator = new CommandCreator();%0A                String commandToExecute = commandCreator.createCommand(measurement.getUserCommand());%0A%0A                CommandPidAndResults results  = executeCommand(commandToExecute
+PidAndResults results  = executeCommand(measurement.getUserCommand()
 );%0A%0A
@@ -3402,26 +3402,22 @@
         
-HttpStatus
+String
  httpSta
@@ -3559,26 +3559,8 @@
 () +
- %22HttpStatus : %22 +
  htt
@@ -4561,17 +4561,21 @@
 Start a 
-c
+userC
 ommand w
@@ -4616,17 +4616,21 @@
  @param 
-c
+userC
 ommand t
@@ -4637,17 +4637,21 @@
 erminal 
-c
+userC
 ommand t
@@ -4770,17 +4770,21 @@
 (String 
-c
+userC
 ommand) 
@@ -4813,16 +4813,532 @@
 ption %7B%0A
+%0A        String%5B%5D tocUserCommand = userCommand.split(%22%5C%5Cs+%22);%0A        if (tocUserCommand%5B0%5D.equals(%22availability%22)) %7B%0A            ApplicationStatusChecker applicationStatusChecker = new ApplicationStatusChecker();%0A            String httpStatus =  applicationStatusChecker.checkStatus(tocUserCommand%5B1%5D);%0A            return new CommandPidAndResults(-1, httpStatus);%0A        %7D%0A%0A        CommandCreator commandCreator = new CommandCreator();%0A        String commandToExecute = commandCreator.createCommand(userCommand);%0A%0A
         
@@ -5428,16 +5428,25 @@
 (command
+ToExecute
 ));%0A    

Move logic for creating commands and executing decisions in executeCommand method.