/*
 TimeBasedPrefixLoad

 Copyright (C) 2022 by University of Southern California
 Written by ASM Rizvi<asmrizvi@usc.edu>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License,
 version 2, as published by the Free Software Foundation.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License along
 with this program; if not, write to the Free Software Foundation, Inc.,
 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 */

 /* 
 Description: This code takes inputs about the traffic, server IPs, and then generates the load in number of packets and bytes in every 5s. 
 The generated outputs represent time-based load.
 Sample command format: cat [TIMESTAMP] [SOURCE] [DATA_LENGTH] | java -jar TimeBasedPrefixLoad.java [DESTINATION_DIR] [SERVER_IPs] [START_TIMESTAMP] [END_TIMESTAMP]
 Here, START_TIMESTAMP is optional, default is the TIMESTAMP from the first standard input line, and END_TIMSTAMP is 10 mins after the START_TIMESTAMP

 Sample command:
 xzcat /B_Root_Anomaly_message_question-20210528/28/20210528-01{0,1,2,3}* | dbcol time srcip msglen | 
 java -jar TimeBasedPrefixLoad.jar /Load_attacks/load-test/ 199.9.14.182,192.228.79.143,2001:500:200::b,2001:500:84::b 1622163610.820339 1622165410.820339

 The above command will take timestamp, source IP, and message length and feed to TimeBasedPrefixLoad.jar. We also provide the destination location, 
 server IP list and start and end time stamp for counting.This code finds the number of incoming packets and bytes in every 5 seconds.

 Sample output:Generated time-wise files in DESTINATION_DIR directory.

 Sample output format:
 prefix packets bytes
 */
package timebasedprefixload;

import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

/**
 *
 * @author asmrizvi
 */
public class TimeBasedPrefixLoad {

    /**
     * @param args the command line arguments
     */
    public static void printInstruction() {
        System.out.println(" Description: This code takes inputs about the traffic, server IPs, and the generates the load in number of packets and bytes in every 5s. \n"
                + " The generated outputs represent time-based load.\n"
                + " Sample command format: cat [TIMESTAMP] [SOURCE] [DATA_LENGTH] | java -jar ParsingDdosLoad.java [DESTINATION_DIR] [SERVER_IPs] [START_TIMESTAMP] [END_TIMESTAMP]\n"
                + " Here, START_TIMESTAMP is optional, default is the TIMESTAMP from the first standard input line, and END_TIMSTAMP is 10 mins after the START_TIMESTAMP\n"
                + "\n"
                + " Sample command:\n"
                + " xzcat /B_Root_Anomaly_message_question-20210528/28/20210528-01{0,1,2,3}* | dbcol time srcip msglen | \n"
                + " java -jar ParsingDdosLoad.jar /Load_attacks/load-test/ 199.9.14.182,192.228.79.143,2001:500:200::b,2001:500:84::b 1622163610.820339 1622165410.820339\n"
                + "\n"
                + " The above command will take timestamp, source IP, and message length and feed to ParsingDdosLoad.jar. We also provide the destination location, \n"
                + " server IP list and start and end time stamp for counting.This code finds the number of incoming packets and bytes in every 5 seconds.\n"
                + "\n"
                + " Sample output:Generated time-wise files in DESTINATION_DIR directory.\n"
                + "\n"
                + " Sample output format:\n"
                + " prefix packets bytes");
    }

    public static void main(String[] args) throws IOException {
        // TODO code application logic here

        if (args.length < 2) {
            System.out.println("===============Not enough parameters to run the program=============");
            printInstruction();
            return;

        }

        final InputStreamReader isReader = new InputStreamReader(System.in);
        final BufferedReader bufReader = new BufferedReader(isReader);

        String line = "";
        double diff = 0.0;
        HashMap<String, HashMap<Integer, Long>> prefixToTimeAndCount = new HashMap<String, HashMap<Integer, Long>>();
        HashMap<String, HashMap<Integer, Double>> prefixToTimeAndLength = new HashMap<String, HashMap<Integer, Double>>();

        ArrayList<String> serverIpList = new ArrayList<String>();
        String[] serverIps = args[1].split(",");
        for (int i = 0; i < serverIps.length; i++) {
            serverIpList.add(serverIps[i]);
        }

        double lowestTime = 0.0;
        double maxTime = 0.0;

        if (args.length == 3) {
            lowestTime = Double.parseDouble(args[2]);
            maxTime = lowestTime + 600.0;
        }

        if (args.length == 4) {
            maxTime = Double.parseDouble(args[2]);
        }

        while ((line = bufReader.readLine()) != null) {
            final String[] splitted = line.split("\t");
            if (splitted.length < 3) {
                continue;
            }

            final String timeStamp = splitted[0];
            if (lowestTime == 0.0) {
                lowestTime = Double.parseDouble(timeStamp);
                maxTime = lowestTime + 600.0;
            }

            final String ip = splitted[1];

            if (ip.equals("") || ip.contains(":")) {
                continue;
            }

            if (serverIpList.contains(ip)) {
                continue;
            }

            final String prefix = ip.substring(0, ip.lastIndexOf("."));

            final double length = Double.parseDouble(splitted[2]);

            if (Double.parseDouble(timeStamp) < lowestTime || Double.parseDouble(timeStamp) >= maxTime) {
                //  System.out.println(timeStamp);
                continue;
            }

            diff = Double.parseDouble(timeStamp) - lowestTime;
            System.out.println(diff);

            int div = (int) Math.ceil(diff / 5.0);

            int modulated = div * 5;

            if (prefixToTimeAndCount.containsKey(prefix)) {
                HashMap<Integer, Long> temp = prefixToTimeAndCount.get(prefix);
                if (temp.containsKey(modulated)) {
                    temp.put(modulated, temp.get(modulated) + 1);
                } else {
                    temp.put(modulated, 1L);
                }

                prefixToTimeAndCount.put(prefix, temp);
            } else {
                HashMap<Integer, Long> temp = new HashMap<Integer, Long>();
                temp.put(modulated, 1L);
                prefixToTimeAndCount.put(prefix, temp);
            }

            if (prefixToTimeAndLength.containsKey(prefix)) {
                HashMap<Integer, Double> temp = prefixToTimeAndLength.get(prefix);
                if (temp.containsKey(modulated)) {
                    temp.put(modulated, temp.get(modulated) + length);
                } else {
                    temp.put(modulated, length);
                }

                prefixToTimeAndLength.put(prefix, temp);
            } else {
                HashMap<Integer, Double> temp = new HashMap<Integer, Double>();
                temp.put(modulated, length);
                prefixToTimeAndLength.put(prefix, temp);
            }

            //System.out.println(prefixToTimeAndCount.size());
        }

        System.out.println("Now writing!!");

        ArrayList<Integer> completedFile = new ArrayList<Integer>();
        for (String prefix : prefixToTimeAndCount.keySet()) {
            HashMap<Integer, Long> timeToCount = prefixToTimeAndCount.get(prefix);
            HashMap<Integer, Double> timeToLength = prefixToTimeAndLength.get(prefix);

            // final String DIRECTORY = "/nfs/landerR04/traces/verfploeter/broot_verfploeter/Peering/Peering_Mapping/2020/Load_attacks/";
            for (int time : timeToCount.keySet()) {
                if (!completedFile.contains(time)) {
                    FileWriter fileWriter = new FileWriter(args[0] + time + ".txt", true);
                    fileWriter.write("#fsdb prefix requests bytes");
                    fileWriter.close();
                    completedFile.add(time);
                }

                FileWriter fileWriter = new FileWriter(args[0] + time + ".txt", true);
                fileWriter.write("\n" + prefix + "\t" + timeToCount.get(time) + "\t" + timeToLength.get(time));
                fileWriter.close();
            }
        }
    }
}
