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

#include "ProlificScheduler.hpp"
#include "CollectiveScheduler.hpp"
#include "SortTensorTask.hpp"

using namespace std;

void print_tensor(int* B,int n,int k){
	for(int slice=0; slice<k; slice++){
		cout<< "Selida : " << slice << "\n";
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++) {
				cout << setw(5) << B[slice *(n*n) + i*n +j] << " " ;
			}
			cout << "\n";
		}
	}
}

//Gia na min pairnei etoimo pinaka o scheduler pou trexei 2os
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,k;

	cout<<"Gia 3diastato pinaka: \n";
	cout<<"Dwse megethos tou nxn pinaka: ";
	cin>>n;
	cout<<"Dwse arithmo 'selidwn' (bathos) k: ";
	cin>> k;

	if(n<=0 || k<=0){
		cerr<< "Sfalma, mi thetikes times ";
		return 1;
	}

	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);

	SortTensorTask task(B,n,k);

	//Prolific
	cout<<"Prolific scheduler me " << k << "ergates(diergasies) \n";
	shuffle_tensor(B,total_elements);

	if(n<=10 && k<=8){
		cout<< "Arxika o pinakas : \n";
		print_tensor(B,n,k);
	}

	ProlificScheduler prolific(k);
	
	auto start_p = chrono::high_resolution_clock::now();
	prolific.execute_task(&task);
	auto end_p = chrono::high_resolution_clock::now();
	
	chrono::duration<double, milli> elapsed_p = end_p - start_p;
	
	if(n<=10 && k<=8){
		cout<< "Taksinomimenos pinakas me Prolific : \n";
		print_tensor(B,n,k);
	}

	//Collective
	//Ta dentra mou mesa
	int levels=ceil(log2(k+1));
	int collective_workers = pow(2,levels) - 1;

	cout << "Collective scheduler me "<< collective_workers << "ergates \n";
	shuffle_tensor(B,total_elements);

	CollectiveScheduler collective(levels);

	auto start_c = chrono::high_resolution_clock::now();
	collective.execute_task(&task);
	auto end_c = chrono::high_resolution_clock::now();

	chrono ::duration<double,milli> elapsed_c=end_c - start_c;

	if(n<=10 && k<=8){
		cout<< "Taksinomimenos me collective: \n";
		print_tensor(B,n,k);
	}

	cout<<"Xronos taksinomisis me prolific: " <<elapsed_p.count() <<" ms \n";
	cout << "Xronos taksinomisis me collective: " << elapsed_c.count() << " ms \n";

	munmap(B,total_elements*sizeof(int));

	return 0;
	
		
}
