#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "mpi.h"

#include "mpi_bnc.h"

#define DIM 5

int main(int argc, char *argv[])
{
	long int i, j, local_dim;
	DMatrix c, x, b;
	DMatrix local_c[10], local_x[10], local_b[10];

	long int d_dim[10];
	int myrank, num_procs;

	MPI_Init(&argc, &argv);
	MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
	MPI_Comm_size(MPI_COMM_WORLD, &num_procs);

	local_dim = _mpi_divide_dim(d_dim, DIM, num_procs);
	if(myrank == 0)
	{
		x = init_dmatrix(num_procs * local_dim, num_procs * local_dim);
		b = init_dmatrix(num_procs * local_dim, num_procs * local_dim);
		c = init_dmatrix(num_procs * local_dim, num_procs * local_dim);
	
		for(i = 0; i < DIM; i++)
		{
			for(j = 0; j < DIM; j++)
			{
				set_dmatrix_ij(x, i, j, (double)(i * DIM + j + 1));
				set_dmatrix_ij(b, i, j, (double)(DIM * DIM - (i * DIM + j)));
			}
		}
	}

	_mpi_init_dmatrix(local_c, d_dim, DIM, MPI_COMM_WORLD);
	_mpi_init_dmatrix(local_x, d_dim, DIM, MPI_COMM_WORLD);
	_mpi_init_dmatrix(local_b, d_dim, DIM, MPI_COMM_WORLD);

	_mpi_divide_dmatrix(local_c, d_dim, c, MPI_COMM_WORLD);
	_mpi_divide_dmatrix(local_x, d_dim, x, MPI_COMM_WORLD);
	_mpi_divide_dmatrix(local_b, d_dim, b, MPI_COMM_WORLD);

	for(i = 0; i < num_procs; i++)
		add_dmatrix(local_c[i], local_x[i], local_b[i]);

	_mpi_collect_dmatrix(c, d_dim, local_c, MPI_COMM_WORLD);

	_mpi_free_dmatrix(local_c, MPI_COMM_WORLD);
	_mpi_free_dmatrix(local_x, MPI_COMM_WORLD);
	_mpi_free_dmatrix(local_b, MPI_COMM_WORLD);
	
	if(myrank == 0)
	{
		print_dmatrix(c);

		free_dmatrix(x);
		free_dmatrix(b);
		free_dmatrix(c);
	}
	MPI_Finalize();

	return EXIT_SUCCESS;
}

