import java.io.*;
import javax.swing.*;

// Fourier approximation
class Fourier1
{ 
public double a[];
public double b[];
public double xj[];
public double zj[];
public double yj[];
public double x0,xn;
public int m; //(2*m+1) data points
public int n; //degree n Fourier function 

public void read_data(String s1)
{
double a[][]=Text.readDoubleT(s1);
int mm=a[0].length;
m=mm/2;
x0=a[0][0];
xn=a[0][mm-1];
xj=new double[mm];
zj=new double[mm];
yj=new double[mm];
for(int k=0;k<=2*m;k++)
{xj[k]=a[0][k];
 yj[k]=a[1][k];
 zj[k]=z_x(xj[k]);
}
}

public double z_x(double x)
{double zz=2.0*Math.PI*(x-x0)/(xn-x0)-Math.PI;
 return zz;
}

public double x_z(double z)
{double xx=(z+Math.PI)/(2.0*Math.PI)*(xn-x0)+x0;
 return xx;
}
        
public Fourier1(String name,int ni)
{
read_data(name);
n=ni;
a=new double[n+1];
b=new double[n+1];
  for(int k=0;k<=n;k++)
  {
  a[k]=0;
  b[k]=0;
  for(int j=0;j<2*m;j++)
    { a[k]+=1.0/m*yj[j]*Math.cos(k*zj[j]);
      b[k]+=1.0/m*yj[j]*Math.sin(k*zj[j]);
    }
  }
}
 
public  double func(double x)
{
double cc=a[0]/2.0+a[n]*Math.cos(n*z_x(x));
for(int k=1;k<n;k++)
{cc+=a[k]*Math.cos(k*z_x(x))+b[k]*Math.sin(k*z_x(x));}
return cc;
}

public void plot_func(double x0i,double xni,int ni)
{	
	double xx[][]=new double[2][ni+1];
	double x1=0;
    for(int i=0;i<=ni;i++)
	{ x1=x0i+(xni-x0i)*i/ni;
	  xx[0][i]=x1;
	  xx[1][i]=func(x1); 
	}
	Plot pp=new Plot(xx[0],xx[1]);
	pp.addData(xj,yj);
	pp.setPlotType(1,32);
    pp.setPlabel("Discrete Trigonometric least square n="+(a.length-1));
	pp.plot();
}

public double[][] result()
{   double xx[][]=new double[4][2*m];
    for(int i=0;i<2*m;i++)
	{ 
	  xx[0][i]=xj[i];
	  xx[1][i]=yj[i];
	  xx[2][i]=func(xj[i]); 
	  xx[3][i]=xx[2][i]-xx[1][i];   
	}
	return xx;
}

public static void main(String arg[])
{
	int n=Integer.parseInt(JOptionPane.showInputDialog("number of terms in the Trigonometric function approximation Sn(x): n="));
	String name=JOptionPane.showInputDialog("Data file name (a.txt)");
	Fourier1 Pa=new Fourier1(name,n);
    String s1[]={"x","Fourier f(x)","f(x)","error"};
	Text.print(Text.T(Pa.result()),s1,"Discrete Fourier curve fitting n = "+n+"m = "+Pa.m);
    Text.printT(Pa.a,"a");
    Text.printT(Pa.b,"b");
    Pa.plot_func(Pa.x0,Pa.xn,100);
}
}