import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.Random;
import javax.swing.*;


//********************************
// QmGame -- Applet extension
//*******************************
public class QmGame // extends javax.swing.JApplet 
{
    // 
    int total_plots = 10;  // total # of wave function plots (appear vertically
    // range of z values plotted
    int y_min = 0;
    int y_max = 100;
    double time=0.0; // in seconds
    // range of x & y coordinates used internally
    int x_begin= 10;
    int x_end=350;
    int y_begin= 400;
    int y_end = 100;
    int z_range = 100;
    int wave_range = (y_begin-y_end)/(total_plots+1);
    int wave_pad = z_range/total_plots;
    // range of x values plotted
    double x_0 = 0.0; // centimeters
    double x_n = 100.0; // centimeters
    double y_0 = 0.0; // centimeters
    double y_n = 100.0; // centimeters
    Complex coef[][];
    Complex area[][];
    Complex prob[][][][];
    double wave[][];
    Ball ball;
    Hole hole;
    Paddle paddle1,paddle2;
    Bumper bumper1,bumper2;
    double ballProb;
    Random ballRand;
    boolean plotWave=false;
    boolean ballActive = false;
    boolean ballToExit = false;
    Complex xProb[][];
    Complex yProb[][];
    double PI;
    Complex midh;
    Complex tf;
    double l = 100.0;
    double h =1000.0;
    long score=0;
    short ballNo =5;
 

    //*************************************
    // QmGame
    //***************************************
    QmGame()
    {
	ball = new Ball();
	ballRand = new Random();
	hole = new Hole(30.0,5.0,10025,false);
	paddle1 = new Paddle(95.0,65.0,5500,false);
	paddle2 = new Paddle(5.0,65.0,5500,false);
	bumper1 = new Bumper(50.0,85.0,1000,true);
	bumper2 = new Bumper(50.0,45.0,1000,true);
	ballProb = 0.0;
	prob = new Complex[12][11][10][10];
	area = new Complex[10][10];
	wave = new double[12][11];
	xProb = new Complex[11][10];
	yProb = new Complex[11][10];
	PI = 3.14159;
	coef = new Complex[10][10];
	Complex ZERO = new Complex(0.0,0.0);
	midh = new Complex(0.0,-1.0*h);
	// System.out.println("djd1");
	for (int xi = 0;xi<110;xi+=10)
	    for (int nx = 1;nx < 10;nx++)
		{
		    Complex kx = new Complex(nx*PI/2.0/l,0.0);
		    xProb[xi/10][nx] = Complex.cos(Complex.mult(kx,new Complex(xi,0.0)));
		}
	// System.out.println("djd2");
	for(int yi=0;yi<100;yi+=10)
	    for (int ny = 1;ny < 10;ny ++)
		{
		    Complex ky = new Complex(ny*PI/2.0/l,0.0);
		    yProb[yi/10][ny]= Complex.cos(Complex.mult(ky,new Complex(yi,0.0)));
		}
	// System.out.println("djd3");
	for (int xi = 0;xi<110;xi+=10)
	    for(int yi=0;yi<100;yi+=10)
		for (int nx = 1;nx < 10;nx++)
		    for (int ny = 1;ny < 10;ny ++)
		{
		    Complex ef = new Complex(0.0,0.0);
		    ef = Complex.mult(xProb[xi/10][nx],yProb[yi/10][ny]);
		    prob[xi/10][yi/10][nx][ny] = ef;
		}
	// System.out.println("djd4");
	for (int nx = 1;nx < 10;nx++)
	    for (int ny = 1;ny < 10;ny ++)
		{
		    area[nx][ny] = ZERO;
		    coef[nx][ny] = ZERO;
		}
	coef[7][1]= new Complex(0.25,0.0);
	coef[8][1] = new Complex(0.25,0.0);
	coef[1][7]= new Complex(0.25,0.0);
	coef[1][8] = new Complex(0.25,0.0);
	Complex pb1,pb2,cpb1,cpb2,p1,p2;


	// System.out.println("djd5");
	for(int yi=0;yi<100;yi+=10)
	    for (int xi = 0;xi<100;xi+=10)
		for (int nx = 1;nx < 10;nx++)
		    for (int ny = 1;ny < 10;ny ++)
			{
			    pb1 = prob[xi/10][yi/10][nx][ny];
			    cpb1 = Complex.conj(pb1);
			    pb2 = prob[(xi/10)+1][yi/10][nx][ny];
			    cpb2= Complex.conj(pb2);
			    p1 = Complex.mult(pb1,cpb1);
			    p2 = Complex.mult(pb2,cpb2);
			    area[nx][ny] = Complex.add(area[nx][ny],Complex.mult(Complex.add(p1,p2),new Complex(5.0,0.0)));
			}
	// System.out.println("djd6");
    }
   

    public int x_scale_sz(double x_in_sz)
    {
	int sz_x;
	sz_x = (int)((x_end-x_begin)*x_in_sz/(x_n-x_0));
	return sz_x;
    }
    public int y_scale_sz(double y_in_sz)
    {
	int sz_y;
	sz_y = (int)(-1.0*(y_end-y_begin)*y_in_sz/(y_n-y_0));
	return sz_y;
    }
    public int x_scale(double x_in)
    {
	int s_x;
	s_x = (int)((x_end-x_begin)*(x_in-x_0)/(x_n-x_0) + x_begin);
	return s_x;
    }
    public int y_scale(double y_in)
    {
	int s_y;
	s_y = (int)((y_end-y_begin)*(y_in-y_0)/(y_n-y_0) + y_begin);
	//	System.out.println(y_in);
	// System.out.println(s_y);
	return s_y;
    }
    //***********************************
    // plot the values
    //*******************************
    public void plot(Graphics g,Font f,Image workspace,Graphics offscreen, MainQmPbApplet main)
    {
	Graphics2D screen2D = (Graphics2D) g;

	Complex ef = new Complex(0.0,0.0);
	Complex cef = new Complex(0.0,0.0);
	double locProb = 0.0;
	double prevProb = 0.0;

	// int nx,ny;
	//while (true)
	ballProb = ballRand.nextFloat();

	    {
		locProb = 0.0;
		for(int yi=0;yi<100;yi+=10)
		    for (int xi = 0;xi<110;xi+=10)
			{
			    Complex ewave = new Complex(0.0,0.0);
			    Complex cjewave = new Complex(0.0,0.0);
			    for (int nx = 1;nx < 10;nx++)
				for (int ny = 1;ny < 10;ny ++)
				    {
					//System.out.println("h="+h);
					Complex E = new Complex(PI*PI*h*h/4.0/Ball.mass*(nx*nx+ny*ny)/l/l,0.0);
					tf = Complex.exp(Complex.mult(Complex.mult(midh,E),new Complex(time,0.0)));
					tf = Complex.div(tf,area[nx][ny]);
				//	System.out.println("tf="+tf.re+"+"+tf.im+"I");
					ef = Complex.mult(prob[xi/10][yi/10][nx][ny],Complex.mult(tf,coef[nx][ny]));
					ewave = Complex.add(ewave,ef);
				    }
			    cjewave = Complex.conj(ewave);
			    wave[xi/10][yi/10] = Complex.mult(ewave,cjewave).re*1000000.0;
			    locProb += wave[xi/10][yi/10];
				//   System.out.println("locProb="+locProb+"ballProb="+ballProb);
			}
		double locProb2 = 0.0; 
here:		for(int yi=0;yi<100 && plotWave && ballActive;yi+=10)
		    for (int xi = 0;xi<110 && plotWave && ballActive;xi+=10)
			{
			    locProb2 += wave[xi/10][yi/10]/locProb;
			    // System.out.println("locProb2="+locProb2+"ballProb="+ballProb);

			    if (locProb2 >=ballProb && prevProb < ballProb )
				// collision possible
				{
				    plotWave = !(hole.detect(xi,yi,this) ||
						 bumper1.detect(xi,yi,this) ||
						 bumper2.detect(xi,yi,this) ||
						 paddle1.detect(xi,yi,this) ||
						 paddle2.detect(xi,yi,this));
				    if (!plotWave)
					{
					    // System.out.println("Ball Detected");
					    ball.x = xi;
					    ball.y = yi;
					    break here;
					}
				}
			    prevProb = locProb2;
			    
			}
			
		offscreen.setFont(f);
		offscreen.setColor(Color.red);
		offscreen.drawString("Dennis Darland",5,50);
		offscreen.drawString("Quantum Pinball",5,80);

		offscreen.setColor(Color.black);
		offscreen.fillRect(x_begin,y_end,x_end-x_begin,y_begin-y_end);
		offscreen.setColor(Color.gray);
		offscreen.fillRect(x_begin+1,y_end+1,x_end-x_begin-2,y_begin-y_end-2);
		hole.plot(offscreen,this);
		bumper1.plot(offscreen,this);
		bumper2.plot(offscreen,this);
		paddle1.plot(offscreen,this);
		paddle2.plot(offscreen,this);
		for(int yi=0;yi<100 && plotWave && ballActive;yi+=10)
		    for (int xi = 0;xi<110&& plotWave && ballActive ;xi+=10)
			{
			    if (xi > 0)
				{
				    offscreen.setColor(Color.blue);
				    offscreen.drawLine(x_scale((double)(xi-10)),y_scale(wave[(xi-10)/10][yi/10]+yi),
					       x_scale((double)xi),y_scale(wave[xi/10][yi/10]+yi));
				    offscreen.setColor(Color.green);
				    offscreen.drawLine(x_scale((double)(xi-10)),y_scale(yi),
					       x_scale((double)xi),y_scale(yi));
				}
			    //    System.out.println("xi="+xi+"yi="+yi+"wave="+wave[xi/10][yi/10]);
			}
		if (hole.active)
		    hole.deactivate(time);
		if (paddle1.active)
		    paddle1.deactivate(time);
		if (paddle2.active)
		    paddle2.deactivate(time);

		if (!plotWave && (ballActive || ballToExit))
		    {
			ball.plot(offscreen,this);
			ballToExit = false;
		    }
		offscreen.setColor(Color.red);
		
		offscreen.drawString(" "+score+"   "+ballNo,280,50);
		screen2D.drawImage(workspace,0,0,main);

		plotWave = true;
		time += 10.0;
		try {Thread.sleep(1000);}
		catch (InterruptedException e){}
			


	    }
    }
    //    public void run()
    //{
    //}

};
