#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
typedef double (*func_t) (double);
 
typedef struct values_s{
    double *arg;
    double *funcval;
    long size;
} values_t;
 
typedef enum boolean_e{
    FALSE = 0,
    TRUE = 1
} boolean_t;
 
double func1 (double x)
{
    return 2*sin(x)-0.5;
}
 
double func2 (double x)
{
    return 2*cos(x);
}
 
values_t *values_allocate(long size)
{
    values_t *val=calloc(1,sizeof(values_t));
 
    if(!val)
    {
        fprintf(stderr,"Allocate Error!");
        return 0;
    }
 
    val->arg=calloc(size,sizeof(double));
    val->funcval=calloc(size,sizeof(double));
 
    if(!val->arg ||!val->funcval)
    {
        fprintf(stderr,"Allocate Error!");
        free(val);
        return 0;
    }
    val->size = size;
    return val;
}
 
boolean_t values_insert(values_t *val,double arg,double value,long index)
{
    boolean_t status=FALSE;
 
    if(!val)
    {
        fprintf(stderr,"Nullpointer!");
        return status;
    }
    if(index<0 || index >= val->size)
    {
        fprintf(stderr,"Index out of range!");
        return status;
    }
 
    val->arg[index] = arg;
    val->funcval[index] = value;
    return status=TRUE;
}
 
boolean_t values_free(values_t *val)
{
    boolean_t status=FALSE;
 
    if(!val)
    {
        fprintf(stderr,"Nullpointer!");
        return status;
    }
 
    free(val->arg);
    free(val->funcval);
    free(val);
    return status=TRUE;
}
 
boolean_t values_print(values_t *val)
{
    boolean_t status=FALSE;
    long i;
    if(!val)
    {
        fprintf(stderr, "Nullpointer.\n");
        return status;
    }
    for(i=0;i<val->size;i++)
        printf("%ld. %5g, %5g\n", i, val->arg[i], val->funcval[i]);
 
    return status=TRUE;
}
 
double newton_step(double x0, func_t func, func_t derivate)
{
    if(derivate(x0)==0)
    {
        fprintf(stderr, "Error: Division by Zero.\n");
        return 0;
    }
    return x0-func(x0)/derivate(x0);
}
 
void values_store(values_t *val)
{
    FILE *fp=fopen("C:\\users\\Patrick\\Dropbox\\3tes_Semester\\prog2\\Übung4\\newton.txt","w");
    long i;
 
    if(fp)
    {
        for(i=0;i<val->size;i++)
        {
            fprintf(fp,"%lf\t%lf\n",val->arg[i],val->funcval[i]);
        }
    }
    else  fprintf(stderr,"Fehler!");
    fclose(fp);
}
 
void values_plot()
{
    FILE *gnuplot = popen("C:\\Users\\Patrick\\Dropbox\\3tes_Semester\\prog2\\Übung4\\newton.txt -persist","w");
 
    if (gnuplot)
    {
        fprintf(gnuplot, "set title 'P2-UE4: Newton'\n");
        fprintf(gnuplot, "set style data lines\n");
        fprintf(gnuplot, "cd 'C:\\Programme\\gnuplot\\bin'\n");
        fprintf(gnuplot, "f(x)=2*sin(x)-0.5\n");
        fprintf(gnuplot, "plot [2.8:3.1] \"p2ue4_newton.txt\" using 1:2 with steps, f(x)\n");
    }
    pclose(gnuplot);
}
 
void newton_iter(double x0, long steps, double precision, func_t func, func_t derivate)
{
    long i=0;
    double xn=0;
    values_t *val=values_allocate(steps);
 
    values_insert(val,x0,func(x0),0);
 
    for(i=0;i<steps && (fabs(val->funcval[i])>precision);i++)
    {
        xn=newton_step(val->arg[i],func,derivate);
        values_insert(val,xn,func(xn),i+1);
    }
 
    values_print(val);
 
    values_store(val);
    values_plot();
 
    values_free(val);
}
 
 
 
 
int main()
{
    newton_iter(3,10,0.0001,func1,func2);
 
    return 0;
}