//Interpolacion con ordenes crecientes hasta nd
// compilar con g++ -I. - I./templates interpol1.cpp 
#include <cmath>
#include <iostream>
#include <iomanip>
#include "algebralineal.h"
#include "interpolacion.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);
        case 3:
//Definir F(x)
            return x*exp(x);
        case 4:
//Definir F(x)
            return atan(x);
    }
}


int main()
{
//Definir extremos intervalo
    double x0, x1;

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

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

// Funcion y tipo de espaciado
    while ((ft != 0) && (ft != 1) && (ft != 2)  && (ft != 3) && (ft != 4))
    {
      cout << "Entrar funcion: 0 - Runge   1 - Bernstein" 
	   << "    2 - sin(x)  3 - x*exp(x)  4 - atan(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;
        }
    }
// Puntos adicionales de interpolacion
   int nint;
    cout<< "  Entrar numero de puntos adicionales a interpolar "<< endl;
    cin >> nint;
    Vector < double >  xint( nint );

    for (int i=0; i < nint; i++)
    {
        cout << "Entrar punto de interpolacion "<< i+1 << endl;
        cin >> xint[i];
    }
    double pi = 4 * atan(1.);

    Vector < double > pold(nint),yint(nint);

    for(int orden =1; orden<=nd; orden++)
    {

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


        int nodos=orden+1;
        Vector < double > x(nodos);
        Vector < double > y(nodos);

//Construccion de vectores

// Calculo de las abcisas de interpolacion
        switch (es)
        {
            case 1:
                for (int i = 0; i < nodos; i++)
                    x[i] = x0 + i * h;
                break;
            case 2:
                for (int i = 0; i < nodos; i++)
                    x[i] = (x0 - x1) / 2 * cos((2 * i + 1) * pi / (2 * nodos)) +
                        (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

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

        cout << endl << "      xint   " << "  p(xint)   " <<
            " f(xint)  " << "|f(xint)-p(xint)|  " <<
                "|p_n(xint)-p_n-1(xint)|"<< endl;

        for (int i= 0;i<nint; i++)
        {
            pold[i]= yint[i];
            yint[i] = eval_difdiv < double >(xint[i], x, a);
            double fint = fun(xint[i], ft);
            cout << setw(10) << xint[i] << "  " << setw(10) << 
                    yint[i] << "  " <<
                    setw(10) << fint << "  " << setw(10) << 
                    abs(yint[i] - fint) << "      "<<
                    abs(pold[i]-yint[i]) << endl;
        }

    }

    return 0;
}
