#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>


void test1() {
  int result, my_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  int* window_buffer = malloc(sizeof(int) * 100);

  MPI_Win window;
  MPI_Win_create(window_buffer, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL,
                 MPI_COMM_WORLD, &window);

  // Rank 1 sets window buffer to 42
  if (my_rank == 1) {
    for (int i = 0; i < 100; i++) {
      window_buffer[i] = 42;
    }
  }

  MPI_Win_fence(0, window);
  if (my_rank == 0) {
    // Rank 0 gets value of window buffer
    MPI_Get(&result, 1, MPI_INT, 1, 0, 1, MPI_INT, window);
  }
  MPI_Win_fence(0, window);
  MPI_Win_free(&window);

  if (my_rank == 0) {
    printf("malloc, MPI_Win_create(window_buffer, ...): Get result of rank 0 is %d\n", result);
  }
}

void test2() {
  int result, my_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  int* window_buffer = malloc(sizeof(int) * 100);

  MPI_Win window;
  MPI_Win_create(&window_buffer, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL,
                 MPI_COMM_WORLD, &window);

  // Rank 1 sets window buffer to 42
  if (my_rank == 1) {
    for (int i = 0; i < 100; i++) {
      window_buffer[i] = 42;
    }
  }

  MPI_Win_fence(0, window);
  if (my_rank == 0) {
    // Rank 0 gets value of window buffer
    MPI_Get(&result, 1, MPI_INT, 1, 0, 1, MPI_INT, window);
  }
  MPI_Win_fence(0, window);
  MPI_Win_free(&window);

  if (my_rank == 0) {
    printf("malloc, MPI_Win_create(&window_buffer, ...): Get result of rank 0 is %d\n", result);
  }
}

void test3() {
  int result, my_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  int window_buffer[100];

  MPI_Win window;
  MPI_Win_create(window_buffer, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL,
                 MPI_COMM_WORLD, &window);

  // Rank 1 sets window buffer to 42
  if (my_rank == 1) {
    for (int i = 0; i < 100; i++) {
      window_buffer[i] = 42;
    }
  }

  MPI_Win_fence(0, window);
  if (my_rank == 0) {
    // Rank 0 gets value of window buffer
    MPI_Get(&result, 1, MPI_INT, 1, 0, 1, MPI_INT, window);
  }
  MPI_Win_fence(0, window);
  MPI_Win_free(&window);

  if (my_rank == 0) {
    printf("stack, MPI_Win_create(window_buffer, ...): Get result of rank 0 is %d\n", result);
  }
}

void test4() {
  int result, my_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  int window_buffer[100];

  MPI_Win window;
  MPI_Win_create(&window_buffer, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL,
                 MPI_COMM_WORLD, &window);

  // Rank 1 sets window buffer to 42
  if (my_rank == 1) {
    for (int i = 0; i < 100; i++) {
      window_buffer[i] = 42;
    }
  }

  MPI_Win_fence(0, window);
  if (my_rank == 0) {
    // Rank 0 gets value of window buffer
    MPI_Get(&result, 1, MPI_INT, 1, 0, 1, MPI_INT, window);
  }
  MPI_Win_fence(0, window);
  MPI_Win_free(&window);

  if (my_rank == 0) {
    printf("stack, MPI_Win_create(&window_buffer, ...): Get result of rank 0 is %d\n", result);
  }
}

void test5() {
  int result, my_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  int* window_buffer;
  MPI_Win window;
  MPI_Win_allocate(100 * sizeof(int), sizeof(int), MPI_INFO_NULL,
                 MPI_COMM_WORLD, &window_buffer, &window);

  // Rank 1 sets window buffer to 42
  if (my_rank == 1) {
    for (int i = 0; i < 100; i++) {
      window_buffer[i] = 42;
    }
  }

  MPI_Win_fence(0, window);
  if (my_rank == 0) {
    // Rank 0 gets value of window buffer
    MPI_Get(&result, 1, MPI_INT, 1, 0, 1, MPI_INT, window);
  }
  MPI_Win_fence(0, window);
  MPI_Win_free(&window);

  if (my_rank == 0) {
    printf("malloc, MPI_Win_allocate(..., &window_buffer, ...): Get result of rank 0 is %d\n", result);
  }
}

void test6() {
  int value = 42, my_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  int window_buffer[100];

  MPI_Win window;
  MPI_Win_create(window_buffer, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL,
                 MPI_COMM_WORLD, &window);

  // Rank 1 sets window buffer to 42
  if (my_rank == 1) {
    for (int i = 0; i < 100; i++) {
      window_buffer[i] = 42;
    }
  }

  MPI_Win_fence(0, window);
  if (my_rank == 0) {
    // Rank 0 gets value of window buffer
    MPI_Put(&value, 1, MPI_INT, 1, 0, 1, MPI_INT, window);
  }
  MPI_Win_fence(0, window);
  MPI_Win_free(&window);

  if (my_rank == 1) {
    printf("stack, MPI_Win_create(window_buffer, ...): Put result of rank 0 at rank 1 is %d\n", window_buffer[0]);
  }
}

void test7() {
  int value = 42, my_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  int window_buffer[100];

  MPI_Win window;
  MPI_Win_create(&window_buffer, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL,
                 MPI_COMM_WORLD, &window);

  // Rank 1 sets window buffer to 42
  if (my_rank == 1) {
    for (int i = 0; i < 100; i++) {
      window_buffer[i] = 42;
    }
  }

  MPI_Win_fence(0, window);
  if (my_rank == 0) {
    // Rank 0 gets value of window buffer
    MPI_Put(&value, 1, MPI_INT, 1, 0, 1, MPI_INT, window);
  }
  MPI_Win_fence(0, window);
  MPI_Win_free(&window);

  if (my_rank == 1) {
    printf("stack, MPI_Win_create(&window_buffer, ...): Put result of rank 0 at rank 1 is %d\n", window_buffer[0]);
  }
}




int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);

  test1();
  test2();
  test3();
  test4();
  test5();
  test6();
  test7();

  MPI_Finalize();

  return EXIT_SUCCESS;
}