import java.awt.*;
import java.io.*;
import java.util.*;


public class Ship
{
// the color server used to read bitmap colors
private int Acceleration;// the quantity of acceleration ship recieves when thrust is applied
public  V2x1  Velocity;  // velocity of the ships center
public  V2x1  Position;  // position of the ships center
public  V2x1  DebrisV[]; // velocity of center each polygon during the explosion
public  V2x1  DebrisP[]; // position of center of each polygon ( during explosion
    
private Space parent; // the parent viewport
    
public int state; // the state of the ship (0 - alive, 1 - dead, 2 -  just blew up)

public EdgeList EL;   // a list of edges describing the contour of the ship
public PolygonList PL;// a list of polygons composing the ship
public int width_2;   // width divided by 2
public int height_2;  // height divided by 2
public int width;   // width divided by 2
public int height;  // height divided by 2
public int real_width;
public int flame;
public double drag_coeff;
    
public Ship(String shipname, Space canvas)
    {
	parent = canvas;

// build the polygon list
// first parse the dimensions
	StringTokenizer TKNZR;
	String str = parent.parent.getParameter(shipname+"_dims");
	TKNZR = new StringTokenizer(str);
	str = null;
	int FST = 0; // the state of the finite state machine
	int w = 0;
	int h = 0;
	while(TKNZR.hasMoreTokens())
	    {
		str = TKNZR.nextToken();
		if(FST == 0)
		    {
			w = Integer.parseInt(str);
			FST = 1;
		    }
		else if(FST == 1)
		    {
			h = Integer.parseInt(str);
			break;
		    }
	    }
	PL = new PolygonList(w, h); // create the list
	PL.insert();                // add an empty slide to it
	width_2  = (int)(w/2+0.5);
	height_2 = (int)(h/2+0.5);
	width = w;
	height = h;
	
// now figure out how many polygons will be in the list
	str = parent.parent.getParameter(shipname+"_slides");
	int num = Integer.parseInt(str);

// now read each slide into the list
	int min_x=width;
	int max_x=0;
	for(int i=0; i<num; i++)
	    {
		// first parse the color
		str = parent.parent.getParameter(shipname+"_color_"+i);
		TKNZR = new StringTokenizer(str);
		str = null;
		int red = 0;
		int green = 0;
		int blue = 0;
		FST = 0;
		while(TKNZR.hasMoreTokens())
		    {
			str = TKNZR.nextToken();
			if(FST == 0)
			    {
				red = Integer.parseInt(str);
				FST = 1;
			    }
			else if(FST == 1)
			    {
				green = Integer.parseInt(str);
				FST = 2;
			    }
			else if(FST == 2)
			    {
				blue = Integer.parseInt(str);
				PL.curr.color = new Color(red, green, blue);
				break;
			    }
		    }
		
		// then parse the coordinates of vertices
		str = parent.parent.getParameter(shipname+"_slide_"+i);
		TKNZR = new StringTokenizer(str);
		str = null;
		int x = 0;
		int y = 0;
		FST = 0;
		while(TKNZR.hasMoreTokens())
		    {
			str = TKNZR.nextToken();
			if(FST == 0)
			    {
				if(str.compareTo("closed")==0)
				    FST = 1;
				else if(str.compareTo("opened")==0)
				    FST = 2;
				else
				    {
					System.out.print("unrecognized token in line ");
					System.out.print(shipname);
					System.out.print("_slide_");
					System.out.print(i);
					System.out.print(" :  ");
					System.out.println(str);
					break;
				    }
			    }
			else if(FST == 1)
			    {
				if(str.compareTo("fill")==0)
				    FST = 4;
				else if(str.compareTo("nfill")==0)
				    FST = 6;
				else
				    {
					System.out.print("unrecognized token in line ");
					System.out.print(shipname);
					System.out.print("_slide_");
					System.out.print(i);
					System.out.print(" :  ");
					System.out.println(str);
					break;
				    }
			    }
			else if(FST == 2)
			    {
				x = Integer.parseInt(str);
				if(x>max_x)
				    max_x = x;
				else if(x<min_x)
				    min_x = x;
				FST = 3;
			    }
			else if(FST == 3)
			    {
				y = Integer.parseInt(str);
				PL.curr.add(x, y);
				FST = 2;
			    }
			else if(FST == 4)
			    {
				x = Integer.parseInt(str);
				if(x>max_x)
				    max_x = x;
				else if(x<min_x)
				    min_x = x;
				FST = 5;
			    }
			else if(FST == 5)
			    {
				y = Integer.parseInt(str);
				PL.curr.add(x, y);
				FST = 4;
			    }
			else if(FST == 6)
			    {
				x = Integer.parseInt(str);
				if(x>max_x)
				    max_x = x;
				else if(x<min_x)
				    min_x = x;
				FST = 7;
			    }
			else if(FST == 7)
			    {
				y = Integer.parseInt(str);
				PL.curr.add(x, y);
				FST = 6;
			    }
		    }
		if(FST==6 || FST==4)
		    PL.curr.add(PL.curr.bot.x, PL.curr.bot.y);
		if(FST == 4)
		    PL.curr.filled = VertexStack.FILLED;
		PL.next();
		PL.insert();
	    }
	real_width = max_x-min_x;
	
// create the edge list
	EL = new EdgeList();
	VertexStack index_vs = PL.head;
	while(index_vs != null)
	    {
		VertexLink index = index_vs.bot;
		for(int i=0; i<index_vs.count; i++)
		    {
			if(index.next == null)
			    break;
			else
			    EL.add(index.x-width_2, index.y-height_2, index.next.x-width_2, index.next.y-height_2);
			index = index.next;
		    }
		index_vs = index_vs.next;
      	    }
	
	// setup the position vector
	Position     = new V2x1((int)(parent.width/2), (int)(height));

	state        = 0;             // initial state of the ship
	Acceleration = 1;             // acceleration magnitude
	Velocity     = new V2x1(0, 0);// velocity vector
	drag_coeff = 0.001;
	flame = 0;
    }

    
public void up()
    { 
	if(state == 0)
	    {
		Velocity.Y-=3;// allways accelerate in the direction of orientation vector times 1(m/s**2)
		flame+=7;
	    }
    }
    
public void down()
    {
	if(state == 0)
	    {
		Velocity.Y++;// allways deaccelerate in the direction of orientation vector times 1(m/s**2)
		flame-=3;
		if(flame<0)
		    flame = 0;
	    }
    }
    

public void left()
    {
	if(state == 0)
	    Velocity.X--;
    }
    

public void right()
    {
	if(state == 0)
	    Velocity.X++;
    }

    
public void explode()
    {
	if(state==0)
	    {
		state = 2;
		flame = 0;
//		Velocity.Y=0;
//		Velocity.X=0;
	    }
    }
    
public void land()
    {
	if(state==0)
	    {
		state = 3;
		flame = 0;
//		Velocity.Y=0;
//		Velocity.X=0;
	    }
    }

public void reset()
    {
	Position     = new V2x1((int)(parent.width/2), (int)(height));

	state        = 0;             // initial state of the ship
	Acceleration = 1;             // acceleration magnitude
	Velocity     = new V2x1(0, 0);// velocity vector
    }

public void move()
    {
	if(state==0)
	    {
// the drag acceleration
		V2x1 Acc_drag = new V2x1(Velocity);
		Acc_drag.normalize();
		Acc_drag.reverse();
		Acc_drag.mult(Velocity.mag_squared());
		Acc_drag.mult(drag_coeff);
		
		V2x1 Acc_grav = new V2x1(0, 6.672E-11);
		Acc_grav.mult(parent.mass/(parent.radius*parent.radius)/20);

		Velocity.add(Acc_grav);
		Velocity.add(Acc_drag);
		Position.add(Velocity);
		
		if(Position.X > parent.width)
		    Position.X -= parent.width;
		else if(Position.X < 0)
		    Position.X += parent.width;
		if(flame>0)
		    flame--;
	    }
	else if(state==1)
	    {
		V2x1 Acc_grav = new V2x1(0, 6.672E-11);
		Acc_grav.mult(parent.mass/(parent.radius*parent.radius)/20);
		for(int i=0; i<PL.count; i++)
		    {
// the drag acceleration
			V2x1 Acc_drag = new V2x1(DebrisV[i]);
			Acc_drag.normalize();
			Acc_drag.reverse();
			Acc_drag.mult(DebrisV[i].mag_squared());
			Acc_drag.mult(drag_coeff);
		

			DebrisV[i].add(Acc_grav);
			DebrisV[i].add(Acc_drag);
			DebrisP[i].add(DebrisV[i]);
			
			if(DebrisP[i].X > parent.width)
			    DebrisP[i].X -= parent.width;
			else if(DebrisP[i].X < 0)
			    DebrisP[i].X += parent.width;
		    }
	    }
	else if(state == 2)
	    {
		DebrisV = new V2x1[PL.count];
		DebrisP = new V2x1[PL.count];
		for(int i=0; i<PL.count; i++)
		    {
			DebrisV[i] = new V2x1(0,0);
			double angle = Math.PI*2*Math.random();
			M3x3 R = new M3x3(angle);
			V2x1 Ortion = new V2x1(R, new V2x1(0, -1));
			V2x1 temp = new V2x1(Ortion);
			temp.mult(Acceleration*5);
			DebrisV[i].add(temp);
			DebrisP[i] = new V2x1(Position);
		    }
		state = 1;
	    }
    }
}

