/*
Kvantova jama
Ondrej Psencik


*/

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.lang.System.*;
import java.lang.Math.*;
import java.lang.*;
import java.lang.Thread;
import java.text.NumberFormat;
import java.math.*;


//Applet zije
public class HarmonickyOscilator extends Applet implements ActionListener, AdjustmentListener{
int width=600;
int height=400;
SimPanel plocha;
SelArea selekty;
Button animace;
Button zobr,plus,minus,pred,po, restime;
Checkbox vypln;
Label cas,dtcas;
Label popis1,popis2, popis3;
Vlakno vlak;	
int stav=0;
Scrollbar rychlost, scrldt;


	public void init()
	{
	  resize(width,height);
	  setLayout(null);
	  setBackground(Color.lightGray);
	  
	  Font f=new Font("Helvetica",Font.PLAIN,12);
	  setFont(f);

	  selekty=new SelArea(10,10,this);
	  add(selekty);

	  plocha=new SimPanel(340,40,createImage(250,270),selekty);
	  add(plocha);
	  
	  
	  animace=new Button("Run");
	  add(animace);
	  animace.setSize(50,30);
	  animace.setLocation(420,320);
	  animace.addActionListener(this);

/*  zobr=new Button("Stop");
	  add(zobr);
	  zobr.setSize(50,30);
	  zobr.setLocation(420,320);
	  zobr.addActionListener(this);
	  
/*  	  plus=new Button("+");
	  add(plus);
	  plus.setSize(15,15);
	  plus.setLocation(380,360);
	  plus.addActionListener(this);

  	  minus=new Button("-");
	  add(minus);
	  minus.setSize(15,15);
	  minus.setLocation(490,360);
	  minus.addActionListener(this);
*/
  	  restime=new Button("Reset");
	  add(restime);
	  restime.setSize(50,30);
	  restime.setLocation(480,320);
	  restime.addActionListener(this);


  	  pred=new Button("<");
	  add(pred);
	  pred.setSize(50,30);
	  pred.setLocation(360,320);
	  pred.addActionListener(this);

  	  po=new Button(">");
	  add(po);
	  po.setSize(50,30);
	  po.setLocation(540,320);
	  po.addActionListener(this);


		popis1=new Label("Časový krok:");
	  add(popis1);
	  popis1.setSize(popis1.getMinimumSize());
	  popis1.setLocation(20,316);

	/*	popis2=new Label("Aktualni cas(t):");
	  add(popis2);
	  popis2.setSize(popis2.getMinimumSize());
	  popis2.setLocation(290,375);
	  */
/*
		dtcas=new Label(Double.toString(plocha.dt));
	  add(dtcas);
	  dtcas.setSize(90,15);
	  dtcas.setLocation(400,360);
*/	  
	/*	cas=new Label(Double.toString(plocha.t));
	  add(cas);
	  cas.setSize(90,15);
	  cas.setLocation(400,380);
*/
		rychlost=new Scrollbar(Scrollbar.HORIZONTAL,90,1,1,100);
		rychlost.setSize(100,15); rychlost.setLocation(130,340);
		add(rychlost);
		rychlost.addAdjustmentListener(this);

		scrldt=new Scrollbar(Scrollbar.HORIZONTAL,30,1,1,50);
		scrldt.setSize(100,15); scrldt.setLocation(20,340);
		add(scrldt);
		plocha.dt=0.001*30;
		scrldt.addAdjustmentListener(new AdjustmentListener(){
			  public void adjustmentValueChanged(AdjustmentEvent e)
			  {
			  	  plocha.dt=0.001*e.getValue();
    		  }
			});


		popis3=new Label("Rychlost animacniho vlakna:");
	  add(popis3);
	  popis3.setSize(popis3.getMinimumSize());
	  popis3.setLocation(130,316);

	  vypln=new Checkbox ("Výplň grafu",true);
	  vypln.setSize(100,20);
	  vypln.setLocation(340,10);
    add(vypln);
    vypln.addItemListener(new ItemListener(){
    	
    	  public void itemStateChanged(ItemEvent e)
    	  { 
    	  	  if(e.getStateChange()==ItemEvent.SELECTED)
    	  	  {plocha.vypln=1; }
    	  	  else
    	  	  {plocha.vypln=0; }
    	  	  if(vlak==null)plocha.Kalkuluj();    	  	  
    	  }
     
	
    });

    plocha.vypln=1; plocha.Kalkuluj();
    animace.setVisible(true);
	  repaint();
	}
	

  public void adjustmentValueChanged(AdjustmentEvent e) 
	{
     plocha.simrychlost=100-e.getValue();
	}


	public void paint(Graphics g)
	{
     g.drawRoundRect(1,1,width-2,height-2,30,30);
	}
	
  public void actionPerformed(ActionEvent e)
	{
		
		if(e.getActionCommand()=="Run"){
			if(stav==0){
					vlak=new Vlakno(plocha);
					vlak.start();
					stav=1;
					pred.setVisible(false);					
					po.setVisible(false);
					animace.setLabel("Stop");					
			}
		} else

		if(e.getActionCommand()=="Reset"){
			plocha.t=1;
		//	cas.setText(Double.toString(plocha.t));
			repaint();
			if(animace.getLabel()=="Run")plocha.Kalkuluj();
		} else
		
		if(e.getActionCommand()=="Stop"){
			if(stav==1){
					if (vlak!=null) vlak.stop();
					vlak=null;
					
					pred.setVisible(true);					
					po.setVisible(true);					
					animace.setLabel("Run");					
					
					repaint();
					stav=0;
					if (vlak!=null)
					  while(vlak.isAlive());
					
					plocha.Kalkuluj();			  			
			}
		} else

		if(e.getActionCommand()=="+"){
			plocha.dt*=10.0;
		//	dtcas.setText(Double.toString(plocha.dt));
		//	dtcas.repaint();
		} else

		if(e.getActionCommand()=="-"){
			plocha.dt/=10.0;
		//	dtcas.setText(Double.toString(plocha.dt));
		//	dtcas.repaint();
		} else

		if(e.getActionCommand()==">"){
			plocha.t+=plocha.dt;
		//	cas.setText(Double.toString(plocha.t));
			repaint();
			plocha.Kalkuluj();			
		} else
		
		if(e.getActionCommand()=="<"){
			plocha.t-=plocha.dt;
		//	cas.setText(Double.toString(plocha.t));
			repaint();
			plocha.Kalkuluj();
		}

		

	}

}


//Deklarace Simulacniho panelu
class SimPanel extends Panel 
{
	Image MyBuffer;	
	Graphics MyGr,OldGr;
	MediaTracker mt;
  
  
  Color simbarva=new Color(102,130,162);
  Color grafbarva=Color.black;
  
  int simrychlost=10;
  
  int width=250;
  int height=270;
  int mult=20; //multiplikace osy
  double rozdilx=210;
  
  int vypln=1;
  double dt=0.001;
  double d=1;
  double t=1;
  double fixt,wtx;
  double korekce;
	SelArea selekty;  	
	
	int []aryN=new int[11];
  double []aryCn=new double[11];
  double []alfan=new double[11];
  int [][]primky=new int[3][11];
  double [][]polefi=new double[212][11];
  int []parab=new int[212];
  
      double mert=104.0;//21.0;     
      double mertpar=21;//1.25*21;           

     double pulkad=5;
     int pulroz=21;
	
	public SimPanel(int x, int y, Image i, SelArea sel)
	{
		selekty=sel;
	  setSize(width,height);
	  setLocation(x,y);
	  mt=new MediaTracker(this);
	  MyBuffer = i;
	  mt.addImage(MyBuffer,1);
    try {mt.waitForAll();}
    catch(Exception e) {};
    MyGr=MyBuffer.getGraphics();
  
    MyGr.setColor(simbarva);
    MyGr.fillRoundRect(0,0,250,270,20,20);
    
  /*  MyGr.setColor(grafbarva);
    MyGr.drawLine(20,20,20,280);
    MyGr.drawLine(20,280,230,280);
    MyGr.drawLine(230,280,230,20);
   */
    for(int j=1;j<11;j++){
    	 alfan[j]=fan(j-1);
    }

     double pulkad=5;
     int pulroz=21;     
     double py;

     for(int l=1; l<212; l+=1){
     	for(int j=1; j<11; j++)
        polefi[l][j]=FIn((l-1.0)/pulroz-pulkad,j-1);
     }
     


    for(int j=1;j<212;j++){
		  py=(j-1.0)/pulroz-pulkad;    	
       parab[j]=(int)(0.5*mertpar*py*py);
    }
    
    for(int j=1;j<11;j++){
    	  korekce+=j;
    	  primky[1][j]=(int)((rozdilx/2)-Math.sqrt((j-0.5) / 0.5 )*pulroz +20);
		  primky[2][j]=(int)((rozdilx/2)+Math.sqrt((j-0.5) / 0.5)*pulroz +20);
		  //primky[2][j]=-Math.sqrt((j-0.5)/0.5);
    }
    
    

     


    Konverse();
    Kalkuluj();
    repaint();   
	}
	
	public double fan(int i)
	{ double d=1;
	   for(int j=1; j<=i; j++){
	   	  d=d*j;
	   }
	   //return(1/korekce);
	   return( 1/ ( Math.sqrt(d*Math.sqrt(Math.PI)*Math.pow(2.0,i+0.0) ) ) );
	}
	
	public double H(int n, double x)
	{ double h1,h2, hn;
	  h2=1;
	  h1=2*x;
	  hn=1;
	  if (n==0) return(1);
		if (n==1) return(2*x);

     for(int i=2; i<=n; i+=1){
       hn=2*x*h1-2*(i-1)*h2;	
       h2=h1; h1=hn;
     }
     return(hn); 	
	}
	
	public double FIn(double x, int n)
	{
     return( alfan[n+1]*H(n,x)*Math.exp(-x*x/2.0));
	}
	
	public double En(int n)
	{
	  return((Math.PI*Math.PI*n*n)/(2*d*d));
	}
	
	public void FI(double t, double x, int xx)
	{  double Cn,Re,Im;
		 //int n;
		 
		 Re=0;
		 Im=0;
		 
	   for(int i=1;i<=10;i++){
	   	Cn=aryCn[i];
	   	//System.out.println(Cn);
	   	//n=aryN[i];
	   	if (Cn>0){
	   	  Re+=Math.cos((i-1+0.5)*t)*Cn*polefi[xx+1][i];//FIn(x,i-1);  // *polefi[xx+1][i];
	   	  Im+=Math.sin((i-1+0.5)*t)*Cn*polefi[xx+1][i];//FIn(x,i-1); // *polefi[xx+1][i];
	   	}
	   }	
		 wtx=mert*(Re*Re+Im*Im);
	}
	
	
	public void Konverse(int poradi)
	{
   	if (selekty.ArCn[poradi].getValue()==99) aryCn[poradi]=0;
   	else
   	aryCn[poradi]=(double)(100-selekty.ArCn[poradi].getValue())/100;
   	//System.out.println(aryCn[poradi]);
	}

	public void Konverse()
	{
	   for(int i=1;i<=10;i++){
	   	Konverse(i);
	   	//aryCn[i]=(double)(100-selekty.ArCn[i].getValue())/100;
//	   	aryN[i]=i-1;//Integer.valueOf(selekty.ArN[i].getText()).intValue();
	   }	
	}
	
	public void Kalkuluj()
	{  int x,y,sx,sy;
     //MyGr.drawRoundRect(1,1,width-2,height-2,15,15);
     //double mert=21.0;     
     
     MyGr.setColor(simbarva);
     MyGr.fillRoundRect(0,0,250,270,20,20);

     MyGr.setColor(Color.black);    
    	FI(t,0,0);
    	x=20; y=(int)(wtx);
    	     
     if(vypln==0){
     for(int i=21; i<230; i+=1){
      	sx=x; sy=y;     	
      	FI(t,(i-21.0)/pulroz-pulkad,i-21);
      	x=i; y=(int)(wtx);//*mult);
      	MyGr.drawLine(sx,250-sy,x,250-y);
      //	MyGr.drawLine(sx,280-sy,sx,279);//fill
     }}
     else{
     for(int i=21; i<230; i+=1){
      	sx=x; sy=y;     	
      	FI(t,(i-21.0)/pulroz-pulkad,i-21);
      	x=i; y=(int)(wtx);//*mult);
      if((sy!=0) && (y!=0)){
      	  MyGr.drawLine(sx,250-sy,x,250-y);
      	  MyGr.setColor(new Color((y*2>255)?255:y*2,0,0));
      	  MyGr.drawLine(sx,250-sy,sx,249);//fill
      }
     }}

     MyGr.setColor(Color.green);
     for(int j=10;j<201;j++){
       MyGr.drawLine(j+19,250-parab[j],j+20,250-parab[j+1]);
     }

		MyGr.setColor(Color.yellow);

		for(int j=0;j<10;j++){
			int yy=(int)((j+0.5)*mertpar);
			MyGr.drawLine(primky[1][j+1]+1,250-yy,primky[2][j+1]-1,250-yy);
			MyGr.drawString(Integer.toString(j),230,250-yy);
			
		}
		
		
		
/*		int yy=(int)(mert*3+210/2)+20;
		MyGr.setColor(Color.red);
		MyGr.drawLine(yy,0,yy,250);*/
     
     	
     	
    repaint();
	}
	
	public void update(Graphics g)
	{
	  paint(g);	
	}
	
	public void paint(Graphics g)
	{
		g.drawImage(MyBuffer,0,0,this);		
	}
	
}

class SelArea extends Panel implements AdjustmentListener, ActionListener
{ 
	int width=320;
	int height=300;
  

  Button refresh;
  Scrollbar s;
  TextField t;
  Font f;
  HarmonickyOscilator mparent;
  Label l;
  Color pozadColor=new Color(177,176,105);
  
  
  Scrollbar[] ArCn=new Scrollbar[11];
  	TextField[] ArN=new TextField[11];
  	int z;
  
  public SelArea(int x, int y, HarmonickyOscilator parent)
  	{  
  		mparent=parent;
		setSize(width,height);
		setLocation(x,y);
		setLayout(null);

    refresh=new Button("Uplatni zmeny");
    refresh.setSize(80,20);
    refresh.setLocation(10,270);
  //  add(refresh);
  /*  refresh.addActionListener(new ActionListener(){
      	
      public void actionPerformed(ActionEvent e){
        mparent.plocha.Konverse();		    
        mparent.plocha.Kalkuluj();
      }
	   }
  	  );
*/

	  f=new Font("Helvetica",Font.PLAIN,14);
 	
 		l=new Label("Váha stavů:");
		l.setLocation(20,20);
		l.setFont(f);
		l.setBackground(pozadColor);
		l.setSize(170,30); 
		add(l);

	  f=new Font("Helvetica",Font.PLAIN,10);
	  setFont(f);
		
		for(int i=1;i<=10;i++){
			s=new Scrollbar(Scrollbar.VERTICAL,50,1,0,100);
			s.setSize(15,100); s.setLocation(i*30-15,100);
			add(s);
			if((i==1) || (i==2)) {s.setValue(0);}
			else s.setValue(100);
			z=i;
			s.addAdjustmentListener( new AdjustmentListener() {
				  int poradi=z;
				  
				  public void adjustmentValueChanged(AdjustmentEvent e)
				  {
		         mparent.plocha.Konverse(poradi);		    
		         if(mparent.animace.getLabel()=="Run")
		         	   mparent.plocha.Kalkuluj();
				  }
			  }
			);
			ArCn[i]=s;
			l=new Label(Integer.toString(i-1));
			l.setSize(20,20); l.setLocation(i*30-18,70);
			l.setBackground(pozadColor);
			add(l);
			l.setAlignment(Label.CENTER);
			//ArN[i]=l;
		}
	}
	

 public void actionPerformed(ActionEvent e)
 {
     if(mparent.vlak!=null) mparent.vlak.suspend();
     mparent.plocha.Konverse();
     if(mparent.vlak!=null) mparent.vlak.resume();     
     mparent.plocha.Kalkuluj();
 }

 public void adjustmentValueChanged(AdjustmentEvent e) 
	{
	}
  	
  	

  	
  	public void paint(Graphics g)
	{
		g.setColor(pozadColor);
    g.fillRoundRect(1,1,width-2,height-2,15,15);		
		g.setColor(Color.black);
    g.drawRoundRect(1,1,width-2,height-2,15,15);		
    
	}
	


	
}

class Vlakno extends Thread
{
  SimPanel panel;
  
   public Vlakno(SimPanel panel)
	{
		this.panel=panel;
	}
	
	public void run()
	{
		//panel.t=0;
		while(true){
		  panel.t+=panel.dt;		
		  panel.Kalkuluj();
		  
		  try{sleep(panel.simrychlost);}
			catch(InterruptedException e){};
			
		}
	}
}