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

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


// Private Functions
static char* display(Problema * pb)
{
    // Name presentation
    static char nameTemplate[]     = "Problème : '%s' (id:%04ld)";
    static char functionTemplate[] = "Fonction : '%s'\nDimension %3d";
    static char output[19 + 4 + MAX_INPUT + 20 + MAX_INPUT + 3 + 1 + 3];

    char name[19 + 4 + MAX_INPUT + 1];
    char function[22 + MAX_INPUT + 3 + 1];

    if(!pb) return "NULL pointer";

    memset(output,'\0',(19 + 4 + MAX_INPUT + 20 + MAX_INPUT + 3 + 1 + 3) * sizeof(char));

    memset(name,'\0',(19 + 5 + MAX_INPUT + 1) * sizeof(char));
    memset(function,'\0',(20 + MAX_INPUT + 3 + 1) * sizeof(char));

    sprintf(name,nameTemplate,pb->_name,pb->_db_id);
    sprintf(function,functionTemplate,pb->_functionRepresentation,pb->_dimension);

    //char displayString[19 + 4 + MAX_INPUT + 20 + MAX_INPUT + 3 + 1];

    sprintf(output,"\n%s\n%s\n",name,function);

    return output;
}

// Public Functions

Problema* createProblema()
{
    Problema * entity = (Problema * )malloc(sizeof(Problema));

    logMessage(DEBUG,"problema allocation",integerToString((int)entity,10));

    // error
    if(!entity)
    {
        logMessage(SEVERE,"malloc failed","Erreur lors de la création d'un problème");
        perror("Erreur lors de la création d'un problème\n");
        return NULL;
    }

    // initialize
    // - dummy id
    entity->_db_id = 0;
    // - clear name tab
    memset(entity->_name,'\0',MAX_INPUT * sizeof(char));
    // - dummy dimension
    entity->_dimension = 0;
    // - clear name tab
    memset(entity->_functionRepresentation,'\0',MAX_INPUT * sizeof(char));
    // - objective function
    entity->_function = NULL;
    // - constraints
    memset(entity->_constraints,0/*NULL*/,MAX_ITEM);
    // - constraints
    memset(entity->_derivees,0/*NULL*/,MAX_ITEM);
    // - possible known solution
    entity->_solution = NULL;


    // methods
    entity->display  = display;

    return entity;
}

Problema* createProblemaWithParameters(
    char*         problemName,
    unsigned long problemId,
    char*         functionRepresentation,
    double*     (*function)       (const double[],const size_t dimension),
    size_t        function_input_dimension
)
{
    Problema* pb = NULL;
    //validation
    double verification[function_input_dimension];

    memset(verification,0,function_input_dimension * sizeof(double));

    logMessage(DEBUG,"newline","");
    logMessage(DEBUG,"function name","createProblemWithParameters");
    logMessage(DEBUG,"parameter : problemName",problemName);
    logMessage(DEBUG,"parameter : problemId",integerToString(problemId,10));
    logMessage(DEBUG,"parameter : functionRepresentation",functionRepresentation);
    logMessage(DEBUG,"parameter : function pointer",integerToString((int)function,10));
    logMessage(DEBUG,"parameter : function input dimension",integerToString(function_input_dimension,10));

    logMessage(DEBUG,"verification vector",printVector(verification,function_input_dimension));

/*
    logMessage(DEBUG,"function verification pointer",integerToString((int)function(verification,function_input_dimension),10));
    logMessage(DEBUG,"function verification value",integerToString((int)(function(verification,function_input_dimension)[0]),10));
*/
    
    // Vérification de la dimension d'entrée
    if( !function(verification,function_input_dimension) )
    {
        logMessage(SEVERE,"dimension verification failed","Mauvaise dimension donnée pour le problème donné");
        perror("Mauvaise dimension donnée pour le problème donné");
        return NULL;
    }
    
    logMessage(DEBUG,"function verification successfull",integerToString((int)(function(verification,function_input_dimension)[0]),10));

    pb = createProblema();

    //Allocatio nayant échouée
    if(!pb)
    {
        perror("L'allocation mémoire a échouée");
        return NULL;
    }

    strcpy(pb->_name,problemName);

    logMessage(DEBUG,"problem name set",pb->_name);

    /* FIXME Set by the database */
    pb->_db_id = problemId;

    logMessage(DEBUG,"problem id set",integerToString(pb->_db_id,10));

    strcpy(pb->_functionRepresentation,functionRepresentation);

    logMessage(DEBUG,"problem function representation set",pb->_functionRepresentation);

    pb->_function = function;

    logMessage(DEBUG,"problem function pointer set",integerToString((int)pb->_function,10));

    pb->_dimension = function_input_dimension;

    logMessage(DEBUG,"problem function dimension set",integerToString(pb->_dimension,10));

    return pb;
}


void      destroyProblema(Problema ** pb)
{
    if(*pb)
    {
        //free((*pb)->_name);
        //free((*pb)->_functionRepresentation);
        free(*pb);

        memset((*pb)->_name,'\0',MAX_INPUT * sizeof(char));
        memset((*pb)->_functionRepresentation,'\0',MAX_INPUT * sizeof(char));
        *pb                            = NULL;
    }
    else
    {
        logMessage(WARNING,"destroyProblema","Trying to free a NULL pointer");
    }
}



boolean   checkInputValidity(Problema* problema, double vector[], size_t dimension)
{
    int cursor = 0;
    // On vérifie toutes les contraintes
    // tant qu'on a des contraintes : constraints_verification != NULL
    while(*(problema->_constraints + cursor))
    {
        // On execute la fonction booléenne
        if( ! (*(problema->_constraints + cursor))(vector,dimension) )
        {
            perror("Input vector invalid !");
            return 0; // Entrée invalide on annule
        }
        // fonction booléenne suivante
        cursor++;
    }

    return 1;
}



