/*
	Ohyb paprsku v okoli garvitacni cocky
  Semestralni prace z PJW
  naprogramoval Ondrej Psencik
  1999
*/


import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.lang.System.*;
import java.lang.Math.*;
import java.lang.*;
import java.awt.Adjustable.*;

//Trida PaprsevVOkoliCocky je applet
public class PaprsekVOkoliCocky extends Applet implements /*ItemListener*/ ActionListener, AdjustmentListener {
	int sirka = 600; static int sirkaplochy=390;
	int vyska = 300; static int vyskaplochy=250;
	double G=6.67e-11;
	double c=2.997925e8;

	static int mode=1;
	int posicex = 155;
	int posicey = 115;
	double Hmotnost = 1e34;
	double meritko=1e7;
	CheckboxGroup cbg;
	Checkbox ch1, ch2;
	Epanel p=new Epanel();
	TextField t;
	Scrollbar s;
	String defhmot=new String("1e34");
	boolean simuluj=false;
   boolean pocmarano=false;
	CentralniTeleso Teleso;
	Button bstart = new Button("Start");
  ZdrojPaprsku [] zdroje=new ZdrojPaprsku[10]; 
	int pocet=2;
	boolean inprc=false;

//initialisacni rutiny
public void init() {
		setBackground(Color.white);
		p.setBackground(Color.white);		
		p.setLocation(1,1);
		resize(sirka,vyska);
		setLayout(null);
		p.setLayout(null);
				
	  add(p);
	  p.setSize(sirkaplochy,vyskaplochy);
		
		Teleso = new CentralniTeleso(Hmotnost,posicex,posicey);		
		zdroje[0] = new ZdrojPaprsku(60,70,p.getGraphics());
		zdroje[1] = new ZdrojPaprsku(60,170,p.getGraphics());
		zdroje[0].lastx=50;
		zdroje[1].lastx=50;		
		

		p.add (zdroje[0]);
		p.add (zdroje[1]);
		p.add(Teleso);
		bstart.setSize(39,23);

		
		bstart.setLocation(10,270);
		add(bstart);
		bstart.addActionListener(this);
		s=new Scrollbar(Scrollbar.HORIZONTAL,50,5,0,100);	
		s.setLocation(400,vyskaplochy-170);
		s.setSize(70,10);
		add(s);
		s.addAdjustmentListener(this);
		
		repaint();
	}
	
//kresli grafiku appletu	
	public void paint(Graphics g) {
		if (simuluj) p.getGraphics().clearRect(0,0,500,500);

	  g.drawRect(0,0,sirkaplochy+1,vyskaplochy+1);
		g.drawString("Hmotnost v kg",400,vyskaplochy-145);
		g.drawString(Double.toString(Hmotnost),400,vyskaplochy-130);
		
	
		g.setColor(Color.blue);
	  g.drawLine(sirkaplochy+10,vyskaplochy,sirkaplochy+20,vyskaplochy);
		g.drawLine(sirkaplochy+10,vyskaplochy-100,sirkaplochy+20,vyskaplochy-100);
		g.drawLine(sirkaplochy+15,vyskaplochy,sirkaplochy+15,vyskaplochy-100);
		double d;
		d=meritko*100/1000; 
		g.drawString(Double.toString(d)+" km",sirkaplochy+30,vyskaplochy-50);

	  int i;

		for (i=0;i<pocet;i++){ 
		  if (simuluj) {
		  	  zdroje[i].repaint();
				nakreslidrahu(zdroje[i]);

		  }
		}
		if (simuluj) simuluj=false;
	}
	
//vypocita drahu paprsku svetla daneho zdroje
	public void nakreslidrahu(ZdrojPaprsku Zdroj) {
		pocmarano=true;
		double zx=(Zdroj.getLocation().x+Zdroj.rozmer/2)*meritko;
		double zy=(Zdroj.getLocation().y+Zdroj.rozmer/2)*meritko;		
		double tx=(Teleso.getLocation().x+Teleso.polomer/2)*meritko;
		double ty=(Teleso.getLocation().y+Teleso.polomer/2)*meritko;
     
		double vektx=(Zdroj.lastx-Zdroj.rozmer/2)*meritko;
		double vekty=(Zdroj.lasty-Zdroj.rozmer/2)*meritko;
		int i,cx,cy;
		double r,dc,dl,rx,ry;
		double time=0.2;
		double px1,px2,py1,py2,px,py;
		double v=Math.sqrt(vektx*vektx+vekty*vekty);
		double dd;
				
		for (i=0;i<300;i++) {
			v=Math.sqrt(vektx*vektx+vekty*vekty);
			rx=(tx-zx);
			ry=(ty-zy);
			
			r=Math.sqrt(rx*rx+ry*ry);
			dl=time*time*G*Hmotnost/(r*r*2);
			
			px1=dl*(tx-zx)/r;
			py1=dl*(ty-zy)/r;
	  
	
			px2=time*time*vektx*c/v;
			py2=time*time*vekty*c/v;
     	 	
			px=px1+px2;
			py=py1+py2;
			
			Double xx=new Double((zx+px)/meritko);
			Double yy=new Double((zy+py)/meritko);
			Double cxx=new Double(zx/meritko);
			Double cyy=new Double(zy/meritko);
			cx=cxx.intValue();
			cy=cyy.intValue();

   		Zdroj.pole[0][i]=cx;
			Zdroj.pole[1][i]=cy;
			Zdroj.pole[2][i]=xx.intValue();
			Zdroj.pole[3][i]=yy.intValue();
			
			zx=zx+px;
			zy=zy+py;
			vektx=px;
			vekty=py;
		}
	}

//prekresli drahu Zdroje dvetla bilou barvou
	public void smazdrahu(ZdrojPaprsku Zdroj){
		int i;
		Zdroj.globgraf.setColor(Color.white);
		for (i=0; i<300; i++) {
			Zdroj.globgraf.drawLine(Zdroj.pole[0][i],Zdroj.pole[1][i],Zdroj.pole[2][i],Zdroj.pole[3][i]);
		}
	}
	
//kresli drahu jednoho Zdroje promennou barvou
	public void kreslidrahu(ZdrojPaprsku Zdroj){
		int i;
		Color c;
		Zdroj.globgraf.setColor(Color.black);
		Polygon p=new Polygon();
		
		p.addPoint(Teleso.getLocation().x,Teleso.getLocation().y);
		p.addPoint(Teleso.getLocation().x+Teleso.polomer,Teleso.getLocation().y);		
		p.addPoint(Teleso.getLocation().x+Teleso.polomer,Teleso.getLocation().y+Teleso.polomer);		
		p.addPoint(Teleso.getLocation().x,Teleso.getLocation().y+Teleso.polomer);		
		
		for (i=0; i<300; i++) {
			c=new Color(i);
			if (p.contains(Zdroj.pole[2][i],Zdroj.pole[3][i]))
			  break;
		 	Zdroj.globgraf.setColor(c);
			Zdroj.globgraf.drawLine(Zdroj.pole[0][i],Zdroj.pole[1][i],Zdroj.pole[2][i],Zdroj.pole[3][i]);
		
		}
	}

//iterativne kresli drahy od vsech zdoju
  public void kreslidrahy(){
	  int i;
		for (i=0;i<pocet;i++){ 
				smazdrahu(zdroje[i]);
				nakreslidrahu(zdroje[i]);
				kreslidrahu(zdroje[i]);
	  }
	}

  
//stisk tlacitka  
  public void actionPerformed(ActionEvent e) {
  	 simuluj=true;
  	 kreslidrahy();
  }

//posuv scrollbaru
	public void adjustmentValueChanged(AdjustmentEvent e) {
		int posice=e.getValue();
		double d=(1.0+(posice-50.0)/100.0)*1e34;
		Hmotnost=d;
		simuluj=true;
		kreslidrahy();
		getGraphics().clearRect(400,vyskaplochy-140,150,20);
		getGraphics().drawString(Double.toString(Hmotnost),400,vyskaplochy-130);	} 
}
	
	
	

//trida Panel, reakce na mys
	class Epanel extends Panel implements MouseMotionListener,MouseListener {
  static boolean zmena=false;
  int posledni=-1;
  int sx,sy,posicex,posicey;
  int index;
	boolean drag;
	  
	public Epanel() {
		 	  addMouseMotionListener(this);
		 	  addMouseListener(this);
	}
	public void prekreslisipky() {
		  int i; 
	 	  for(i=0;i<(((PaprsekVOkoliCocky)getParent()).pocet);i++) {
			(((PaprsekVOkoliCocky)getParent()).zdroje[i]).repaint();
			}
	}
	
	public int dejZdroj(int x, int y) {
	  int i,px,py; Polygon pol; ZdrojPaprsku z;
	  int vysledek=-1; double r,s,v; Double a,b;
		boolean tahnihrot=false;
	  PaprsekVOkoliCocky p=(PaprsekVOkoliCocky)getParent();
	  for (i=0;i<p.pocet;i++) {
		  	pol=new Polygon(); z=p.zdroje[i];
			r=1; 
			if ((z.lasty-z.rozmer/2)==0) {a=new Double(0); b=new Double(5);}
			else {s=-(z.lastx-z.rozmer/2)/(z.lasty-z.rozmer/2); 
			   v=Math.sqrt(r*r+s*s);
			   a=new Double(5*r/v);
			   b=new Double(5*s/v);
			}
			
			px=a.intValue();
			py=b.intValue();

		  	pol.addPoint(z.getLocation().x+px+z.rozmer/2,z.getLocation().y+py+z.rozmer/2);
		  	pol.addPoint(z.getLocation().x-px+z.rozmer/2,z.getLocation().y-py+z.rozmer/2);
		  	pol.addPoint(z.getLocation().x-px+z.lastx,z.getLocation().y-py+z.lasty);
		  	pol.addPoint(z.getLocation().x+px+z.lastx,z.getLocation().y+py+z.lasty);
		  	
	  		if (pol.contains(x,y)) {
	  			vysledek=i;
	  			tahnihrot=false;
	  		}
	  		
	  		px=z.lastx+z.getLocation().x;
	  		py=z.lasty+z.getLocation().y;
			pol=new Polygon();
			pol.addPoint(px-6,py-6); 
			pol.addPoint(px+6,py-6);
			pol.addPoint(px+6,py+6);
			pol.addPoint(px-6,py+6);			
			
			if (pol.contains(x,y)) {
	  			vysledek=i;
	  			tahnihrot=true;
			}
	  }


				if (posledni>-1)
	  			{ p.zdroje[posledni].sipkatah=false;
	  			}	  			
	  			
	  			if (vysledek>-1) { p.zdroje[vysledek].sipkatah=true;
	  				if (p.zdroje[vysledek].hrot!=tahnihrot) {
	  						p.zdroje[vysledek].hrot=tahnihrot;	
	  						prekreslisipky();
	  				}
		  			
	  			}
	  			if (vysledek!=posledni) prekreslisipky();
	  			posledni=vysledek;

	  return vysledek;
	}
//----------
    public void mouseClicked (MouseEvent e)  { 
    }
    public void mouseEntered (MouseEvent e)  { 
    }
    public void mouseExited  (MouseEvent e)  { 
		if (!drag) {
		  int i; 
		  posledni=-1; 
	 	  for(i=0;i<(((PaprsekVOkoliCocky)getParent()).pocet);i++) {
			(((PaprsekVOkoliCocky)getParent()).zdroje[i]).sipkatah=false;
			}
			prekreslisipky();
		}
    }
    
    public void mouseReleased(MouseEvent e)  {
    	 drag=false;
    }  
 
 	 public void mousePressed(MouseEvent e) {
 	 	  sx=e.getX(); sy=e.getY();
 	 	  posicex=sx; posicey=sy;
 	 	  index=dejZdroj(sx,sy);
 	 	  repaint();
 	 	  drag=true;
	 }

//----------
   public void mouseMoved (MouseEvent e)  { 
   	if (zmena) {zmena=false;
	  int i; 
 	  for(i=0;i<(((PaprsekVOkoliCocky)getParent()).pocet);i++) {
			(((PaprsekVOkoliCocky)getParent()).zdroje[i]).repaint();
 	  }
   	}
   	if (!drag) {int index=dejZdroj(e.getX(),e.getY());}
   }	
   
   
   public void mouseDragged (MouseEvent e)  { 
		if (index>-1) {
  			PaprsekVOkoliCocky p=(PaprsekVOkoliCocky)getParent();

			if (p.zdroje[index].hrot) {
		 	  	p.zdroje[index].globgraf.setColor(Color.white);
		 	  	p.zdroje[index].kresliSipku(p.zdroje[index].getLocation().x+p.zdroje[index].rozmer/2,p.zdroje[index].getLocation().y+p.zdroje[index].rozmer/2,p.zdroje[index].getLocation().x+p.zdroje[index].lastx,p.zdroje[index].getLocation().y+p.zdroje[index].lasty);   	
				p.zdroje[index].globgraf.drawRect(p.zdroje[index].getLocation().x+p.zdroje[index].lastx-6,p.zdroje[index].getLocation().y+p.zdroje[index].lasty-6,12,12);
			
			  	p.zdroje[index].lastx=e.getX()-p.zdroje[index].getLocation().x;
			  	p.zdroje[index].lasty=e.getY()-p.zdroje[index].getLocation().y;			  	
				prekreslisipky();
			}
			
			else {
  			p.zdroje[index].globgraf.setColor(Color.white);
 	    	p.zdroje[index].kresliSipku(p.zdroje[index].getLocation().x+p.zdroje[index].rozmer/2,p.zdroje[index].getLocation().y+p.zdroje[index].rozmer/2,
	    	p.zdroje[index].getLocation().x+p.zdroje[index].lastx,p.zdroje[index].getLocation().y+p.zdroje[index].lasty);   	
  			
     	posicex=p.zdroje[index].getLocation().x+e.getX()-sx;
     	posicey=p.zdroje[index].getLocation().y+e.getY()-sy;
     	

  	 	  if ((posicex>0) && (posicey>0) && ((posicex+p.zdroje[index].rozmer)<PaprsekVOkoliCocky.sirkaplochy) && ((posicey+p.zdroje[index].rozmer)<PaprsekVOkoliCocky.vyskaplochy)) {
	       p.zdroje[index].setLocation(posicex,posicey);
				sx=e.getX(); sy=e.getY();
				p.zdroje[index].globgraf.setColor(Color.red);
 		    	p.zdroje[index].kresliSipku(posicex+p.zdroje[index].rozmer/2,posicey+p.zdroje[index].rozmer/2,
 	    	  	posicex+p.zdroje[index].lastx,posicey+p.zdroje[index].lasty);   	
  			}
			}
				
				
			
		}
   }
   
   public void paint(Graphics g) {
	  int i; 
 	  for(i=0;i<(((PaprsekVOkoliCocky)getParent()).pocet);i++) {
			(((PaprsekVOkoliCocky)getParent()).zdroje[i]).repaint();
 	  }
   }
   
}

//Centralni teleso je gravitacni teleso kolem nehoz se paprsky
//ohybaji
class CentralniTeleso extends Canvas implements MouseListener,MouseMotionListener {
	int polomer = 19;
	int posicex;
	int posicey;
	int sx,sy;
		
	double Hmotnost;
	int velikost = 20;	
	
  public CentralniTeleso(double M, int x, int y)
	{
		Hmotnost=M;
		posicex=x;
		posicey=y;		
		setSize(velikost,velikost);
		setLocation(posicex, posicey);
		addMouseListener(this);
		addMouseMotionListener(this);
	}

  public void paint(Graphics g) {
    g.fillOval(0, 0,polomer,polomer); 	
  }
//------
    public void mouseClicked (MouseEvent e)  { 
    }
    public void mouseEntered (MouseEvent e)  { 
		setCursor(new Cursor(Cursor.MOVE_CURSOR));    	
    }
    public void mouseExited  (MouseEvent e)  { 
    }
    public void mouseReleased(MouseEvent e)  {
    }  
 
	 public void mousePressed(MouseEvent e) {
	 	 sx=e.getX();
	 	 sy=e.getY();
	 	 posicex=getLocation().x;
	 	 posicey=getLocation().y;
	 	// getParent().repaint();
	 }



//----Mouse cosi
  public void mouseDragged (MouseEvent e)  { 
	     posicex=posicex+e.getX()-sx;
       posicey=posicey+e.getY()-sy;   		
	 	  if ((posicex>0) && (posicey>0) && ((posicex+velikost)<PaprsekVOkoliCocky.sirkaplochy) && ((posicey+velikost)<PaprsekVOkoliCocky.vyskaplochy)) {
       setLocation(posicex,posicey);
  			}
			//sx=posicex; sy=posicey;  	
			((PaprsekVOkoliCocky)getParent().getParent()).kreslidrahy();
			
  }

  public void mouseMoved (MouseEvent e)  { 
  }  

}


//Zdroj paprsku
//==========================================================

class ZdrojPaprsku extends Canvas implements MouseListener, MouseMotionListener {
int posicex, posicey;
int rozmer = 12;
int hranice= 3;
int sx,sy, lastx, lasty;
boolean sipkatah=false;
boolean hrot=false;

boolean vektortah=false;
boolean active=false;
int [][]pole=new int[4][301];

Graphics globgraf;

  public ZdrojPaprsku(int x,int y, Graphics g) {
    	lastx=rozmer/2; lasty=rozmer/2;
    	posicex=x;
  	  posicey=y;
  	  globgraf=g;
  	  setSize(rozmer, rozmer);
  	  setLocation(x,y);
 	  addMouseListener(this);
 	  addMouseMotionListener(this);
  }
	
	public void update(Graphics g) {
		g.setColor(Color.black);
		paint(g);
	}

  public void paint(Graphics g) {
		posicex=getLocation().x;
		posicey=getLocation().y;		
		globgraf.setColor(Color.white);
 	  	kresliSipku(posicex+rozmer/2,posicey+rozmer/2,posicex+lastx,posicey+lasty);   	
		globgraf.drawRect(posicex+lastx-6,posicey+lasty-6,12,12);
 	  	g.drawLine(0,0,rozmer,rozmer);
    	g.drawLine(rozmer,0,0,rozmer);
    	g.drawRect(rozmer/2-hranice,rozmer/2-hranice,hranice*2,hranice*2);
  	  	globgraf.setColor(Color.black);
  	  	if (sipkatah && !hrot) {globgraf.setColor(Color.red);};
		if (sipkatah && hrot) {
	  		globgraf.setColor(Color.blue);
			globgraf.drawRect(posicex+lastx-6,posicey+lasty-6,12,12);
	  		globgraf.setColor(Color.black);
		}
 	  if (vektortah) {
 	  	  kresliSipku(posicex+rozmer/2,posicey+rozmer/2,posicex+sx,posicey+sy);   
  	    lastx=sx; lasty=sy;
 	  }  else
  		{
 	  	  kresliSipku(getLocation().x+rozmer/2,getLocation().y+rozmer/2,getLocation().x+lastx,getLocation().y+lasty);   
  		}
	}

	public void kresliSipku(int x1,int y1,int x2,int y2)
	{
 	  	  if (((x2-x1)!=0) || ((y2-y1)!=0))
 	  	  {  globgraf.drawLine(x1,y1,x2,y2);   
 	  	     int dx=x1-x2;
 	  	     int dy=y1-y2;
 	  	     double dx2,dy2;

 	  	     double z=Math.sqrt(dx*dx+dy*dy);
 	  	     double uhel;
 	  	   
 	  	     uhel=uhel=Math.acos(dx/z);
 	  	     if ((Math.asin(dy/z)<0))
 	  	  		{uhel=2*Math.PI-Math.acos(dx/z);
 	  	  		}
 	  	     dx2=10*(Math.cos(uhel+Math.PI/6));
 	 			dy2=10*(Math.sin(uhel+Math.PI/6));
 	 			
 	 			Double tx=new Double(dx2);
 	 			Double ty=new Double(dy2);
  	       globgraf.drawLine(x2,y2,x2+tx.intValue(),y2+ty.intValue());   

 	  	     uhel=uhel=Math.acos(dx/z);
 	  	     if ((Math.asin(dy/z)<0))
 	  	  		{uhel=2*Math.PI-Math.acos(dx/z);
 	  	  		}
 	  	     dx2=10*(Math.cos(uhel-Math.PI/6));
 	 			dy2=10*(Math.sin(uhel-Math.PI/6));
 	 		  	tx=new Double(dx2);
 	 			ty=new Double(dy2);
  	       
  	       globgraf.drawLine(x2,y2,x2+tx.intValue(),y2+ty.intValue());   
 	  	  }   
	}


 /*implementace mouselisteneru*/
    public void mouseClicked (MouseEvent e)  { 
    }
    public void mouseEntered (MouseEvent e)  { 
      	posicex=getLocation().x;
     	posicey=getLocation().y;    	
     	active=true;
    }
    public void mouseExited  (MouseEvent e)  { 
    	  active=false;
    }
    public void mouseReleased(MouseEvent e)  {
    	 vektortah=false;
    }  
 
	 public void mousePressed(MouseEvent e) {
		  if (((PaprsekVOkoliCocky)getParent().getParent()).pocmarano){
		  	  ((Panel)getParent()).repaint();
				((PaprsekVOkoliCocky)getParent().getParent()).pocmarano=false;		  	   
		  }
 	   sx=rozmer/2;
 	   sy=rozmer/2;
 	   posicex=getLocation().x;
 	   posicey=getLocation().y; 	   
 	   if (PaprsekVOkoliCocky.mode==1) {
 	   	vektortah=true;
 	   };
		Epanel.zmena=true; 	   
	 }
// --------------------------------------------------------  
    /* MouseMotionListener */
   public void mouseDragged (MouseEvent e)  { 
		if (PaprsekVOkoliCocky.mode==0) 
   	{
	 	  globgraf.setColor(Color.white);
	 	  kresliSipku(posicex+rozmer/2,posicey+rozmer/2,posicex+lastx,posicey+lasty);   	

	    	posicex=posicex+e.getX()-sx;
       posicey=posicey+e.getY()-sy;   		
	 	  	if ((posicex>0) && (posicey>0) && ((posicex+rozmer)<PaprsekVOkoliCocky.sirkaplochy) && ((posicey+rozmer)<PaprsekVOkoliCocky.vyskaplochy)) {
       setLocation(posicex,posicey);
  			}
   	}
  		else {
			sx=e.getX();
			sy=e.getY();
  		}

	  Epanel.zmena=true;
    ((Epanel)getParent()).prekreslisipky();
   }


   public void mouseMoved (MouseEvent e)  { 
   	 if ((Math.abs(e.getX()-(rozmer/2))<hranice) && (Math.abs(e.getY()-(rozmer/2))<hranice)) 
   	 {PaprsekVOkoliCocky.mode=0; setCursor(new Cursor(Cursor.MOVE_CURSOR));}
   	 else {PaprsekVOkoliCocky.mode=1;
					setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));   	 
   	 }
   }	
  
// --------------------------------------------------------   
}