import mpi.MPI;

public class Main {
    public static void main(String[] args) {
        MPI.Init(args);
        int rank = MPI.COMM_WORLD.Rank();
        int size = MPI.COMM_WORLD.Size();
        int[][] matrix = null;
        int rows = 1000;
        int cols = 1000;
        long starttime = 0;
        long endtime = 0;

        if (rank == 0) {
            matrix = MatrixGenerator.generateMatrix(rows, cols);
            starttime = System.nanoTime();
        }

        int halfRows = rows / 2;
        int[] localMatrixFlat = new int[halfRows * cols];

        if (rank == 0) {
            int index = 0;
            for (int i = halfRows; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    localMatrixFlat[index++] = matrix[i][j];
                }
            }
            MPI.COMM_WORLD.Send(localMatrixFlat, 0, localMatrixFlat.length, MPI.INT, 1, 0);
            index = 0;
            for (int i = 0; i < halfRows; i++) {
                for (int j = 0; j < cols; j++) {
                    localMatrixFlat[index++] = matrix[i][j];
                }
            }
        } else if (rank == 1) {
            MPI.COMM_WORLD.Recv(localMatrixFlat, 0, localMatrixFlat.length, MPI.INT, 0, 0);
        }

        int[][] localMatrix = new int[halfRows][cols];
        int index = 0;
        for (int i = 0; i < halfRows; i++) {
            for (int j = 0; j < cols; j++) {
                localMatrix[i][j] = localMatrixFlat[index++];
            }
        }

        int localMax = findMaxInMatrix(localMatrix, rank);
        System.out.println("Process " + rank + " local max: " + localMax);

        int[] globalMax = new int[1];
        MPI.COMM_WORLD.Reduce(new int[]{localMax}, 0, globalMax, 0, 1, MPI.INT, MPI.MAX, 0);
        if (rank == 0) {
            System.out.println("Global max element: " + globalMax[0]);
            endtime = System.nanoTime();
            long duration = (endtime - starttime);
            System.out.println("Time: " + duration);
        }

        MPI.Finalize();
   }
   private static int findMaxInMatrix(int[][] matrix, int rank) {
        int max = Integer.MIN_VALUE;
        for (int[] row : matrix) {
            for (int value : row) {
                if (value > max) {
                    max = value;
                    System.out.println("New max "+max+" in container "+rank);
                }
            }
        }
        return max;
    }
}
