//Programa de interpolacion polinomial
//con ilustracion de los  ejemplos de  Runge y Bernstein
//Compilar con g++ -I. -I./templates interpol.cpp gnuplot_i_calnum.cpp
#include <cmath>
#include <iostream>
#include <iomanip>
#include "algebralineal.h"
#include "interpolacion.h"
#include "gnuplot_i_calnum.h"
using namespace std;
inline double fun(double x, int ft)
{
    switch (ft)
    {
        case 0:
            return 1. / (1. + 25 * x * x);
            break;
        case 1:
            return abs(x);
            break;
        case 2:
//Definir F(x)
            return sin(x);
    
    }
}

int main()
{
//Programa de interpolacion
    double x0, x1;

    cout << "Entrar xmin" << endl;
    cin >> x0;
    cout << "Entrar xmax" << endl;
    cin >> x1;
    int nd;

    cout << "Entrar orden polinomio interpolador" << endl;
    cin >> nd;
    int ft=-1;

    while ((ft != 0) && (ft != 1) && (ft != 2)  && (ft != 3) && (ft != 4))
    {
        cout << "Entrar funcion: 0 - Runge   1 - Bernstein  2 - sin(x)  " << endl;
        cin >> ft;
    }
    cout << "Entrar tipo de espaciado: 1: uniforme  2: Chebychev" << endl;
    int es = 0;

    while ((es != 1) && (es != 2))
    {
        cin >> es;
        if ((es != 1) && (es != 2))
        {
            cout << "Espaciado erroneo" << endl;
            cout << "Entrar tipo de espaciado: 1: uniforme  2:Chebychev" << endl;
        }
    }
    double xint;

    double pi = 4 * atan(1.);

//Espaciado entre los nodos
    double h = (x1 - x0) / nd;

    nd++;
//El numero de nodos es una unidad mayor que el orden
    Vector < double >x(nd);

//Construccion de vectores

// Calculo de las abcisas de interpolacion
    switch (es)
    {
        case 1:
            for (int i = 0; i < nd; i++)
                x[i] = x0 + i * h;
            break;
        case 2:
            for (int i = 0; i < nd; i++)
                x[i] = (x0 - x1) / 2 * cos((2 * i + 1) * pi / (2 * nd)) +
                    (x1 + x0) / 2.;
//	cout << x << endl;
            break;
        default:
            cout << "Espaciado erroneo" << endl;
            return 1;
    }

//Calculo de las ordenadas de interpolacion y de los coeficientes del
//polinomio
    Vector < double >y(nd);

    for (int i = 0; i < nd; i++)
        y[i] = fun(x[i], ft);
    Vector < double >a = difdiv < double >(x, y);
    cout<<" Nodos de interpolacion"<<endl;
    cout<<"   i  "<<"    x   "<< "         y    "<<endl;
    for (int i=0;i<nd;i++) cout <<"   "<< i+1 <<setw(10)<<x[i]<<
            "   "<<setw(10)<<y[i] << endl;
    cout << endl<<"coeficientes diferencias divididas a= " << a << endl;

//evaluacion del polinomio y funcion en los puntos de dibujo(200)
// se dibuja un 2*deltax100 % fuera del intervalo
    int n = 200;
    double delta=0.;
    cout << " Entrar delta" <<
        "(Dibujo en [x0-(x1-x0)*delta, x1+(x1-x0)*delta] "<< endl << endl;
    cin>>delta;
    x1+=(x1-x0)*delta;
    x0-=(x1-x0)*delta;
    double hh = (x1 - x0) / n;

    n++;
    Vector < double >xx(n), yy(n), ff(n);

    cout << "       x    " << "    p(x)   " <<
        "   f(x)   " << "  |f(x)-p(x)|  " << endl;
    for (int i = 0; i < n; i++)
    {
        xx[i] = x0 + i * hh;
        yy[i] = eval_difdiv < double >(xx[i], x, a);
        ff[i] = fun(xx[i], ft);

//Impresion de la funcion en 20 puntos igualmente espaciados
        if ((i / 10) * 10 == i)
            cout << setw(10) << xx[i] << "  " << setw(10) << yy[i] << "  " <<
                setw(10) << ff[i] << "  " << setw(10) << abs(yy[i] - ff[i]) << endl;
    }

//Dibujo del polinomio y la funcion
    Gnuplot g1 = Gnuplot();
//Seleccionamos escala logaritmica para ciertas funciones
// if ((ft == 0) || (ft == 1))	g1.cmd("set logscale y");
    if ((ft == 0))
    g1.cmd("set logscale y");
    g1.set_style("lines");
    g1.plot_xy(xx, ff, " ");
    g1.set_style("points");
    g1.plot_xy(xx, yy, " ");
//Eleccion del tiempo de permanencia de la grafica en pantalla
    int SLEEP_LGTH = 25;
    sleep(SLEEP_LGTH);
    return 0;
}
