#include<iostream>
#include<fstream>
#include<sstream>
#include<cstdlib>
#ifdef __WIN32__
	#define EXEC_MUT "mut.exe"
	#define EXEC_SIM "sim.exe"
	#define EXEC_DEL "rm"
#else
	#define EXEC_MUT "./mut"
	#define EXEC_SIM "./sim"
	#define EXEC_DEL "rm -rf"

#endif
using namespace std;
const string exec_mut=EXEC_MUT;
const string exec_sim=EXEC_SIM;
const string exec_del=EXEC_DEL;


string original_input;
string changed_input;
string original_output;
string changed_output;
string progress;
string prob;


ofstream fout_progress;
ofstream fout_output;

string readfile(string filename) {
    ifstream t(filename.c_str());
 string str((std::istreambuf_iterator<char>(t)),
                 std::istreambuf_iterator<char>());
    return str;
}

bool diff(string file1, string file2) {
    string a=readfile(file1);
    string b=readfile(file2);
    return a==b;
}   
void mutate(string input, string output, string prob) {
    ostringstream str;
    str<<rand();
    string command=exec_mut+" "+input+" "+prob+" "+str.str()+" > " +output;
    int a=system(command.c_str());
}

string simulate(string input, string output) {
    string command=exec_sim+" "+input+" > "+output;
    int a =system(command.c_str());
    return readfile(output);
}

void print_progress(string line) {
    fout_progress<<line<<endl;
}

void print_output(string line) {
	fout_output<<line<<endl;
}

int main(int argc, char** argv) {
	srand(time(0));
    
    ostringstream oss;
    char* inputfile = argv[1];
    char* outputfile = argv[2];
    int tests = atoi(argv[3]);
    char* prb = argv[4];
    char* prefix = argv[5];
    

    oss<<inputfile;
    original_input=oss.str();
    oss.str("");

    oss<<prefix<<"_input2";
    changed_input=oss.str();
    oss.str("");

    oss<<prefix<<"_output1";
    original_output=oss.str();
    oss.str("");

    oss<<prefix<<"_output2";
    changed_output=oss.str();
    oss.str("");
    
    oss<<prefix;
    progress=oss.str();
    oss.str("");
    
    string commad(exec_del+" "+progress);
    int b=system(commad.c_str());
    
    oss<<prb;
    prob=oss.str();
    oss.str("");

    
    fout_output.open(outputfile);
    fout_progress.open(progress.c_str(),fstream::out | fstream::app);
    
    simulate(original_input,original_output);
    int correct=0;
    int lastperc=0;
    for(int i=0;i<tests;i++) {
    	mutate(original_input,changed_input,prob);
    	simulate(changed_input,changed_output);
        if(diff(original_output,changed_output)) {
            correct++;
        }
        int perc=1.0*(i+1)/tests*100;
        if(perc%5==0&&perc!=lastperc) {
        	oss<<perc;
            print_progress(oss.str());
            oss.str("");
            lastperc=perc;

        }
    }
    fout_output<<"Circuit error rate is "<<(tests-correct)<<"/"<<tests<<" = "<<1.0*(tests-correct)/tests<< " = "<<(1.0*(int)(1000*(tests-correct)/tests)/10)<<"%"<<endl;
    string command(exec_del+" "+original_output+" "+changed_input+" "+changed_output);
    int a=system(command.c_str());
}
