#include "toolbox.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct array *sort(struct array *arr, comparator f)
{
    if(!arr || !f) return NULL;
    
    void *temp = malloc(arr->elem_size);
    if(!temp) return NULL;

    if (arr->len > 0) {
        for(size_t index1 = 0; index1 < arr->len - 1; index1 ++ ){

            for(size_t index2 = index1; index2 < arr->len; index2 ++){
            
                void *data1 = arr->data + index1 * arr->elem_size;
                void *data2 = arr->data + index2 * arr->elem_size;

                if(f(data1,data2) > 0){
                    memcpy(temp, data2, arr->elem_size);
                    memcpy(data2, data1, arr->elem_size);
                    memcpy(data1, temp, arr->elem_size);
                }
            }
        }
    }

    free(temp);
    return arr;

}

struct array *map(struct array *arr, size_t output_size, mapper f)
{
    if(!arr || !f)return NULL;

    void *data = calloc(arr->len, output_size);   
    if(!data) return NULL;

    size_t index = 0;
    while (index != arr->len){
        void *data2 = data + index * output_size;
        void *n = arr->data + index * arr->elem_size;
        
        f(data2, n);
        index ++;
    }

    free(arr->data);
    arr->data = data;
    arr->elem_size = output_size;

    return arr;
}

struct array *filter(struct array *arr, predicate f)
{
    if(!arr || !f) return NULL;

    size_t index = 0;
    int flon = 0;
    while(index != arr->len){

        void *cur = arr->data + index * arr->elem_size;
        
        if(f(cur) != 0) flon ++;

        index ++;
    }

    index = 0;
    void *data1 = calloc(flon, arr->elem_size);
    if(!data1 && flon > 0) return NULL;
    
    size_t index2 = 0;
    while(index != arr->len){
        void *cur = arr->data + index * arr->elem_size;

        if(f(cur) != 0){
            void *n = data1 + index2 * arr->elem_size;
            memcpy(n, cur, arr->elem_size);
            index2 ++;
        }
        index ++;
    }

    free(arr->data);
    arr->data = data1;
    arr->len = flon;

    return arr;
}

void *reduce(struct array *arr, void *start_value, reducer f)
{
    if(!arr || !start_value || !f) return NULL;

    void *rslt = start_value;
    size_t index = 0;

    while(index != arr->len){
        void *cur = arr->data + index * arr->elem_size;

        rslt = f(rslt, cur);
        index ++;
    }

    return rslt;
}

void foreach(struct array *arr, acceptor f)
{
    if(!arr || !f) return;
// arr.data est un array de x valeurs
    size_t index = 0;
    
    while(index != arr->len){
        
        f(arr->data + index * arr->elem_size);
        index ++;
    }
}
/*
#include <stdio.h>
#include <stdlib.h>

int *add(int *res, int *n)
{
    *res += *n;
    return res;
}

void print_int(int *n)
{
    printf("%d\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    int res = 0;
    reduce(&arr, &res, (reducer)&add);
    printf("%d\n", res);

    free(arr.data);
}
*/

/*
#include <stdio.h>
#include <stdlib.h>

int odd(int *n)
{
    return *n % 2;
}

void print_int(int *n)
{
    printf("%d\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    foreach(filter(&arr, (predicate)&odd), (acceptor)&print_int);

    free(arr.data);
}
*/

/*
#include <stdio.h>
#include <stdlib.h>

void next(double *res, int *n)
{
    *res = *n + 1;
}

void print_double(double *n)
{
    printf("%.1lf\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    foreach(map(&arr, sizeof(double), (mapper)&next), (acceptor)&print_double);

    free(arr.data);
}
*/


/*
#include <stdio.h>
#include <stdlib.h>

int reverse(int *a, int *b)
{
    return *b - *a;
}

void print_int(int *n)
{
    printf("%d\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    foreach(sort(&arr, (comparator)&reverse), (acceptor)&print_int);

    free(arr.data);
}
*/


/*
#include <stdio.h>
#include <stdlib.h>

void print_int(int *n)
{
    printf("%d\n", *n);
}
 
int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    foreach(&arr, (acceptor)&print_int);

    free(arr.data);
}
*/
