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

#include <math.h>

#include "utilities.h"
#include "logger.h"

char* printVector(
    double vector[],
    size_t dimension)
{
    char* value;
    char buffer[20];
    unsigned int counter = 0;

    LogLevel old = getLogLevelDisplayed();
    setLogLevelDisplayed(NONE);

    value =(char *)malloc(40*sizeof(char));
    memset(value,'\0',40);

    logMessage(DEBUG,"\tinit",value);

    strcat(value,"{");

    logMessage(DEBUG,"\t1st delimiter",value);
    while(counter < dimension)
    {
        logMessage(DEBUG,"\tcounter",integerToString(counter,10));
        logMessage(DEBUG,"\tdimension",integerToString(dimension,10));

        memset(buffer,'\0',20);

        logMessage(DEBUG,"\tclean buffer",buffer);

        sprintf(buffer,"%.5lf",vector[counter]);
        if( counter + 1 < dimension ) strcat(buffer,", ");

        logMessage(DEBUG,"\tfill buffer",buffer);

        strcat(value,buffer);

        logMessage(DEBUG,"\tconcat value",value);
        counter++;
    }
    strcat(value,"}");
    logMessage(DEBUG,"\tcompleted",value);

    setLogLevelDisplayed(old);

    return value;
}

char* printBoolean(
    boolean b)
{
    static char* booleanValue[] = {
        "TRUE",
        "FALSE"
    };

    return (b!=0)? booleanValue[0] : booleanValue[1];
}

/**
 * FIXME Free the result
 * @param function
 * @param x
 * @param dimension
 * @param delta
 * @return
 */
double* approximateGradient(
    double* (*function)(const double[], const size_t dimension),
    double x[],
    size_t dimension,
    double delta)
{
    double buffer[dimension];
    double* result;
    double operation_buffer;
    int counter;

    LogLevel old = getLogLevelDisplayed();
    setLogLevelDisplayed(NONE);

    logMessage(DEBUG,"\tpresentation","approximateGradient");
    logMessage(DEBUG,"\tinit vector",printVector(x,dimension));
    logMessage(DEBUG,"\tinit dimension",integerToString(dimension,10));

    result = (double *)malloc(dimension * sizeof(double));
    
    for(counter = 0; counter < dimension;counter++)
    {
        memcpy(buffer,x,dimension * sizeof(double)); //copie du vecteur
        logMessage(DEBUG,"\tinit buffer",printVector(buffer,dimension));
        buffer[counter] += delta;
        logMessage(DEBUG,"\tdelta buffer",printVector(buffer,dimension));


        logMessage(DEBUG,"\tfunction value w/ buffer",printVector((*function)(buffer,dimension),1));
        logMessage(DEBUG,"\tfunction value w/ initial vector",printVector((*function)(x,dimension),1));
        logMessage(DEBUG,"\toperation value","");
/*
        double a,b,c;
        a = (*function)(buffer,dimension)[0];
        b = (*function)(x,dimension)[0];
        c = a - b;
        printf("\t - True value 1st value : '%f'\n",(*function)(buffer,dimension)[0]);
        printf("\t - True value 2nd value : '%f'\n",(*function)(x,dimension)[0]);
        printf("\t - True value diff value : '%f'\n",(double)((*function)(buffer,dimension)[0] - (*function)(x,dimension)[0] ));
        printf("\t - True value fraction value : '%f'\n",(((*function)(buffer,dimension)[0] - (double)(*function)(x,dimension)[0] ) / delta));
        printf("\t - True value a value : '%f'\n",a);
        printf("\t - True value b value : '%f'\n",b);
        printf("\t - True value c value : '%f'\n",c);
        printf("\t - True value new fraction value : '%f'\n",(c / delta));
*/

        operation_buffer = (*function)(buffer,dimension)[0];
        operation_buffer -= (*function)(x,dimension)[0];

        //result[counter] = ( (double)(*function)(buffer,dimension)[0] - (double)(*function)(x,dimension)[0] ) / delta;
        result[counter] = ( operation_buffer ) / delta;
    }

    logMessage(DEBUG,"\tresult",printVector(result,dimension));

    setLogLevelDisplayed(old);

    return result;
}

double  normeEuclidienne(
    const double x[],
    const size_t dimension)
{
    int i;
    double temp = 0;
    for(i=0; i<dimension; i++)
        temp += x[i] * x[i];

    return (double) sqrt( temp );
}

double  error(
    unsigned int dimension,
    double x[],
    double solution[])
{
    double buffer[dimension];
    int i;

    for(i=0; i<dimension; i++)
        buffer[i] = x[i] - solution[i];

    return normeEuclidienne(buffer,dimension);
}


char* integerToString(int val, int base)
{
    static char buf[32] = {0};

    int i = 30;

    for(; val && i ; --i, val /= base)

            buf[i] = "0123456789abcdef"[val % base];

    return &buf[i+1];

}

char* doubleToString(
    double val)
{
    static char buf[32] = {0};

    sprintf(buf,"%.6lf",val);

    return &buf[0];
}
