/*
 * Author: Paul Koshevoy
 * MyCanvas.java  Fri 29 Oct 1997, 08:35:00 1997
 */

import java.awt.*;
import java.awt.image.*;

public class Space extends Canvas implements Runnable
{
private int delay = 41; // delay between the redraws of the canvas in milliseconds

public  int state;      // 1=frozen , 0=running
public  int width;      // width of the canvas
public  int height;     // height of the canvas

public Program3 parent; // the parent of this component
    
public  Ship spaceship;  // the ship
public  Terrain terrain; // the terrain that ship will interact with
public  Speedometer speedometer;
public  FuelGauge fuelgauge;
public  double mass;     // the mass of the planet
public  double radius;   // the radius of the planet

private Image shipImage;      // buffer for double buffering
public  Image BACKGROUND;     // background picture
private Image terrainImage;   // buffer for double buffering
private MediaTracker tracker; // this tracker will look out for the progress on the background load
private Image offImage;       // buffer for double buffering
private Graphics offGraphics; // buffer for double buffering
private Thread animatorThread;// thread for double buffering and rotaion

public int minX;       // minimal X offset for the center of spaceship
public int minY;       // minimal Y offset for the center of spaceship
public int maxX;       // maximal X offset for the center of spaceship
public int maxY;       // maximal Y offset for the center of spaceship
    
    
    
public Space(Program3 parent_, Image BACKGROUND_, double m, double r) // constructor
    {
	parent = parent_;
	mass = m;
	radius = r;
	state = 1;
	BACKGROUND = BACKGROUND_;
	tracker = new MediaTracker(this);
	tracker.addImage(BACKGROUND, 0);
	try
	    {
		tracker.waitForID(0);
	    }
	catch(InterruptedException e)
	    {
		System.out.println("exception happend while during an attempt to load an image");
	    }
	width  = BACKGROUND.getWidth(this);
	height = BACKGROUND.getHeight(this);
	setSize(width, height);
	state = 0;
    }
    
public void start()
    {
	if(animatorThread == null)
	    animatorThread = new Thread(this); // create a new thread for double buffering
	animatorThread.start();                // start the new thread
    }
    
public void stop()
    {
	if(animatorThread != null)
	    animatorThread.stop(); // stop the double buffer thread
	animatorThread = null;     // destroy the double buffer thread
	offGraphics = null;        // destroy offscreen buffer
	offImage = null;           // destroy offscreen buffer
    }

public void set_ship_terrain(Ship ship, Terrain trrn, Speedometer spdmtr, FuelGauge flgg)
    {
	spaceship = ship;
	terrain   = trrn;
	speedometer = spdmtr;
	fuelgauge = flgg;
	minX = 0;
	minY = 0;
	maxX = (int)(width-spaceship.width);
	maxY = (int)(height-spaceship.height);
    }
    
public void reset()
    {
	terrainImage = null;
    }

public void run()
    {
	Thread.currentThread().setPriority(Thread.MAX_PRIORITY); // maximize the priority of the thread
	long startTime = System.currentTimeMillis();             // start time

	while(Thread.currentThread() == animatorThread)          // double buffer thread
	    {
		try
		    {
			startTime += delay;
			Thread.sleep(Math.max(0, startTime - System.currentTimeMillis()));
		    }
		catch(InterruptedException e)
		    {
			break;
		    }
		repaint(); // redraw
	    }
    }
    
    
public void update(Graphics g)
    {
	paint(g);
    }

    
public void paint(Graphics g)
    {
	speedometer.repaint();
	fuelgauge.repaint();
	parent.update_gauges();
	
	// set up double buffer
	if((offGraphics == null))
	    {
		offImage = createImage(width, height);
		offGraphics = offImage.getGraphics();
		offGraphics.setFont(new Font("Symbol", Font.BOLD, 24));
	    }
	if(shipImage == null)
	    {
		Graphics shipGraphics;
		int size = spaceship.width*spaceship.height;
		int temp[] = new int[size];
		shipImage = createImage(spaceship.width, spaceship.height);
		shipGraphics = shipImage.getGraphics();
		shipGraphics.setColor(Color.black);
		shipGraphics.fillRect(0, 0, spaceship.width, spaceship.height);
		drawShip(shipGraphics, 0, 0);
		PixelGrabber PG = new PixelGrabber(shipImage, 0, 0, spaceship.width, spaceship.height, temp, 0, spaceship.width);
		try
		    {
			PG.grabPixels();
		    }
		catch(InterruptedException e)
		    {
			System.out.println("pixel grab failed");
		    }
//		for(int j=0; j<spaceship.height; j++)
//		    {
//			for(int i=0; i<spaceship.width; i++)
//			    {
//				System.out.print(temp[i+j*spaceship.width]);
//				System.out.print(" ");
//			    }
//			System.out.println();
//		    }
		for(int i=0; i<size; i++)
		    if(temp[i]==-16777216)
			temp[i]=0;
		shipImage = createImage(new MemoryImageSource(spaceship.width, spaceship.height, temp, 0, spaceship.width));
	    }
	if(terrainImage == null)
	    {
		int size = width*height;
		int temp[] = new int[size];
		terrainImage = createImage(width, height);
		Graphics terrainGraphics = terrainImage.getGraphics();
		terrainGraphics.setColor(Color.black);
		terrainGraphics.fillRect(0, 0, width, height);
		int Y_temp[] = new int[terrain.size];
		for(int i=0; i<8; i++)
		    {
			for(int j=0; j<terrain.size; j++)
			    Y_temp[j] = (int)(terrain.Y[j]+((height-terrain.Y[j])*i)/7f);
			terrainGraphics.setColor(new Color(0, 0, (int)(255*(7-i)/7)));
			Polygon poly = new Polygon(terrain.X, Y_temp, terrain.size);
			terrainGraphics.fillPolygon(poly);
		    }
		PixelGrabber PG = new PixelGrabber(terrainImage, 0, 0, width, height, temp, 0, width);
		try
		    {
			PG.grabPixels();
		    }
		catch(InterruptedException e)
		    {
			System.out.println("pixel grab failed");
		    }
		for(int i=0; i<size; i++)
		    if(temp[i]==-16777216)
			temp[i]=0;
		terrainImage = createImage(new MemoryImageSource(width, height, temp, 0, width));
	    }
	
	spaceship.move();
	if(spaceship.state == 0)
	    {
		if(collision())
		    {
//			System.out.print("collision at speed ");
//			speedometer.dump();
			if((int)(spaceship.Position.X - spaceship.real_width/2) < terrain.lpX ||
			   (int)(spaceship.Position.X + spaceship.real_width/2) > terrain.lpX+terrain.lpRealSize ||
			   (speedometer.speed > speedometer.safe))
			    spaceship.explode();
			else
			    spaceship.land();
		    }
	    }

// Set the background to be black
//        offGraphics.setColor(Color.black);
//        offGraphics.fillRect(0, 0, width, height);
	
	offGraphics.drawImage(BACKGROUND, 0, 0, this);
	offGraphics.drawImage(terrainImage, 0, 0, this);
	
//        offGraphics.setColor(Color.blue);
//	Polygon poly = new Polygon(terrain.X, terrain.Y, terrain.size);
//	offGraphics.fillPolygon(poly);

	int random = (int)(Math.random()*3);
	Color random_color;
	if(random == 0)
	    random_color = Color.cyan;
	else if(random == 1)
	    random_color = Color.green;
	else
	    random_color = Color.red;
	offGraphics.setColor(random_color);
	
	offGraphics.drawLine(terrain.lpX, terrain.lpY, terrain.lpX+terrain.lpRealSize, terrain.lpY);
	if(spaceship.flame != 0)
	    {
		int x[] = new int[4];
		int y[] = new int[4];
		x[0] = (int)(spaceship.Position.X);
		y[0] = (int)(spaceship.Position.Y+spaceship.height_2);
		x[1] = (int)(spaceship.Position.X-3);
		y[1] = (int)(spaceship.Position.Y+spaceship.height_2+spaceship.flame*0.5);
		x[2] = (int)(spaceship.Position.X);
		y[2] = (int)(spaceship.Position.Y+spaceship.height_2+spaceship.flame*1.5);
		x[3] = (int)(spaceship.Position.X+3);
		y[3] = (int)(spaceship.Position.Y+spaceship.height_2+spaceship.flame*0.5);
		Polygon poly = new Polygon(x, y, 4);
		offGraphics.setColor(Color.red);
		offGraphics.fillPolygon(poly);
	    }

	if(spaceship.state==1)
	    {
		VertexStack index = spaceship.PL.head;
		for(int i=0; i<spaceship.PL.count; i++)
		    {
			int X = (int)(spaceship.DebrisP[i].X-spaceship.width_2);
			int Y = (int)(spaceship.DebrisP[i].Y-spaceship.height_2);
			drawPoly(offGraphics, index, X, Y);
			if(X<minX)
			    drawPoly(offGraphics, index, X+width, Y);
			else if(X>maxX)
			    drawPoly(offGraphics, index, X-width, Y);
			index = index.next;
			if(Y>height)
			    spaceship.DebrisV[i]=new V2x1(0,0);
		    }
		offGraphics.setColor(random_color);
		offGraphics.drawString("you have crashed", (width-12*16)/2, height/2);
	    }
	else
	    {
		int X = (int)(spaceship.Position.X-spaceship.width_2);
		int Y = (int)(spaceship.Position.Y-spaceship.height_2);
//		drawShip(offGraphics, X, Y);
		offGraphics.drawImage(shipImage, X, Y, this);
		if(X<minX)
//		    drawShip(offGraphics, X+width, Y);
		    offGraphics.drawImage(shipImage, X+width, Y, this);
		else if(X>maxX)
//		    drawShip(offGraphics, X-width, Y);
		    offGraphics.drawImage(shipImage, X-width, Y, this);
		if(spaceship.state == 3)
		    {
			offGraphics.setColor(random_color);
			offGraphics.drawString("you have landed", (width-12*15)/2, height/2);
		    }
	    }
	g.drawImage(offImage, 0, 0, this);
    }

public boolean collision()
    {
	boolean result;
	LineEquation L1 = new LineEquation();
	LineEquation L2 = new LineEquation();
	EdgeList terrainEL = terrain.span((int)(spaceship.Position.X-spaceship.real_width/2),
					  (int)(spaceship.Position.X+spaceship.real_width/2));
	EdgeLink index_1 = spaceship.EL.head; // iterator through spaceship edges
	EdgeLink index_2;                     // iterator through edges of terrain under the spaceship
	while(index_1 != null)
	    {
		L1.set(index_1, spaceship.Position);
		index_2 = terrainEL.head;
		while(index_2 != null)
		    {
//			System.out.println();
//			L1.dump();
//			System.out.println("line 2: ");
//			index_2.dump();

			result = false;
			int L11 = L1.f(index_2.X1, index_2.Y1);
			int L12 = L1.f(index_2.X2, index_2.Y2);
			if((L11<0 && L12>0) || (L12<0 && L11>0))
			    {
				result = true;
			    }
			L2.set(index_2.Y1, index_2.Y2, index_2.X1, index_2.X2, index_2.b);
//			System.out.println();
//			L2.dump();
			int L21 = L2.f(index_1.X1, index_1.Y1, spaceship.Position);
			int L22 = L2.f(index_1.X2, index_1.Y2, spaceship.Position);
			if(((L21<0 && L22>0) || (L22<0 && L21>0)) && result==true)
			    {
//				System.out.print(L11);
//				System.out.print(" ");
//				System.out.print(L12);
//				System.out.print(" ");
//				System.out.print(L21);
//				System.out.print(" ");
//				System.out.println(L22);
//				L1.dump();
//				L2.dump();
				return true;
			    }
			index_2 = index_2.next;
		    }
		index_1 = index_1.next;
	    }
	return false;
    }

private void drawShip(Graphics GR, int x, int y)
    {
	VertexStack vs_index = spaceship.PL.head;
	while(vs_index != null)
	    {
		GR.setColor(vs_index.color);
		if(vs_index.loop)
		    {
			int X[] = new int[vs_index.count-1];
			int Y[] = new int[vs_index.count-1];
			VertexLink index = vs_index.bot;
			for(int i=0; i<vs_index.count-1; i++)
			    {
				X[i] = index.x+x;
				Y[i] = index.y+y;
				index = index.next;
			    }
			if(vs_index.filled == VertexStack.FILLED)
			    {
				Polygon poly = new Polygon(X, Y, vs_index.count-1);
				GR.fillPolygon(poly);
			    }
			else
			    GR.drawPolygon(X, Y, vs_index.count-1);
		    }
	      
		VertexLink index = vs_index.bot;
		for(int i=0; i<vs_index.count; i++)
		    {
			if(index.next == null)
			    GR.drawLine(index.x+x, index.y+y, index.x+x, index.y+y);
			else
			    GR.drawLine(index.x+x, index.y+y, index.next.x+x, index.next.y+y);
			index = index.next;
		    }
		vs_index = vs_index.next;
	    }
    }
private void drawPoly(Graphics GR, VertexStack vs_index, int x, int y)
    {
	GR.setColor(vs_index.color);
	if(vs_index.loop)
	    {
		int X[] = new int[vs_index.count-1];
		int Y[] = new int[vs_index.count-1];
		VertexLink index = vs_index.bot;
		for(int i=0; i<vs_index.count-1; i++)
		    {
			X[i] = index.x+x;
			Y[i] = index.y+y;
			index = index.next;
		    }
		if(vs_index.filled == VertexStack.FILLED)
		    {
			Polygon poly = new Polygon(X, Y, vs_index.count-1);
			GR.fillPolygon(poly);
		    }
		else
		    GR.drawPolygon(X, Y, vs_index.count-1);
	    }
	
	VertexLink index = vs_index.bot;
	for(int i=0; i<vs_index.count; i++)
	    {
		if(index.next == null)
		    GR.drawLine(index.x+x, index.y+y, index.x+x, index.y+y);
		else
		    GR.drawLine(index.x+x, index.y+y, index.next.x+x, index.next.y+y);
		index = index.next;
	    }
    }
}

