/***
 * @author: Marc Feger
 * @mail: marc.feger@uni-duesseldorf.de
 */
#include <stdlib.h>
#include <time.h>
#include <printf.h>
#include <ntsid.h>
#include <pthread.h>

// SIZE > COUNT_THREADS is a must
#define SIZE 100000000
#define COUNT_THREADS 1

struct arguments {
    int id;
    int *array;
    int *max;
};

typedef struct arguments arguments_s;

int *create_random_array() {
    srand((unsigned int) time(NULL));
    int *array = malloc(SIZE * sizeof(int));
    for (int i = 0; i < SIZE; i++) {
        array[i] = rand();
    }
    return array;
}

int get_maximum(const int *array, int from, int to) {
    int max = 0;
    for (int i = from; i < to; i++) {
        if (array[i] > max) max = array[i];
    }
    return max;
}

void *worker(void *arg) {
    arguments_s *args = (arguments_s *) arg;

    int from = args->id * (SIZE / COUNT_THREADS);
    int to = (args->id + 1) * (SIZE / COUNT_THREADS);
    if (args->id == COUNT_THREADS - 1) to = SIZE;

    args->max[args->id] = get_maximum(args->array, from, to);

    return NULL;
}

int main(void) {

    int *array = create_random_array();
    int *max = malloc(SIZE * sizeof(int));

    arguments_s args;

    args.array = array;
    args.max = max;

    pthread_t threads[COUNT_THREADS];

    clock_t start_t;

    start_t = clock();
    // create all threads
    for (int i = 0; i < COUNT_THREADS; i++) {
        args.id = i;
        if (pthread_create(&threads[i], NULL, worker, (void *) &args) != 0) {
            printf("pthread_create() did not create a thread");
        }
        if (pthread_join(threads[i], NULL) != 0) {
            printf("pthread_join() did not join a thread");
        }
    }


    int total_max = get_maximum(args.max, 0, COUNT_THREADS);
    printf("The total maximum is: %d\n", total_max);
    printf("It took %f clocks for %d threads to find the maximum of %d elements\n",
           ((double) (start_t - clock())) / CLOCKS_PER_SEC, COUNT_THREADS, SIZE);

    free(array);
    free(max);

    return 0;
}