// Vaddina Prakash Rao
// (C) Copyright 2005, Chair of Telecommunications
// TU Dresden

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <stdio.h>
using namespace std;

#define SIM24 		"/root/ns-2/ns-allinone-2.28/ns-2.28/ns /root/ns-2/ns-allinone-2.28/ns-2.28/examples/backoff_test/wpan24.tcl > test.txt"
#define SIM868 		"/root/ns-2/ns-allinone-2.28/ns-2.28/ns /root/ns-2/ns-allinone-2.28/ns-2.28/examples/backoff_test/wpan868.tcl > test.txt"
#define RESULTS 	"awk -f avg_throughput.awk wpan.tr"

// DO YOU WISH TO ADD SUPPORT FOR MORE PARAMETERS ? INCREMENT THIS VALUE BY THE NUMBER OF NEWLY ADDED PARAMETERS
#define	NUM_OF_STATS 11

#define NUM_OF_DROPS 19

void ns_path();
void cbrgen(string, int);
int num_of_sims();
int num_of_points();
int max_sims();
void change_seed(int);
void print_sim(int);
void change_datarate(int);
string CURRENT_DATARATE;
string CURRENT_FILENAME = "traffic";
string TECH;

vector<string> vecArray1;
string NS;

int main(int argc, char *argv[])
{
    int i, q, pos, sims, points;
    ofstream out, out1;
    ifstream in;
    string temp1;
    vector<string>::iterator ptr;
    
    if (argc != 2)
	{
	    cout << "Error !! Insufficient or Excessive parameters." << endl;
	    exit(EXIT_FAILURE);
	}
    
    if ((strcmp(*(argv+1),"24")!=0) && (strcmp(*(argv+1),"868")!=0))
	{
	    cout << *(argv+1) << endl;
	    cout << "Error !! Unrecognised parameters" << endl;
	    exit(EXIT_FAILURE);
	}
    else
	TECH = *(argv+1);
    
    // Check if there is an error in opening the files, performance.txt and parameters.txt.
    out.open("performance.txt", ios::trunc);
    if (!out)
	{
	    cout << endl << "Error Opening File, \"performance.txt\"" << "\n\n";
	    exit(EXIT_FAILURE);
	}
    
    out1.open("drops.txt", ios::trunc);
    if (!out1)
	{
	    cout << endl << "Error Opening File, \"drops.txt\"" << "\n\n";
	    exit(EXIT_FAILURE);
	}

    in.open("parameters.txt");
    if (!in)
	{
	    cout << endl << "Error Opening File, \"parameters.txt\"" << "\n\n";
	    exit(EXIT_FAILURE);
	}
    // Check if the file, parameters.txt is empty.
    else if (!getline(in, temp1))
	{
	    cout << "The file \"pparameters.txt\" is empty. The program will now terminate" << endl;
	    exit(EXIT_FAILURE);
	}
	
    // Read the file, parameters.txt. Exclude the comments and empty lines.
    while(getline(in, temp1, '\n'))
	{
	    pos = temp1.find("#", 0);
	    if (pos == 0)
		continue;
	    else if (temp1.length() == 0)
		continue;
	    else
	        vecArray1.push_back(temp1);
	}
    
    // Create the backup directory for the traffic files. Neglect the warning message if the directory already exists.
    system ("mkdir dir_traffic");
    
    ns_path();
    sims = max_sims();
    points = num_of_points();
    cout << "Number of points: " << points << endl;
    cout << "Number of simulations: " << sims << endl;
    cout << "Ideal number of simulations: " << num_of_sims() << endl;
    
    // Run the sumulation, the required number of times.
    for (i=0; i<points; i++)	
	{
	    change_datarate(i);
	    for (q=0; q<sims; q++)
    		{
		    cout << endl;
		    cbrgen(CURRENT_DATARATE, q);
		    change_seed(q);
		    cout << "Simulation Iteration: " << q+1 << endl;
	    
		    // While testing the program, disable the following command
		    if (TECH == "24")
			system (SIM24);
		    else if (TECH == "868")
			system (SIM868);
	    
		    // Print the iteration number in the file, performance.txt for reference. Comment it when not needed.
		    // DO NOT FORGET to change the print format in the avg_throughput.awk, if you disble this command.
		    // Also DO NOT FORGET to remove the variable 'discard' in the function, find_avg(), if the following
		    // command is disabled.
		    print_sim(q);
	    
		    // Command to generate results using the awk script. But make sure this is not already done in the 
		    // wpan.tcl script file.
		    // system (RESULTS);
		}
	}
	
    out.close();
    out1.close();
    in.close();
    
    // Remove the temporary files.
    if (remove ("current_seed.txt") == -1)
	cout << "Error deleting temporary files !!" << endl << endl;
    else
	cout << "Temporary files are deleted !!" << endl << endl;
    
    return 0;
}	

// Print the simulation iteration number.
void print_sim(int sim)
{
    ofstream out("performance.txt", ios::app);
    ofstream out1("drops.txt", ios::app);
    if (!out)
	cout << "Error opening file, \"performance.txt\"";
    else
	{
	    out << sim+1 << endl;
	    out.close();
	}	    

    if (!out1)
	cout << "Error opening file, \"drops.txt\"";
    else
	{
	    out1 << sim+1 << endl;
	    out1.close();
	}	    
}


//Function to retreive the path to the NS-2 executable. 
void ns_path()
{
    vector<string>::iterator ptr;
    bool flag = 0;
    for (ptr=vecArray1.begin(); ptr!=vecArray1.end(); ptr++)
	{
	    if (*ptr == "ns_path")
		flag = 1;
	    else if (flag == 1)
		{
		    flag = 0;
		    NS = *ptr;
		    cout << endl << "Path to the NS executable: " << NS << endl;
		    break;
		}
	}
    return;
}


// Function to change the seed of the random number generator in the script file, wpan.tcl
void change_seed(int seed)
{
    //ifstream in("wpan.tcl");
    //if (!in)
//	{
//	    cout << "Simulation script file(wpan.tcl) not found or its name changed. Please copy the file to this directory or rename the file back to wpan.tcl." << endl;
//	    exit(EXIT_FAILURE);
//	}
	
    ofstream out("current_seed.txt", ios::trunc);
    if (!out)
	{
	    cout << "Error opening file, \"current_seed.txt\"" << endl;
	    exit(EXIT_FAILURE);
	}	    
    
    out << seed+1;
    cout << "Seed value: " << seed+1 << "   ";
    
//    in.close();
    out.close();
}

//Function to generate traffic using the script file cbrgen.tcl
void cbrgen(string datarate, int seed)
{
    string fileseed, space = " ", traffic = "dir_traffic/traffic", underscore = "_";
    stringstream  ss;
    ss << seed+1;
    fileseed = ss.str();
    system("rm traffic");
    
    CURRENT_FILENAME = traffic + underscore + TECH + underscore + datarate + underscore + fileseed;

    ifstream in1("cbrgen_star.tcl");
    bool flag = 0;
    
    if (in1)
	{
	    vector<string>::iterator ptr;
	    for (ptr=vecArray1.begin(); ptr!=vecArray1.end(); ptr++)
		{	
		    if (*ptr == "cbrgen")
			flag = 1;
		    else if (flag == 1)
			{
			    flag = 0;
			    string type = *ptr;
			    string nodes = *(ptr+1);
			    string connections = *(ptr+2);
			    string starttime = *(ptr+3);
			    string timegap = *(ptr+4);
			    string rateincr = *(ptr+5);
			    string numincr = *(ptr+6);
			    string complete_path;
			    complete_path = NS + space + "cbrgen_star.tcl" + space + type + space + nodes + space + "-seed" + space + fileseed + space + connections + space + "-rate" + space + datarate + space + starttime + space + timegap + space + rateincr + space + numincr + space + ">";
			    //cout << complete_path + space + CURRENT_FILENAME << endl;
			    //cout << complete_path + space + "traffic" << endl;
			    system ((complete_path + space + CURRENT_FILENAME).c_str());
			    system ((complete_path + space + "traffic").c_str());
			    cout << endl << "New traffic file \"traffic\" created." << endl;
			    break;
			}
		}
	}
    else
	{
	    cout << endl << "ERROR !! traffic generator script file (cbrgen.tcl), not found. The simulation cannot continue. The program will now exit." << endl << endl;
	    exit(EXIT_FAILURE);
	}
    
    in1.close();
}

// Function to determine the number of times the simulation will be performed.
int num_of_sims()
{
    vector<string>::iterator ptr;
    bool flag = 0;
    string str_temp;
    int sims;
    for (ptr=vecArray1.begin(); ptr!=vecArray1.end(); ptr++)
	{	
	    if (*ptr == "num_of_simulations")
		flag = 1;
	    else if (flag == 1)
		{    
		    flag = 0;
		    str_temp = *ptr;
		    break;
		}
	}
    
    // strtol (const char *source, char *unptr, int base)
    // source - the source string which is converted to a long integer.
    // unptr - the pointer where the unrecognised part of the string is stored. Lets say a string 
    // contains a few unrecognised characters. The conversion to interger is successfully done until this
    // character is reached after which the characters are discarded and a pointer to this is returned
    // and stored in the pointer, unptr. If this pointer is NULL, no reference is stored. 
    // base - indicates the base of the integer. 0/10 - decimal, 8 - octal, 16 - Hex.
    sims = strtol(str_temp.c_str(), NULL, 0);
    //cout << "Number of simulations: " << sims << endl;
    return sims;
}


// Function to read the number of points needed to generate the results. The simulation is carried out 
// the number of times returned by this function. The difference between this function and the previous 
// function is that the previous function returns the number of iterations to be carried out to generate 
// each point in a graph. And the value returned in this function determines the number points to be 
// generated each being iterated by the value returned by the previous function. 

int num_of_points()
{
    vector<string>::iterator ptr;
    bool flag = 0;
    string str_temp;
    int points;

    for (ptr=vecArray1.begin(); ptr!=vecArray1.end(); ptr++)
	{	
	    if (*ptr == "num_of_points")
		flag = 1;
	    else if (flag == 1)
		{    
		    flag = 0;
		    str_temp = *ptr;
		    break;
		}
	}
    
    points = strtol(str_temp.c_str(), NULL, 0);
    //cout << "Number of simulations: " << sims << endl;
    return points;
}


int max_sims()
{
    vector<string>::iterator ptr;
    bool flag = 0;
    string str_temp;
    int maxsims;

    for (ptr=vecArray1.begin(); ptr!=vecArray1.end(); ptr++)
	{	
	    if (*ptr == "max_simulations")
		flag = 1;
	    else if (flag == 1)
		{    
		    flag = 0;
		    str_temp = *ptr;
		    break;
		}
	}
    
    maxsims = strtol(str_temp.c_str(), NULL, 0);
    //cout << "Number of simulations: " << sims << endl;
    return maxsims;
}

void change_datarate(int upperloop)
{
    vector<string>::iterator ptr;
    string str_temp, point;
    ofstream out("performance.txt", ios::app);
    ofstream out1("drops.txt", ios::app);
    
    // Converting the input int parameter to string type.
    // ostringstream strstream;
    // strstream << upperloop;
    // point = strstream.str();        
    
    for (ptr=vecArray1.begin(); ptr!=vecArray1.end(); ptr++)
	{
	    if (*ptr == "datarates")
		str_temp = *(ptr+upperloop+1);
	}
	
    CURRENT_DATARATE = str_temp;
    out << "datarate:" << CURRENT_DATARATE << endl;
    out1 << "datarate:" << CURRENT_DATARATE << endl;
    //cbrgen(str_temp);
    
    out.close();
    out1.close();
}




