#include <boost/thread.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "row.hpp"
#include "sort_algorithms.hpp"
using namespace std;

int idx(int i, int j, int n) {
	return i*n+j;
}

void fill_worker(double *a, int n, int k, int tid) {
	int base=n/k;
	int rem=n%k;
	int start_row=tid*base;
	int end_row=start_row+base;
	if (tid==k-1) {
		end_row+=rem;
	}
	for (int i=start_row;i<end_row;i++) {
		for (int j=0;j<n;j++) {
			a[idx(i,j,n)]=(double) rand()/(RAND_MAX*1.0);
		}
	}
}

void print_worker(double *a, int n, int k, int tid) {
	int base=n/k;
	int rem=n%k;
	int start_row=tid*base;
	int end_row=start_row+base;
	if (tid==k-1) 
		end_row+=rem;
	for (int i=start_row;i<end_row;i++) {
		for (int j=0;j<n;j++) {
			cout << a[idx(i,j,n)] << " ";
		}
		cout << endl;
	}
}

void sort_worker(double *a, int n , int k , int tid) {
	int base=n/k;
	int rem=n%k;
	int start_row=tid*base;
	int end_row=start_row+base;
	if (tid==k-1) 
		end_row+=rem;
	for (int i=start_row;i<end_row;i++) {
		double *row_ptr=&a[idx(i,0,n)];
		row<double> r(row_ptr,n);
		bubble_sort(r);
		for (int j=0;j<n;j++) {
			row_ptr[j]=r[j];
		}
	}
	
}
void fill_matrix_parallel(double *a, int n, int k) {
	boost::thread_group tg;
	for (int tid=0;tid<k;tid++) {
		tg.create_thread(boost::bind(fill_worker,a,n,k,tid));
	}
	tg.join_all();
}

void  print_matrix_parallel(double *a, int n , int k) {
	boost::thread_group tg;
	for (int tid=0;tid<k;tid++) {
		tg.create_thread(boost::bind(print_worker,a,n,k,tid));
	}
	tg.join_all();
}

void sort_rows_parallel(double *a, int n, int k) {
	boost::thread_group tg;
	for (int tid=0; tid<k;tid ++) {
		tg.create_thread(boost::bind(sort_worker,a,n,k,tid));
	}
	tg.join_all();
}

int main() {
	srand(time(0));
	int n=8;
	int fill_threads=3;
	int print_threads=2;
	int sort_threads=4;
	double *a=new double[n*n];
	fill_matrix_parallel(a,n,fill_threads);
	sort_rows_parallel(a,n,sort_threads);
	print_matrix_parallel(a,n,print_threads);
	delete [] a;
	return 0;
}
