// the coordinator of the application
void coordinator(void)
{
	// we need to establish what power is used in the hypercube this
	// tells us how many communication directions we have
	int power = hypercubePower(world_size);
	std::cout << power << std::endl;
	// an array that will house the various offsets that we need to 
	// connect with the appropriate nodes in each direction
	int comms_offsets[16];
	initArray(comms_offsets, 0, 16);
	
	// we need to determine our communication directions based on the 
	// bits in our rank
	computeDirections(comms_offsets, world_rank, power);
	for(unsigned int i = 0; i < power; i++)
	std::cout << "rank " << world_rank << " offset " << i << ": " <<
		comms_offsets[i] << std::endl;
		
	// to start the computation we need to distribute a message for
	// starting the computation in this case we will send a single
	// integer that will represent the dimension that we need to
	// communicate on. this will state which channel we need to send on
	int message = 0;
	for (unsigned int i = 0; i < power; i++)
	{
		MPI_Send(&i, 1, MPI_INT, world_rank + comms_offsets[i], 0, MPI_COMM_WORLD);
		std::cout << "rank " << world_rank << "send message to rank " << world_rank +
			comms_offsets[i] << std::endl;
	}
	
	//calculate the average of 100 random numbers
	srand(world_rank);
	int sum = randomSum();
	float average = sum / 100.f;
	std::cout << "rank " << world_rank << " average is: " << average << std::endl;
	
	// send a message to all the other nodes to tell them to sum up their averages
	for( unsigned int i = 0; i < power; i++)
	{
		MPI_Send(&i, 1, MPI_INT, world_rank + comms_offsets[i], 0, MPI_COMM_WORLD);
		std::cout << "rank " << world_rank << "send total message to rank " <<
			world_rank + comms_offsets[i] << std::endl;
	}
	
	// we need to get the averages from each direction
	float total_average = average;
	for(int message = power - 1; message >= 0; message--)
	{
		MPI_Recv(&average, 1, MPI_FLOAT, world_rank + comms_offsets[message],
			0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
		std::cout << "rank " << world_rank << " received total from " <<
			world_rank + comms_offsets[message] << std::endl;
		total_average += average;
	}
	
	// print out the overall average
	std::cout << "rank " << world_rank << " total and average: " <<
		total_average << " " << total_average / world_size << std::endl;
}
void PlaneSegmenter::update()
{
    if(!rgb_img.rows || !depth_img.rows) return;

    rgb_mutex.lock(); depth_mutex.lock();

    computeNormals();
    computeDirections();


    planes.clear();
    for(unsigned int d=0; d<directions.size();++d)
    {
        float px_avg = 0.f;
        float py_avg = 0.f;
        float pz_avg = 0.f;
        float nx_avg = 0.f;
        float ny_avg = 0.f;
        float nz_avg = 0.f;
        for(unsigned int p=0; p<directions.at(d).size(); ++p)
        {
            px_avg += directions.at(d).at(p).pos.x/directions.at(d).size();
            py_avg += directions.at(d).at(p).pos.y/directions.at(d).size();
            pz_avg += directions.at(d).at(p).pos.z/directions.at(d).size();

            nx_avg += directions.at(d).at(p).norm.x/directions.at(d).size();
            ny_avg += directions.at(d).at(p).norm.y/directions.at(d).size();
            nz_avg += directions.at(d).at(p).norm.z/directions.at(d).size();
        }
        planes.push_back(PlaneSegmenter::Point(-d,cv::Point3f(px_avg,py_avg,pz_avg), cv::Point3f(nx_avg,ny_avg,nz_avg)));
    }

//    std::cout<<"planes num: "<< planes.size() << std::endl;
    std::cerr<<"-";
    drawPlanes();
//    cv::imshow("update depth", depth_img);
    cv::imshow("update rgb", rgb_img);

    depth_mutex.unlock(); rgb_mutex.unlock();
    cv::waitKey(1);
}
// a participant in the application
void participant(void)
{
	// we need to establish what power is used in the hypercube this
	// tells us how many communication directions we have
	int power = hypercubePower(world_size);
	std::cout << power << std::endl;
	
	// an array that will house the various offsets that we need to 
	// connect with the appropriate nodes in each direction
	int comms_offsets[16];
	initArray(comms_offsets, 0, 16);
	
	// we need to determine our communication directions based on the 
	// bits in our rank
	computeDirections(comms_offsets, world_rank, power);
	for(unsigned int i = 0; i < power; i++)
		std::cout << "rank " << world_rank << " offset " << i << ": " <<
			comms_offsets[i] << std::endl;
			
	// we need to receive a message to start computation from another 
	// node and then propogate it on further
	int message = 0;
	MPI_Recv(&message, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD,
		MPI_STATUS_IGNORE);
	for (message++; message < power; message++)
	{
		MPI_Send(&message, 1, MPI_INT, world_rank + comms_offsets[message],
			0, MPI_COMM_WORLD);
		std::cout << "rank " << world_rank << " send message to rank " <<
			world_rank + comms_offsets[message] << std::endl;
	}
	
	// calculate the average of 100 random numbers
	srand(world_rank);
	int sum = randomSum();
	float average = sum / 100.f;
	std::cout << "rank " << world_rank << " average is: " << average << std::endl;
	
	// we need to get a message that will tell us to total our average
	// get this message and retain it
	// send a messafe to all the other nodes to tell them to sum up their averages
	MPI_Recv(&message, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
	for(int i = message + 1; i < power; i++)
	{
		MPI_Send(&i, 1, MPI_INT, world_rank + comms_offsets[i], 0, MPI_COMM_WORLD);
		std::cout << "rank " << world_rank << " sent total messages to rank " <<
			world_rank + comms_offsets[i] << std::endl;
	}
	
	// we need to get the averages from each direction
	float total_average = average;
	for ( int i = power - 1; i > message; i--)
	{
		MPI_Recv(&average, 1, MPI_FLOAT, world_rank + comms_offsets[i],
			0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
		std::cout << "rank " << world_rank << " received total from " << world_rank +
			comms_offsets[i] << std::endl;
		total_average += average;
	}
	
	// print out the overall average
	std::cout << "rank " << world_rank << " total and average: " <<
		total_average << " " << total_average / world_size << std::endl;
		
	// send our average onto the next node
	std::cout << "rank " << world_rank << " " << comms_offsets[message] << std::endl;
	MPI_Send(&total_average, 1, MPI_FLOAT, world_rank + comms_offsets[message], 0, MPI_COMM_WORLD);
	std::cout << "rank " << world_rank << " sent total average to rank " << world_rank + comms_offsets[message] << std::endl;
}