#include<iostream>
#include<boost/thread.hpp>
#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;
    
}
