import java.awt.*;
import java.applet.*;
import java.util.Random;

import graph.*;

public class analiza extends Applet {

      G2Dint graph1         = new G2Dint();   // Graph class to do the plotting
	  G2Dint graph2         = new G2Dint();   // Graph class to do the plotting
	  G2Dint graph3         = new G2Dint();   // Graph class to do the plotting
      
	  Axis xaxis1;
      Axis yaxis1;
	  Axis xaxis2;
      Axis yaxis2;
	  Axis xaxis3;
      Axis yaxis3;
      
	  DataSet data1;
	  DataSet data2;
	  DataSet data3;
	  DataSet data4;
	  DataSet data5;
	  DataSet data6;

	  	 

      TextField npoint			= new TextField(8);      // Number of points 
      TextField length			= new TextField(8);      // Length of signal
	  TextField hinit			= new TextField(8);      // Initial period
      TextField dh   			= new TextField(8);      // Period change
	  TextField noise			= new TextField(8);      // noise
	  TextField wmean			= new TextField(8);      // Window mean
	  TextField wwidth			= new TextField(8);      // Window width
	  TextField ileft			= new TextField(8);      // Left border
	  TextField iright			= new TextField(8);      // Right border
	  Button plot				= new Button("Refresh"); // Button to plot it.
      Label result				= new Label();			 // Label for result

	  Random rnd				= new Random();

      public void init() {
      	 Label title            = new Label("Phase shift analysis",Label.CENTER);
      	 Panel panel            = new Panel();
         GridBagLayout gridbag  = new GridBagLayout();
         GridBagConstraints  c  = new GridBagConstraints();
         Font font              = new Font("TimesRoman",Font.PLAIN,15);

         title.setFont(new Font("TimesRoman",Font.PLAIN,25));
         result.setFont(new Font("TimesRoman",Font.BOLD,16)); 
         
         setLayout(new BorderLayout() );
         add("North",title);
         add("Center",panel);

         npoint.setText(getParameter("NPOINTGP")); 
         length.setText(getParameter("LENGTHGP"));
         hinit.setText(getParameter("HINITGP"));
         dh.setText(getParameter("DHGP"));
         noise.setText(getParameter("NOISEGP"));
         wmean.setText(getParameter("WMEANGP"));
		 wwidth.setText(getParameter("WWIDTHGP"));
		 ileft.setText(getParameter("ILEFTGP"));
		 iright.setText(getParameter("IRIGHTGP"));

         panel.setLayout(gridbag);

         Label npointlb   = new Label("Number of Points:");        
		 Label lengthlb   = new Label("Length:");       
		 Label hinitlb    = new Label("Initial period:");         
		 Label dhlb       = new Label("Period change:");        
		 Label noiselb    = new Label("Noise intensity:");         
		 Label wmeanlb    = new Label("Window mean:");         
		 Label wwidthlb   = new Label("Window width:");         
		 Label ileftlb    = new Label("Left border:");         
		 Label irightlb   = new Label("Right border:");         
		 Label comment1   = new Label("Signal parameters:");         
		 Label comment2   = new Label("Window characteristic:");         
         Label comment3   = new Label("Interval borders");         
         Label author     = new Label("Author: Matija Jezersek"); 
		         
         npointlb.setFont(font);
         lengthlb.setFont(font);
		 hinitlb.setFont(font);
		 dhlb.setFont(font);
		 noiselb.setFont(font);
		 wmeanlb.setFont(font);
		 wwidthlb.setFont(font);
		 ileftlb.setFont(font);
		 irightlb.setFont(font);
		 comment1.setFont(font);
		 comment2.setFont(font);
		 comment3.setFont(font);
		 author.setFont(font);
		                   
         npoint.setFont(font);
         npoint.setBackground(Color.lightGray);
         length.setFont(font);
         length.setBackground(Color.lightGray);
		 hinit.setFont(font);
         hinit.setBackground(Color.lightGray);
		 dh.setFont(font);
         dh.setBackground(Color.lightGray);
		 noise.setFont(font);
         noise.setBackground(Color.lightGray);
		 wmean.setFont(font);
         wmean.setBackground(Color.lightGray);
		 wwidth.setFont(font);
         wwidth.setBackground(Color.lightGray);
		 ileft.setFont(font);
         ileft.setBackground(Color.lightGray);
		 iright.setFont(font);
         iright.setBackground(Color.lightGray);
		 plot.setFont(font);
         plot.setBackground(Color.red);


		 /* Graph1 position:
		 */
         c.weightx = 1.0;
         c.weighty = 1.0;
         c.gridwidth = 4;
		 c.gridheight = 6;
         c.fill  =  GridBagConstraints.BOTH;
         gridbag.setConstraints(graph1,c);

		 c.weightx = 0.0;
         c.weighty = 0.0;
		 c.gridwidth = 2;
		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.gridheight = 1;
		 c.fill  =  GridBagConstraints.NONE;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(comment1,c);

         c.gridwidth = 1;
		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.EAST;
		 gridbag.setConstraints(npointlb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(npoint,c);

		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.EAST;
		 gridbag.setConstraints(lengthlb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(length,c);
         
		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.EAST;
		 gridbag.setConstraints(hinitlb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(hinit,c);

		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.EAST;
		 gridbag.setConstraints(dhlb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(dh,c);

		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.NORTHEAST;
		 gridbag.setConstraints(noiselb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.NORTHWEST;
		 gridbag.setConstraints(noise,c);

		 /* Graph2 position:
		 */
		 c.weightx = 1.0;
         c.weighty = 1.0;
         c.gridwidth = 4;
		 c.gridheight = 3;
         c.fill  =  GridBagConstraints.BOTH;
         gridbag.setConstraints(graph2,c);

         c.weightx = 0.0;
         c.weighty = 0.0;
		 c.gridwidth = 2;
		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.gridheight = 1;
		 c.fill  =  GridBagConstraints.NONE;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(comment2,c);

         c.gridwidth = 1;
		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.EAST;
		 gridbag.setConstraints(wmeanlb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(wmean,c);

		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.NORTHEAST;
		 gridbag.setConstraints(wwidthlb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.NORTHWEST;
		 gridbag.setConstraints(wwidth,c);

		 /* Graph3 position:
		 */
 		 c.weightx = 1.0;
         c.weighty = 1.0;
         c.gridwidth = 4;
		 c.gridheight = 4;
         c.fill  =  GridBagConstraints.BOTH;
         gridbag.setConstraints(graph3,c);

         c.weightx = 0.0;
         c.weighty = 0.0;
		 c.gridwidth = 2;
		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.gridheight = 1;
		 c.fill  =  GridBagConstraints.NONE;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(comment3,c);

		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.EAST;
		 gridbag.setConstraints(ileftlb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(ileft,c);

		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.NORTHEAST;
		 gridbag.setConstraints(irightlb,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.NORTHWEST;
		 gridbag.setConstraints(iright,c);

		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.fill=GridBagConstraints.HORIZONTAL;
		 c.anchor = GridBagConstraints.WEST;
		 gridbag.setConstraints(result,c);

		 c.gridwidth = 1;
		 c.fill  =  GridBagConstraints.NONE;
		 c.gridwidth=GridBagConstraints.RELATIVE;
		 c.anchor = GridBagConstraints.CENTER;
		 gridbag.setConstraints(author,c);

		 c.gridwidth = 2;
		 c.gridwidth=GridBagConstraints.REMAINDER;
		 c.anchor = GridBagConstraints.CENTER;
		 gridbag.setConstraints(plot,c);


		 panel.add(graph1);
         panel.add(comment1);
         panel.add(npointlb);
         panel.add(npoint);
         panel.add(lengthlb);
		 panel.add(length);
         panel.add(hinitlb);
		 panel.add(hinit);
		 panel.add(dhlb);
		 panel.add(dh);
		 panel.add(noiselb);
		 panel.add(noise);
		 panel.add(graph2);
		 panel.add(comment2);
		 panel.add(wmeanlb);
		 panel.add(wmean);
		 panel.add(wwidthlb);
		 panel.add(wwidth);
		 panel.add(graph3);
		 panel.add(comment3);
		 panel.add(ileftlb);
		 panel.add(ileft);
		 panel.add(irightlb);
		 panel.add(iright);
         panel.add(result);
		 panel.add(author);
		 panel.add(plot);

         
         xaxis1 = graph1.createXAxis();
         xaxis1.setTitleText("X");
         yaxis1 = graph1.createYAxis();
		 yaxis1.setTitleText("Y");

         xaxis2 = graph2.createXAxis();
         xaxis2.setTitleText("Frequency");
         yaxis2 = graph2.createYAxis();
		 yaxis2.setTitleText("Amp.");

         xaxis3 = graph3.createXAxis();
         xaxis3.setTitleText("X");
         yaxis3 = graph3.createYAxis();
		 yaxis3.setTitleText("Phase");


         data1 = new DataSet();
         data2 = new DataSet();
         data3 = new DataSet();
         data4 = new DataSet();
         data5 = new DataSet();
         data6 = new DataSet();

		 data1.linecolor = Color.red;
		 data2.linecolor = Color.blue;
		 data3.linecolor = Color.red;
		 data4.linecolor = Color.blue;
		 data5.linecolor = Color.gray;
		 data6.linecolor = Color.red;

		 data1.legend(400,35,"signal 1");
		 data2.legend(400,45,"signal 2");
		 data3.legend(400,35,"spectrum 1");
		 data4.legend(400,45,"spectrum 2");
		 data5.legend(400,55,"window");
		 data6.legend(400,35,"phase shift");

		        
		 xaxis1.attachDataSet(data1);
         yaxis1.attachDataSet(data1);
         graph1.attachDataSet(data1);

		 xaxis1.attachDataSet(data2);
         yaxis1.attachDataSet(data2);
         graph1.attachDataSet(data2);


		 xaxis2.attachDataSet(data3);
         yaxis2.attachDataSet(data3);
         graph2.attachDataSet(data3);
		 
		 xaxis2.attachDataSet(data4);
         yaxis2.attachDataSet(data4);
         graph2.attachDataSet(data4);

		 xaxis2.attachDataSet(data5);
         yaxis2.attachDataSet(data5);
         graph2.attachDataSet(data5);

		 
		 xaxis3.attachDataSet(data6);
         yaxis3.attachDataSet(data6);
         graph3.attachDataSet(data6);

         
		 graph1.setDataBackground(new Color(255,200,175));
         graph1.setBackground(new Color(200,150,100));
		 
		 graph2.setDataBackground(new Color(255,200,175));
         graph2.setBackground(new Color(200,150,100));
		 
		 graph3.setDataBackground(new Color(255,200,175));
         graph3.setBackground(new Color(200,150,100));

         plot();

      }

	  	  
	  double Window(double x, double m, double s)
	  {
		 if((x < (m-s)) || (x > (m+s)))
			return 0.0;
		 else
		    return Math.cos((x-m)/(s*0.65))*Math.cos((x-m)/(s*0.65));
	  }

	  double Magnitude(double re, double im)
	  {
		 return Math.sqrt(re * re + im * im);
	  }

	    
	  
	  void DFT(double v[], double re[], double im[], int N)
	  {
		 int j, k;
		 double arg1 = 2.0 * Math.PI / (N * 1.0);
		 double arg;
		 for (j = 0; j < N; j++)
		 {
			arg = arg1*j;
			re[j] = 0.0;
			im[j] = 0.0;
			for (k = 0; k < N; k++)
			{
				re[j] += v[k] * Math.cos(k * arg);
				im[j] += v[k] * Math.sin(k * arg);
			}
		 }
		 double Nsq = Math.sqrt(N);
		 for (j=0; j < N; j++)
		 {
			re[j] /= Nsq ;
			im[j] /= Nsq ;
		 }
      }
	  
	  void IDFT(double uRE[], double uIM[], double cRE[], double cIM[], int N)
	  {
		 int j, k;
		 double arg1 = 2.0 * Math.PI / (N * 1.0);
		 double arg, arg2;
		 for (j = 0; j < N; j++)
		 {
			arg = arg1*j;
			cRE[j] = 0.0;
			cIM[j] = 0.0;
			for (k = 0; k < N; k++)
			{
				arg2 = arg * k;
				cRE[j] += (uRE[k] * Math.cos(arg2) + uIM[k] * Math.sin(arg2));
				cIM[j] += (uIM[k] * Math.cos(arg2) - uRE[k] * Math.sin(arg2));
			}
		 }
		 double Nsq = Math.sqrt(N);
		 for (j=0; j < N; j++)
		 {
			cRE[j] /= Nsq ;
			cIM[j] /= Nsq ;
		 }
      }
	  
	  double[] unwrap(double v[], int N)
	  {
		 double result[] = new double[N];
		 double sum = 0.0;
		 for(int i = 1; i<N; i++)
		 {
			if((v[i]-v[i-1]) > 3)		{ sum -= 2.0 * Math.PI; }
			else if((v[i]-v[i-1]) < -3)	{ sum += 2.0 * Math.PI; }
			result[i] = v[i] + sum;
		 }
		 return result;
	  }


	  double slope(double X[], double Y[], int l, int r, int N)
	  {
		 if((l < 0)||(r >= N)||(l > r))	{ return 0.0; }
		 double sumx = 0.0;
		 double sumy = 0.0;
		 int n = (r - l);
		 for (int i=l; i<=r; i++)
		 {
			sumx += X[i];
			sumy += Y[i];
		 }
		 
		 sumx = 0.0;
		 sumy = 0.0;
		 double mx = sumx / n;
		 double my = sumy / n;
		 double param1 = n*mx*my;
		 double param2 = n*mx*mx;

		 for (int i = l; i <= r; i++)
		 {
			sumx += X[i]*Y[i] - param1;
			sumy += X[i]*X[i] - param2;
		 }
	
		 if (sumy == 0.0)	{ return 10.0e200; }
		 return sumx/sumy;
	 }
	  
	  void plot() {
         int N;
         double L;
		 double period;
		 double deltaP;
		 double sigma;
		 double mean;
		 double width;
         double x;
		 double left;
		 double right;
         int count = 0;
         boolean error = false;

         try {
              N   = Integer.parseInt(npoint.getText());
         } catch(Exception e) {
              this.showStatus("Error with number of points!");
              System.out.println("Number of points error "+e.getMessage());
              return;
         }

         try {
            L  = Double.valueOf(length.getText()).doubleValue();
         } catch(Exception e) {
              this.showStatus("Error with length area number value!");
              System.out.println("length error "+e.getMessage());
              return;
         }

		 try {
            period  = Double.valueOf(hinit.getText()).doubleValue();
         } catch(Exception e) {
              this.showStatus("Error with initial period number value!");
              System.out.println("period error "+e.getMessage());
              return;
         }

         try {
            deltaP = Double.valueOf(dh.getText()).doubleValue();
         } catch(Exception e) {
              this.showStatus("Error with period change value!");
              System.out.println("period change error "+e.getMessage());
              return;
         }

		 try {
            sigma = Double.valueOf(noise.getText()).doubleValue();
         } catch(Exception e) {
              this.showStatus("Error with noise value!");
              System.out.println("noise error "+e.getMessage());
              return;
         }

		 try {
            mean = Double.valueOf(wmean.getText()).doubleValue();
         } catch(Exception e) {
              this.showStatus("Error with window mean value!");
              System.out.println("window mean error "+e.getMessage());
              return;
         }

		 try {
            width = Double.valueOf(wwidth.getText()).doubleValue();
         } catch(Exception e) {
              this.showStatus("Error with window width value!");
              System.out.println("window width error "+e.getMessage());
              return;
         }

		 try {
            left = Double.valueOf(ileft.getText()).doubleValue();
         } catch(Exception e) {
              this.showStatus("Error with left border of interval value!");
              System.out.println("left border of interval error "+e.getMessage());
              return;
         }

		 try {
            right = Double.valueOf(iright.getText()).doubleValue();
         } catch(Exception e) {
              this.showStatus("Error with right border of interval value!");
              System.out.println("right border of interval error "+e.getMessage());
              return;
         }


         double		d[]		= new double[2*N];
		 double		X[]		= new double[N];
		 double		Yref[]	= new double[N];
		 double		Y[]		= new double[N];
		 double		W[]		= new double[N];
			 

         this.showStatus("Calculating points!");
		 
		 double omega1, omega2;
		 
		 omega1 = 6.283185307/period;
		 omega2 = 6.283185307/(period+deltaP);
		 
		 int i,j;
		 for(i=0; i<N; i++) 
   		 {

             X[i] = i*(L/N);
			 Yref[i]	= Math.sin(X[i]*omega1) + rnd.nextGaussian()*sigma;
			 Y[i]		= Math.sin(X[i]*omega2) + rnd.nextGaussian()*sigma;
		 }

		 count = 0;
		 for(i=0; i<N; i++) 
   		 {
			 d[count] = X[i];
			 d[count+1] = Yref[i]; 		             
			 count += 2;
         }
		 data1.deleteData();
		 try {
               data1.append(d,N);
         } catch(Exception e) {
             this.showStatus("Error while appending data1!"); 
             System.out.println("Error while appending data!");
             return;
		 }

		 count = 0;
		 for(i=0; i<N; i++) 
   		 {
			 d[count] = X[i];
			 d[count+1] = Y[i]; 		             
			 count += 2;
         }
		 data2.deleteData();
		 try {
               data2.append(d,N);
         } catch(Exception e) {
             this.showStatus("Error while appending data2!"); 
             System.out.println("Error while appending data!");
             return;
		 }

		/*
		** DFT
		*/

		 double	QREref[]	= new double[N];
		 double	QIMref[]	= new double[N];
		 double	QRE[]		= new double[N];
		 double	QIM[]		= new double[N];

		 try {
              DFT(Yref,QREref,QIMref, N);
			  DFT(Y, QRE, QIM, N);
         } catch(Exception e) {
              this.showStatus("Error DFT points!");
              System.out.println("DFT error "+e.getMessage());
              return;
         }
		 
		 count = 0;
		 for(i=0; i<N; i++) 
   		 {
			 d[count++] = i;
			 d[count++] = Magnitude(QREref[i],QIMref[i]); 		             
			 //count += 2;
         }
		 
		 data3.deleteData();
		 try {
               data3.append(d,N);
         } catch(Exception e) {
             this.showStatus("Error while appending data3!"); 
             System.out.println("Error while appending data!");
             return;
		 }

		 count = 0;
		 for(i=0; i<N; i++) 
   		 {
			 d[count] = i;
			 d[count+1] = Magnitude(QRE[i],QIM[i]); 		             
			 count += 2;
         }
		 
		 data4.deleteData();
		 try {
               data4.append(d,N);
         } catch(Exception e) {
             this.showStatus("Error while appending data4!"); 
             System.out.println("Error while appending data!");
             return;
		 }
		 
		 count = 0;
		 for(i=0; i<N; i++) 
   		 {
			 W[i] = Window(i,mean,width);
			 QREref[i] *=W[i];
			 QIMref[i] *=W[i];
			 QRE[i] *=W[i];
			 QIM[i] *=W[i];
			 d[count] = i;
			 d[count+1] = W[i]; 		             
			 count += 2;
         }

		 
		 data5.deleteData();
		 try {
               data5.append(d,N);
         } catch(Exception e) {
             this.showStatus("Error while appending data5!"); 
             System.out.println("Error while appending data!");
             return;
		 }
		 
		 double	GREref[]	= new double[N];
		 double	GIMref[]	= new double[N];
		 double	GRE[]		= new double[N];
		 double	GIM[]		= new double[N];

		 double	PHIref[]	= new double[N];
		 double	PHI[]		= new double[N];
		 
		 try {
		 IDFT(QREref, QIMref, GREref, GIMref, N);
		 IDFT(QRE, QIM, GRE, GIM, N);
		 } catch(Exception e) {
              this.showStatus("Error DFT points!");
              System.out.println("DFT error "+e.getMessage());
              return;
         }

		 for(i=0; i<N; i++) 
   		 {
			 PHIref[i]	= Math.atan2(GIMref[i], GREref[i]);
			 PHI[i]		= Math.atan2(GIM[i], GRE[i]);
         }

		 PHIref = unwrap(PHIref, N);
		 PHI = unwrap(PHI, N);
		 count = 0;
		 for(i=0; i<N; i++) 
   		 {
			 PHI[i] -= PHIref[i];
			 d[count]	= X[i];
			 d[count+1] = PHI[i]; 		             
			 count += 2;
         }

		 data6.deleteData();
		 try {
               data6.append(d,N);
         } catch(Exception e) {
             this.showStatus("Error while appending data6!"); 
             System.out.println("Error while appending data!");
             return;
		 }
            
		 Double Left = new Double(left*N/L);
		 Double Right = new Double(right*N/L);

		 double Slope = slope(X, PHI, Left.intValue(), Right.intValue(), N);
		 result.setText(/*new String*/("SLOPE: " + Double.toString(Slope)));

         graph1.repaint();
		 graph2.repaint();
		 graph3.repaint();
      }



     public boolean action(Event e, Object a) {

         if(e.target instanceof Button) {
             if( plot.equals(e.target) ) {
                  plot();
                  return true;
             }
         }


         return false;
       }




}




