/**
 * @file interpolation.c
 * @brief Contients les portotypes desfocntions de gestions des fichiers.
 * @author Valentin PORTAIL et Jérémie VILLEPREUX
 * @version 1.0
 * @date 08/11/2022
 */

#include "interpolation.h"
#include "gestionFichier.h"


/** 
 * @brief Permet de calculer la valeur du polynome de Lagrange en 1 point considérer.
 *
 * @param[in] points         Tableau qui contient les points données du polynome. 
 * @param[in] nb_points      Nombre de point du polynome considérer.
 * @param[in] x              Nombreauquel on souhaite connaitre l'évaluation.
 *
 * @return Renvoie la valeur du polynome de Lagrange au points **x** point considérer.
 */
double methode_lagrange(double ** points, unsigned int nb_points, double x) {

    // Initialisation des fonctions annexes l_i

    double * l = malloc(nb_points * sizeof(double));

    if (!l) {
        perror("Erreur d'allocation");
        exit(EXIT_FAILURE);
    }

    // Calcul de l_i(x)
    unsigned int i, j;

    for (i = 0; i < nb_points; ++i) {
        l[i] = 1;
        for (j = 0; j < nb_points; ++j) {
            if (i != j) {
                l[i] *= (x - points[j][0]) / (points[i][0] - points[j][0]);
            }
        }
    }

    // Calcul de P(x)
    double p = 0;
    
    for (i = 0; i < nb_points; ++i) {
        p += points[i][1] * l[i];
    }

    free(l);

    return p;
}



/** 
 * @brief Permet de calculer la valeur du polynome de Neville en 1 point considérer.
 *
 * @param[in] points         Tableau qui contient les points données du polynome. 
 * @param[in] nb_points      Nombre de point du polynome considérer.
 * @param[in] x              Nombre au quel on souhaite connaitre l'évaluation.
 *
 * @return Renvoie la valeur du polynome de Lagrange au points **x** point considérer.
 */
double methode_neville(double ** points, unsigned int nb_points, double x) {
    // Initialisation d'une table de stockage

    double ** stock = malloc(nb_points * sizeof(double *));
    unsigned int k, i;

    for (k = 0; k < nb_points; ++k) {
        stock[k] = malloc((nb_points - k) * sizeof(double)); // On aura stock[k][i] (k = degré poly. & i = indice début) pour P[x_i, x_i+k]
    }

    // Calcul des différents polynômes

    for (i = 0; i < nb_points; ++i) {
        stock[0][i] = points[i][1];
    }

    for (k = 1; k < nb_points; ++k) {
        for (i = 0; i < nb_points - k; ++i) {
            stock[k][i] = ((x - points[i+k][0]) * stock[k-1][i] - (x - points[i][0]) * stock[k-1][i+1]) / (points[i][0] - points[i+k][0]);
        }
    }

    // Extraire le résultat

    double result = stock[nb_points - 1][0];

    for (k = 0; k < nb_points; ++k) {
        free(stock[k]);
        stock[k] = NULL;
    }

    free(stock);
    stock = NULL;

    return result;
}


/** 
 * @brief Procédure qui permet d'écrire les valeurs des **x** et de **f(x)** pour les points considérer (grâce au polynome de Lagrange).
 *
 * @param[in] nom_fichier    Nomdu fichier où écrire les points.
 * @param[in] points         Tableau qui contient les points données du polynome. 
 * @param[in] nb_points      Nombre de point du polynome considérer.
 * @param[in] borne_inf      Borne inf de la valeur en laquelle on souhaite évaluer le polynome.
 * @param[in] borne_sup      Borne inf de la valeur en laquelle on souhaite évaluer le polynome.
 *
 */
void ecriture_polynome_L(char * nom_fichier, double**points, unsigned int nb_points, double borne_inf, double borne_sup){

    int cpt;
    double x;
    double y;
    double pas = 0.1;
    //On affichera les valeurs du polynome par pas de 0.1

    int nbr_ite = (int)(borne_sup - borne_inf)/pas;
    //c'est un eniter, car "pas"<1.
    

    for (cpt = 0; cpt < nbr_ite; ++cpt){

	x = borne_inf + cpt*pas;
	y = methode_lagrange(points, nb_points, x);
	ecriture_points(nom_fichier, x, y);
    }

}

/** 
 * @brief Procédure qui permet d'écrire les valeurs des **x** et de **f(x)** pour les points considérer (grâce au polynome de Lagrange).
 *
 * @param[in] nom_fichier    Nomdu fichier où écrire les points.
 * @param[in] points         Tableau qui contient les points données du polynome. 
 * @param[in] nb_points      Nombre de point du polynome considérer.
 * @param[in] borne_inf      Borne inf de la valeur en laquelle on souhaite évaluer le polynome.
 * @param[in] borne_sup      Borne inf de la valeur en laquelle on souhaite évaluer le polynome.
 *
 */
void ecriture_polynome_N(char * nom_fichier, double**points, unsigned int nb_points, double borne_inf, double borne_sup){

    int cpt;
    double x;
    double y;
    double pas = 0.1;
    //On affichera les valeurs du polynome par pas de 0.1

    int nbr_ite = (int)(borne_sup - borne_inf)/pas;
    //c'est un eniter, car "pas"<1.
    

    for (cpt = 0; cpt < nbr_ite; ++cpt){
	x = borne_inf + cpt*pas;
	y = methode_neville(points, nb_points, x);
	ecriture_points(nom_fichier, x, y);
    }

}
