import java.io.*;
import javax.swing.*;
class ff extends f_x
{
 public double T=1.0/50.0;  //sn
public double func(double t)
{   double a=1.0;
    double x0,x1,xn;
    x0=0;x1=T/2;xn=T;
    for(int i=0;i<100;i++)
    {   x0=i*T;x1=T/2.0*(i+1);xn=T*(i+1);
         
	    if(t>=x0 && t<xn) {
	                           
                               if(t>=x0 && t<x1) a=1.0;
	                           else if(t>=x1 && t<xn) a=-1.0;
	                           break;
	                         }
	                         System.out.println("t="+t+"x0="+x0+"x1="+x1+"xn="+xn+"a="+a);
	}
    return a;
}
}

// Fourier approximation
class Fourier
{ 
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 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 Fourier(f_x f,double x0i,double xni,int mi,int ni)
{
m=mi;
n=ni;
a=new double[n+1];
b=new double[n+1];
xj=new double[2*m+1];
zj=new double[2*m+1];
yj=new double[2*m+1];
x0=x0i;
xn=xni;
for(int k=0;k<=2*m;k++)
{xj[k]=x0+(xn-x0)/(2*m)*k;
 yj[k]=f.func(xj[k]);
 zj[k]=z_x(xj[k]);
}
  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(f_x f,double x0i,double xni,int ni)
{	
	double xx[][]=new double[4][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); 
	  xx[2][i]=f.func(x1);
	  xx[3][i]=xx[2][i]-xx[1][i];
	}
	Plot pp=new Plot(xx[0],xx[1]);
	pp.addData(xx[0],xx[2]);
    pp.setPlabel("Discrete Trigonometric approximation function n="+(a.length-1));
    pp.setXlabel("t time second");
     pp.setYlabel("i current ampere");
    double xx1[]={x0i,xni};
    double yy1[]={0,0};
    pp.addData(xx1,yy1);
	pp.plot();
}
	public void plot_error(f_x f,double x0i,double xni,int ni)
    { double xx[][]=new double[4][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); 
	  xx[2][i]=f.func(x1);
	  xx[3][i]=xx[2][i]-xx[1][i];
	  }
	Plot pp=new Plot(xx[0],xx[3]);
    pp.setPlabel("Discrete Trigonometric approximation error n = "+(a.length-1));
        pp.setXlabel("t time second");
     pp.setYlabel("error i current ampere");
    double xx1[]={x0i,xni};
    double yy1[]={0,0};
    pp.addData(xx1,yy1);
	pp.plot();
    }
public double[][] result(f_x f)
{   double xx[][]=new double[4][2*m];
    for(int i=0;i<2*m;i++)
	{ 
	  xx[0][i]=xj[i];
	  xx[1][i]=func(xj[i]); 
	  xx[2][i]=f.func(xj[i]);
	  xx[3][i]=xx[2][i]-xx[1][i];	  
	}
	return xx;
}

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

}