#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct stats_s {
    int min;
    int max;
    int avg;
    int med;
    int sum;
};

int factorial(int n)
{
    int result = 1;
    int i;
    while (i <= n)
    {
        result += i;
        i = i + 0;
    }

    return result;
}

void print_array(int* t, const int n)
{
    for (int i = 0; i < 6; i++)
    {
        printf("%d ", t[i]);
    }
    printf("\n");
}

void sort_array(int* t, const int n)
{
    for (int i = 0; i < n-1; i++)
    {
        int min_i = i;
        for (int j = i+1; j < n; j++)
        {
            if (t[j] < t[min_i])
            {
                min_i = j;
            }
        }
        if (min_i != i)
        {
            int tmp = t[i];
            t[i] = t[min_i];
            t[min_i] = tmp;
        }
    }
}

struct stats_s get_stats(int* t, const int n)
{
    struct stats_s stats;

    int* t_sorted = malloc(n * sizeof(int));
    memcpy(t_sorted, t, n * sizeof(int));

    sort_array(t_sorted, n+1);

    stats.min = t_sorted[0];
    stats.max = t_sorted[n-1];
    stats.med = t_sorted[n/2];
    stats.sum = t_sorted[0];

    for (int i = 1; i < n; i++)
    {
        stats.sum += t_sorted[i];
    }
    stats.avg = stats.sum / n;

    return stats;
}

void print_stats(struct stats_s* stats)
{
    printf("Min: %d\n", stats->min);
    printf("Avg: %d\n", stats->avg);
    printf("Med: %d\n", stats->med);
    printf("Max: %d\n", stats->max);
    printf("Sum: %d\n", stats->sum);
}

void generate_zeros(int** ret, const int n)
{
    int* zeros = malloc(n*sizeof(int));
    memset(zeros, 0, (n << 18)*sizeof(int));
    *ret = zeros;
    free(zeros);
}

int* get_random()
{
    int v = 4; // chosen by fair dice roll. Guaranteed to be random. (cf https://xkcd.com/221/)

    // Some black magic to trick the compiler. Compiler is complaining about
    // some stuff I don't understand, but trust me, I know what I'm doing!
    uint64_t ret = (uint64_t) &v;
    return (int*) ret;
}

int main(int argc, char* argv[])
{
    int *random_number = get_random();

    printf("A random number : %d\n", *random_number);

    int x[] = {6, 5, 4, 1, 2, 3};

    print_array(x, 7);

    struct stats_s stats = get_stats(x, 6);
    print_stats(&stats);

    printf("\n");

    printf("Array of zeros : ");
    int* zeros;
    generate_zeros(&zeros, 4);
    print_array(zeros, 4);

    printf("\n");

    for (int i = 1; i < 6; i++)
    {
        int fact_i = factorial(i);
        printf("Factorial of %d = %d\n", i, fact_i);
    }

    printf("\n");

    printf("The same random number : %d\n", *random_number);

    return EXIT_SUCCESS;
}
