#include <iostream>
#include <cstdlib>
#include <ctime>
#include <sys/mman.h>
#include <chrono>
#include <iomanip>
#include <string>
#include <cmath>

#include "ProlificScheduler.hpp"
#include "CollectiveScheduler.hpp"
#include "TestAlgorithms.hpp"

void shuffle_tensor(int* B,int total_elements){
	for(int i=0;i<total_elements; i++){
		B[i]=(rand()%2001)-1000;
	}
}

int main() {
	srand(time(0));
	int n=1000;

	std::string algo_names[] ={"Setup time","Quick","Bubble","Merge","Selection","Insertion","Enumeration"};
	int k_values[]={10,100};

	std::cout<<"Xronoi taksinomisis se ms analoga me algorithmo kai Scheduler: \n";
	std::cout<<std::left<<std::setw(15)<<"Algorithm"
		 <<std::setw(12) <<"Workers (k)"
		 <<std::setw(25) <<"Xronos Prolific (ms)"
		 <<std::setw(25) <<"Xronos Collective(ms)"<<"\n";

	for(int k:k_values){
		int total_elements=n*n*k;
		int* B = (int*) mmap(NULL, total_elements*sizeof(int), PROT_READ |PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS, -1,0);

		int levels=std::ceil(std::log2(k+1));

		for(int algo=0; algo<=6; ++algo){
			//Prolific		
			shuffle_tensor(B,total_elements);
			TestAlgorithms task_prolific(B,n,k,algo);
			ProlificScheduler prolific(k);
			
			auto start_p=std::chrono::high_resolution_clock::now();
			prolific.execute_task(&task_prolific);
			auto end_p=std::chrono::high_resolution_clock::now();
			std::chrono::duration<double,std::milli> elapsed_p = end_p -start_p;
			
			//Collective
			shuffle_tensor(B,total_elements);
			TestAlgorithms task_collective(B,n,k,algo);
			CollectiveScheduler collective(levels);
			
			auto start_c=std::chrono::high_resolution_clock::now();
			collective.execute_task(&task_collective);
			auto end_c=std::chrono::high_resolution_clock::now();
			std::chrono::duration<double,std::milli> elapsed_c = end_c - start_c;

			std::cout<<std::left<<std::setw(15) << algo_names[algo]
					    <<std::setw(12) << k
					    <<std::setw(25) << elapsed_p.count()
					    <<std::setw(25) << elapsed_c.count() << "\n";
			}

			munmap(B,total_elements*sizeof(int));
		}
	return 0;
}
